C# Get Path/Filename by Handle (hWnd) 32 and 64bit

匿名 (未验证) 提交于 2019-12-03 08:51:18

问题:

I got the following code to get path/filename by handle:

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]     private static extern int GetWindowThreadProcessId(IntPtr handle, out uint processId);      public static string GetProcessPath(IntPtr hwnd)     {         uint pid = 0;         GetWindowThreadProcessId(hwnd, out pid);         Process proc = Process.GetProcessById((int)pid);         return proc.MainModule.FileName.ToString();     } 

it works perfect in 32 bit but I get error in 64bit > "Only part of the ReadProcessMemory or WriteProcessMemory request was completed." the project is compiled as x86 (platform target x86).

How can I fix it?

~Thanks Ron

回答1:

It appears from your question that you've currently compiled your program as a 32-bit application. However, the process you're trying to query (assuming you're running on a 64-bit version of Windows) is undoubtedly a 64-bit one. That kind of thing isn't allowed. Although you can run 32-bit applications on 64-bit versions of Windows, they run under the dedicated Windows on Windows (WOW64) subsystem. That's why you're getting a Win32Exception claiming that "Only part of a ReadProcessMemory or WriteProcessMemory request was completed". I agree it's not the most descriptive of error messages if you don't already know how Windows manages 32-bit and 64-bit processes, but armed with this knowledge it makes at least a little more sense.

The solution is to compile your application as a 64-bit application (x64), or for "Any CPU". Everything should work as expected after that. If possible, I suggest using "Any CPU", which will allow the application to run in 32-bit mode on 32-bit OSes and 64-bit on 64-bit OSes. Which is really the ideal set of circumstances, assuming that:

  1. You've written your P/Invoke definitions correctly (i.e., using IntPtr where appropriate, instead of Integer).
  2. You're not relying on 3rd-party DLLs (to which you don't have the source code) that were compiled as 32-bit.


回答2:

I'm not aware of a known problem with this, it smells environmental. The error is very low level, probably the wow64 emulation layer. I can only suggest you punt and use a different way to get the same info. You can use WMI, Win32_Process class. Run a select query on ProcessId, the ExecutablePath property gives you what you are looking for. Use the WMI Code Creator utility to experiment, it auto-generates the C# code you need. The odds are however not zero that this will fail the same way.



回答3:

It works well for me on a 64x machine. The only changes to the code are checking the values, as:

if (hwnd != IntPtr.Zero) {     if (pid != 0)      {         var p = Process.GetProcessById((int) pid)         if (p != null)         {             //...         }     } } 


回答4:

This thing is absolutely possible from a 32 bit application when checking a 64 bit process, though not as straightforward as it would be if it were a 64 bit compiled application:

    [Flags]     enum ProcessAccessFlags : uint     {         All = 0x001F0FFF,         Terminate = 0x00000001,         CreateThread = 0x00000002,         VMOperation = 0x00000008,         VMRead = 0x00000010,         VMWrite = 0x00000020,         DupHandle = 0x00000040,         SetInformation = 0x00000200,         QueryInformation = 0x00000400,         Synchronize = 0x00100000,         ReadControl = 0x00020000,         PROCESS_QUERY_LIMITED_INFORMATION = 0x1000     }      [DllImport("kernel32.dll")]     private static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, bool bInheritHandle, int dwProcessId);      [DllImport("kernel32.dll")]     private static extern bool QueryFullProcessImageName(IntPtr hprocess, int dwFlags, StringBuilder lpExeName, out int size);      [DllImport("kernel32.dll", SetLastError = true)]     private static extern bool CloseHandle(IntPtr hHandle);      private static Process GetProcessByHandle(IntPtr hwnd)     {         try         {             uint processID;             GetWindowThreadProcessId(hwnd, out processID);             return Process.GetProcessById((int)processID);         }         catch { return null; }     }      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);             }         }         return null;     }      private static string GetWindowPath(IntPtr hwind)     {         try         {             Process currentProcess = GetProcessByHandle(hwind);              if (Environment.OSVersion.Version.Major >= 6)             {                 string newMethReturn = GetExecutablePathAboveVista(currentProcess.Id);                 if (!string.IsNullOrWhiteSpace(newMethReturn))                     return newMethReturn;             }               if (currentProcess != null)                  return currentProcess.MainModule.FileName;             else                 return null;         }         catch         { return null; }     } 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!