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

时间:2022-02-13 00:01:36

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()需要一个Process的句柄,而不是一个Window。

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 occasionally it returns a file/path where the drive letter is a "?" instead of the actual drive letter (like "C"). -- Haven't figured out why yet.

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());
}

5 个解决方案

#1


6  

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

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

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

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

#2


8  

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.Process class.

现在已经挣扎了一个小时同样的问题,还得到了第一个字母取代了?通过使用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;
}

#3


2  

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相比,它返回​​用户样式路径,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'\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();
}

#4


1  

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()来获取进程句柄。但这看起来非常糟糕,我觉得有一种更优雅的方式可以做你想做的事。

#5


0  

try this to get the file name of the executable :

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

C#:

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

mfg

#1


6  

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

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

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

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

#2


8  

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.Process class.

现在已经挣扎了一个小时同样的问题,还得到了第一个字母取代了?通过使用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;
}

#3


2  

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相比,它返回​​用户样式路径,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'\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();
}

#4


1  

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()来获取进程句柄。但这看起来非常糟糕,我觉得有一种更优雅的方式可以做你想做的事。

#5


0  

try this to get the file name of the executable :

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

C#:

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

mfg