如何从进程ID获取主窗口句柄?

时间:2009-12-11 15:34:36

标签: c++ windows winapi windows-7

如何从进程ID获取窗口句柄?

我想把这个窗口放在前面。

在“Process Explorer”中运行良好。

9 个答案:

答案 0 :(得分:50)

我检查了.NET如何确定主窗口。

我的发现表明它也使用了EnumWindows()

此代码应该与.NET方式类似:

struct handle_data {
    unsigned long process_id;
    HWND window_handle;
};

HWND find_main_window(unsigned long process_id)
{
    handle_data data;
    data.process_id = process_id;
    data.window_handle = 0;
    EnumWindows(enum_windows_callback, (LPARAM)&data);
    return data.window_handle;
}

BOOL CALLBACK enum_windows_callback(HWND handle, LPARAM lParam)
{
    handle_data& data = *(handle_data*)lParam;
    unsigned long process_id = 0;
    GetWindowThreadProcessId(handle, &process_id);
    if (data.process_id != process_id || !is_main_window(handle))
        return TRUE;
    data.window_handle = handle;
    return FALSE;   
}

BOOL is_main_window(HWND handle)
{   
    return GetWindow(handle, GW_OWNER) == (HWND)0 && IsWindowVisible(handle);
}

答案 1 :(得分:37)

我不相信Windows(而不是.NET)提供直接的方法来实现它。

我知道的唯一方法是使用EnumWindows()枚举所有顶级窗口,然后找到每个属于GetWindowThreadProcessID()的进程。这听起来是间接的和低效的,但它并没有你想象的那么糟糕 - 在一个典型的例子中,你可能会有十几个顶级窗口可以走过......

答案 2 :(得分:11)

这里有可能误解。 .Net中的WinForms框架自动将创建的第一个窗口(例如Application.Run(new SomeForm()))指定为MainWindow。但是,win32 API无法识别每个进程的“主窗口”的概念。消息循环完全能够处理尽可能多的“主”窗口,系统和进程资源将允许您创建。因此,您的流程没有“主窗口”。在一般情况下,您可以做的最好的事情是使用EnumWindows()来使所有非子窗口在给定进程上处于活动状态,并尝试使用一些启发法来确定哪一个是您想要的那个。幸运的是,大多数进程在大多数情况下只能运行一个“主”窗口,所以在大多数情况下你应该得到很好的结果。

答案 3 :(得分:6)

这是我使用基于最佳答案的纯Win32 / C ++的解决方案。我们的想法是将所需的所有内容包装到一个函数中,而无需外部回调函数或结构:

#include <utility>

HWND FindTopWindow(DWORD pid)
{
    std::pair<HWND, DWORD> params = { 0, pid };

    // Enumerate the windows using a lambda to process each window
    BOOL bResult = EnumWindows([](HWND hwnd, LPARAM lParam) -> BOOL 
    {
        auto pParams = (std::pair<HWND, DWORD>*)(lParam);

        DWORD processId;
        if (GetWindowThreadProcessId(hwnd, &processId) && processId == pParams->second)
        {
            // Stop enumerating
            SetLastError(-1);
            pParams->first = hwnd;
            return FALSE;
        }

        // Continue enumerating
        return TRUE;
    }, (LPARAM)&params);

    if (!bResult && GetLastError() == -1 && params.first)
    {
        return params.first;
    }

    return 0;
}

答案 4 :(得分:2)

虽然可能与您的问题无关,但请查看GetGUIThreadInfo Function

答案 5 :(得分:0)

只是为了确保你没有混淆tid(线程ID)和pid(进程ID):

DWORD pid;
DWORD tid = GetWindowThreadProcessId( this->m_hWnd, &pid);

答案 6 :(得分:0)

作为Hiale解决方案的扩展,您可以提供支持具有多个主窗口的进程的不同或修改版本。

首先,修改结构以允许存储多个句柄:

struct handle_data {
    unsigned long process_id;
    std::vector<HWND> handles;
};

其次,修改回调函数:

BOOL CALLBACK enum_windows_callback(HWND handle, LPARAM lParam)
{
    handle_data& data = *(handle_data*)lParam;
    unsigned long process_id = 0;
    GetWindowThreadProcessId(handle, &process_id);
    if (data.process_id != process_id || !is_main_window(handle)) {
        return TRUE;
    }
    // change these 2 lines to allow storing of handle and loop again
    data.handles.push_back(handle);
    return TRUE;   
 }

最后,修改主函数的返回值:

std::vector<HWD> find_main_window(unsigned long process_id)
{
    handle_data data;
    data.process_id = process_id;
    EnumWindows(enum_windows_callback, (LPARAM)&data);
    return data.handles;
}

答案 7 :(得分:0)

旧问题,但似乎流量很大,这是一个简单的解决方案:

IntPtr GetMainWindowHandle(IntPtr aHandle) {
        return System.Diagnostics.Process.GetProcessById(aHandle.ToInt32()).MainWindowHandle;
}

答案 8 :(得分:-1)

在这里,我想补充一点,如果您正在读取作为进程HWND的窗口句柄,则该进程不应在调试中运行,否则它将无法通过使用FindWindowEx找到窗口句柄。

相关问题