如果我只有一个窗口句柄(hWnd),我如何GetModuleFileName()?

我正在尝试获取我的C#2.0应用程序之外的窗口的可执行文件的名称。 我的应用程序当前使用来自“user32.dll”的GetForegroundWindow()调用获取窗口句柄(hWnd)。

从我能够进行的挖掘,我想我想使用GetModuleFileNameEx()函数(来自PSAPI)来获取名称,但GetModuleFileNameEx()需要一个Process的句柄,而不是一个Window。

是否可以从窗口句柄获取进程句柄? (我是否需要先获取窗口的线程句柄?)

编辑第一句话,使我更清楚我正在尝试做什么。

UPDATE! 这是我发现为我工作的C#代码。 唯一需要注意的是它会返回一个文件/路径,其中驱动器号是“?” 而不是实际的驱动器号(如“C”)。 – 还没弄明白为什么呢。

[DllImport("user32.dll")] static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId); [DllImport("kernel32.dll")] static extern IntPtr OpenProcess(UInt32 dwDesiredAccess, Int32 bInheritHandle, UInt32 dwProcessId); [DllImport("psapi.dll")] static extern uint GetModuleFileNameEx(IntPtr hProcess, IntPtr hModule, [Out] StringBuilder lpBaseName, [In] [MarshalAs(UnmanagedType.U4)] int nSize); [DllImport("kernel32.dll")] [return: MarshalAs(UnmanagedType.Bool)] static extern bool CloseHandle(IntPtr hObject); private string GetWindowModuleFileName(IntPtr hWnd) { uint processId = 0; const int nChars = 1024; StringBuilder filename = new StringBuilder(nChars); GetWindowThreadProcessId(hWnd, out processId); IntPtr hProcess = OpenProcess(1040, 0, processId); GetModuleFileNameEx(hProcess,IntPtr.Zero,filename,nChars); CloseHandle(hProcess); return (filename.ToString()); } 

您可以调用GetWindowThreadProcessId ,它将返回与窗口关联的进程。

从那里,您可以调用OpenProcess来打开进程并获取进程的句柄。

现在已经挣扎了一个小时同样的问题,还得到了第一个字母取代了 通过使用GetModuleFileNameEx。 最后使用System.Diagnostics.Process类提出了这个解决方案。

 [DllImport("user32.dll")] public static extern IntPtr GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId); void GetProcessPathFromWindowHandle(IntPtr hwnd) { uint pid = 0; Win32.GetWindowThreadProcessId(hwnd, out pid); Process p = Process.GetProcessById((int)pid); return p.MainModule.FileName; } 

如果您在Windows 64位平台上运行,则可能需要使用QueryFullProcessImageName。 与GetProcessImageFileName相比,它返回​​用户样式路径,GetProcessImageFileName返回需要使用NtQuerySymbolicLinkObject或ZwQuerySymbolicLinkObject转换的系统样式路径。

一个庞大的示例function – 建议分解为可重用的位。

 typedef DWORD (__stdcall *PfnQueryFullProcessImageName)(HANDLE hProcess, DWORD dwFlags, LPTSTR lpImageFileName, PDWORD nSize); typedef DWORD (__stdcall *PfnGetModuleFileNameEx)(HANDLE hProcess, HMODULE hModule, LPTSTR lpImageFileName, DWORD nSize); std::wstring GetExeName( HWND hWnd ){ // Convert from Window to Process ID DWORD dwProcessID = 0; ::GetWindowThreadProcessId(hWnd, &dwProcessID); // Get a handle to the process from the Process ID HANDLE hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwProcessID); // Get the process name if (NULL != hProcess) { TCHAR szEXEName[MAX_PATH*2] = {L'\0'}; DWORD nExeName = sizeof(szEXEName)/sizeof(TCHAR); // the QueryFullProcessImageNameW does not exist on W2K HINSTANCE hKernal32dll = LoadLibrary(L"kernel32.dll"); PfnQueryFullProcessImageName pfnQueryFullProcessImageName = NULL; if(hKernal32dll != NULL) { pfnQueryFullProcessImageName = (PfnQueryFullProcessImageName)GetProcAddress(hKernal32dll, "QueryFullProcessImageNameW"); if (pfnQueryFullProcessImageName != NULL) pfnQueryFullProcessImageName(hProcess, 0, szEXEName, &nExeName); ::FreeLibrary(hKernal32dll); } // The following was not working from 32 querying of 64 bit processes // Use as backup for when function above is not available if( pfnQueryFullProcessImageName == NULL ){ HINSTANCE hPsapidll = LoadLibrary(L"Psapi.dll"); PfnGetModuleFileNameEx pfnGetModuleFileNameEx = (PfnGetModuleFileNameEx)GetProcAddress(hPsapidll, "GetModuleFileNameExW"); if( pfnGetModuleFileNameEx != NULL ) pfnGetModuleFileNameEx(hProcess, NULL, szEXEName, sizeof(szEXEName)/sizeof(TCHAR)); ::FreeLibrary(hPsapidll); } ::CloseHandle(hProcess); return( szEXEName ); } return std::wstring(); } 

你究竟想做什么? 您可以获取使用GetWindowThreadProcessId()创建窗口的进程的进程ID,然后使用OpenProcess()来获取进程句柄。 但这看起来非常糟糕,我觉得有一种更优雅的方式可以做你想做的事。

试试这个来获取可执行文件的文件名:

C#:

 string file = System.Windows.Forms.Application.ExecutablePath; 

MFG