As you know, retrieving process path in .NET is quite straightforward. For example, if you have process instance someProcess you can get the process path by accessing someProcess.MainModule.FileName. However, for elevated processes, the previous code snippet throws Win32Exception.

As you have probably guessed, the reason is related to the bugs I mentioned in my previous post. In this case too, the Process class is using PROCESS_QUERY_INFORMATION access right to open the desired process. The difference from the previous case is that in order to get the main module and process path, the code really needs PROCESS_QUERY_INFORMATION so we cannot simply change it with PROCESS_QUERY_LIMITED_INFORMATION.

Fortunately, Microsoft has introduced a new function for getting process path QueryFullProcessImageName which does work with PROCESS_QUERY_LIMITED_INFORMATION access right. To call the function, we need to open the process ourselves and pass the handle.

private static string GetExecutablePath(Process Process)
{
    //If running on Vista or later use the new function
    if (Environment.OSVersion.Version.Major >= 6)
    {
        return GetExecutablePathAboveVista(Process.Id);
    }

    return Process.MainModule.FileName;
}

private static string GetExecutablePathAboveVista(int ProcessId)
{
    var buffer = new StringBuilder(1024);
    IntPtr hprocess = OpenProcess(ProcessAccessFlags.PROCESS_QUERY_LIMITED_INFORMATION,
                                  false, ProcessId);
    if (hprocess != IntPtr.Zero)
    {
        try
        {
            int size = buffer.Capacity;
            if (QueryFullProcessImageName(hprocess, 0, buffer, out size))
            {
                return buffer.ToString();
            }
        }
        finally
        {
            CloseHandle(hprocess);
        }
    }
    throw new Win32Exception(Marshal.GetLastWin32Error());
}

[DllImport("kernel32.dll")]
private static extern bool QueryFullProcessImageName(IntPtr hprocess, int dwFlags,
               StringBuilder lpExeName, out int size);
[DllImport("kernel32.dll")]
private static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess,
               bool bInheritHandle, int dwProcessId);

[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool CloseHandle(IntPtr hHandle);

You can turn the above code snippet into an extension method too. If you want Microsoft to add a new property for easily getting the process path, vote for this suggestion at the connect website: Add Path property to Process class so that it works with elevated processes too.

推荐.NET配套的通用数据层ORM框架:CYQ.Data 通用数据层框架
新浪微博粉丝精灵,刷粉丝、刷评论、刷转发、企业商家微博营销必备工具"