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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/277085/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 21:13:18  来源:igfitidea点击:

How do I GetModuleFileName() if I only have a window handle (hWnd)?

c#winapihwnd

提问by Pretzel

I'm trying to get the name of the executable of a window that is outside my C# 2.0 application. My app currently gets a window handle (hWnd) using the GetForegroundWindow() call from "user32.dll".

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

From the digging that I've been able to do, I think I want to use the GetModuleFileNameEx() function (from PSAPI) to obtain the name, but GetModuleFileNameEx() requires a handle to a Process, not a Window.

从我已经能够做的挖掘来看,我想我想使用 GetModuleFileNameEx() 函数(来自 PSAPI)来获取名称,但是 GetModuleFileNameEx() 需要一个进程的句柄,而不是一个窗口。

Is it possible to get a process handle from a window handle? (Do I need to get the thread handle of the window first?)

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

EDITED the first sentence to make it clearer what I'm trying to do.

编辑第一句话以更清楚地说明我要做什么。

UPDATE!Here's the C# code that I found worked for me. The only caveat is occasionallyit returns a file/path where the drive letter is a "?" instead of the actual drive letter (like "C"). -- Haven't figured out why yet.

更新!这是我发现对我有用的 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());
}

采纳答案by Pretzel

You can call GetWindowThreadProcessIdand that will return you the process associated with the window.

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

From that, you can call OpenProcessto open the process and get the handle to the process.

由此,您可以调用OpenProcess来打开进程并获取进程的句柄。

回答by Adam Rosenfield

What exactly is it that you're trying to do? You can get the process ID of the the process which created a window with GetWindowThreadProcessId(), followed by OpenProcess()to get the process handle. But this seems very kludgy, and I feel like there's a more elegant way to do what you want to do.

你到底想做什么?您可以使用GetWindowThreadProcessId()获取创建窗口的进程的进程 ID ,然后使用OpenProcess()获取进程句柄。但这似乎很笨拙,我觉得有一种更优雅的方式来做你想做的事。

回答by Adam Rosenfield

Been struggling with the same problem for an hour now, also got the first letter replaced by a ?by using GetModuleFileNameEx. Finaly came up with this solution using the System.Diagnostics.Processclass.

一个小时以来一直在为同样的问题苦苦挣扎,第一个字母也被替换为? 通过使用 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;
}

回答by Greg Domjan

If you are running on a windows 64 bit platform, you may need to use QueryFullProcessImageName instead. This returns a user style path, compared to GetProcessImageFileName which returns a system style path that would need to be converted using NtQuerySymbolicLinkObject or ZwQuerySymbolicLinkObject.

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

One mammoth example function - recommend breaking up into re usable bits.

一个庞大的示例函数 - 建议分解为可重复使用的位。

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'
string file = System.Windows.Forms.Application.ExecutablePath;
'}; 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(); }

回答by muh

try this to get the file name of the executable :

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

C#:

C#:

##代码##

mfg

制造