小智 54
我检查了.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);
}
Run Code Online (Sandbox Code Playgroud)
Jer*_*fin 37
我不相信Windows(而不是.NET)提供了直接的方法来实现它.
我知道的唯一方法是枚举所有顶级窗口,EnumWindows()然后找到每个窗口所属的进程GetWindowThreadProcessID().这听起来是间接的和低效的,但它并没有你想象的那么糟糕 - 在典型的情况下,你可能会有十几个顶级窗口可以走过......
Dat*_*han 11
这里有可能误解..Net中的WinForms框架自动将创建的第一个窗口(例如Application.Run(new SomeForm()))指定为MainWindow.但是,win32 API无法识别每个进程的"主窗口"的概念.消息循环完全能够处理尽可能多的"主"窗口,系统和进程资源将允许您创建.因此,您的流程没有"主窗口".在一般情况下,您可以做的最好的事情是EnumWindows()使所有非子窗口在给定进程上处于活动状态,并尝试使用一些启发式方法来确定哪一个是您想要的那个.幸运的是,大多数进程在大多数情况下只能运行一个"主"窗口,因此在大多数情况下您应该获得良好的结果.
这是我使用基于最佳答案的纯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;
}
Run Code Online (Sandbox Code Playgroud)