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
How to get main window handle from process id?
提问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)¶ms);
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 找到窗口句柄。