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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1888863/
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-27 21:29:42  来源:igfitidea点击:

How to get main window handle from process id?

c++windowswinapiwindows-7

提问by Alexey Malistov

How to get mainwindow handle from process id?

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

I want to bring this window to the front.

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

It works well in "Process Explorer".

它在“流程资源管理器”中运行良好。

回答by Hiale

I checked how .NET determines the main window.

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

My finding showed that it also uses EnumWindows().

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

This code should do it similarly to the .NET way:

这段代码应该与 .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);
}

回答by Jerry Coffin

I don't believe Windows (as opposed to .NET) provides a direct way to get that.

我不相信 Windows(而不是 .NET)提供了一种直接的方法来获得它。

The only way I know of is to enumerate all the top level windows with EnumWindows()and then find what process each belongs to GetWindowThreadProcessID(). This sounds indirect and inefficient, but it's not as bad as you might expect -- in a typical case, you might have a dozen top level windows to walk through...

我所知道的唯一方法是枚举所有顶级窗口,EnumWindows()然后找到每个窗口所属的进程GetWindowThreadProcessID()。这听起来间接且效率低下,但它并没有你想象的那么糟糕——在典型的情况下,你可能有十几个顶层窗口要穿过......

回答by Dathan

There's the possibility of a mis-understanding here. The WinForms framework in .Net automatically designates the first window created (e.g., Application.Run(new SomeForm())) as the MainWindow. The win32 API, however, doesn't recognize the idea of a "main window" per process. The message loop is entirely capable of handling as many "main" windows as system and process resources will let you create. So, your process doesn't have a "main window". The best you can do in the general case is use EnumWindows()to get all the non-child windows active on a given process and try to use some heuristics to figure out which one is the one you want. Luckily, most processes are only likely to have a single "main" window running most of the time, so you should get good results in most cases.

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

回答by Benj

This is my solution using pure Win32/C++ based on the top answer. The idea is to wrap everything required into one function without the need for external callback functions or structures:

这是我基于最佳答案使用纯 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;
}

回答by AntonK

Though it may be unrelated to your question, take a look at GetGUIThreadInfo Function.

尽管它可能与您的问题无关,但请查看GetGUIThreadInfo Function

回答by Oliver Zendel

Just to make sure you are not confusing the tid (thread id) and the pid (process id):

只是为了确保您不会混淆 tid(线程 ID)和 pid(进程 ID):

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

回答by Class Skeleton

As an extension to Hiale's solution, you could provide a different or modified version that supports processes that have multiple main windows.

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

First, amend the structure to allow storing of multiple handles:

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

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

Second, amend the callback function:

二、修改回调函数:

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

Finally, amend the returns on the main function:

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

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

回答by arimaknp

Here, I would like to add that if you are reading window handle that is HWND of a process then that process should not be running in a debugging otherwise it will not find the window handle by using FindWindowEx.

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