如何从进程ID获取主窗口句柄?
我想将该窗口置于前台。
在“Process Explorer”中可以正常工作。
如何从进程ID获取主窗口句柄?
我想将该窗口置于前台。
在“Process Explorer”中可以正常工作。
我查看了.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);
}
if (data.process_id != process_id || !IsWindowVisible(handle))
有什么区别。此外,这种方法需要微调以支持具有多个主窗口的进程 ID(例如 Web 浏览器)。 - Class SkeletonGetWindow(handle, GW_OWNER) == 0
检查窗口是否不是所有窗口(例如对话框或其他窗口)。IsWindowVisible(handle)
检查窗口是否可见且未隐藏(许多没有 GUI 的应用程序仍然有一个隐藏的窗口,甚至像在系统托盘中运行的配置应用程序这样的具有隐藏 GUI 的应用程序也有)。因此,如果窗口可见且没有所有者,则被视为“主窗口”,这足以描述大多数“主窗口”。 - Jason C我不相信Windows(与.NET相对)提供了直接获取此信息的方法。
我所知道的唯一方法是使用EnumWindows()
枚举所有顶层窗口,然后找出每个窗口属于哪个进程GetWindowThreadProcessID()
。这听起来间接且效率低下,但它并没有你想象中那么糟糕 - 在典型情况下,您可能需要遍历十几个顶层窗口...
这是我基于顶部答案的纯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;
}
if (GetWindowThreadProcessId(hwnd, &processId) && processId == pParams->second && GetWindow(hwnd, GW_OWNER) == 0)
。请注意不改变原意,并使翻译易于理解。 - Pep这里可能存在误解。在 .Net 中,WinForms 框架会自动将第一个创建的窗口(例如,Application.Run(new SomeForm())
)指定为 MainWindow
。然而,win32 API 并不认可进程级别的“主窗口”概念。消息循环完全能够处理尽可能多的“主”窗口,只要系统和进程资源允许你创建即可。因此,你的进程没有“主窗口”。一般情况下,你只能使用 EnumWindows()
获取给定进程上所有非子窗口并尝试使用一些启发式方法来确定你想要的那个窗口。幸运的是,大多数进程通常只有单个“主”窗口在运行,所以大多数情况下应该可以得到良好的结果。
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;
}
只是为了确保您不会混淆tid(线程ID)和pid(进程ID):
DWORD pid;
DWORD tid = GetWindowThreadProcessId( this->m_hWnd, &pid);