如何从进程id中获取main窗口句柄?我想把这扇Windows移到前面。它在“Process Explorer”中运行良好。
4urapxun1#
我检查了.NET如何确定主窗口。我的发现表明它也使用EnumWindows()。这段代码应该类似于.NET的方式:
EnumWindows()
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); }
字符串
soat7uwm2#
我不相信Windows(相对于.NET)提供了一个直接的方法来实现这一点。我所知道的唯一方法是枚举所有具有EnumWindows()的顶层窗口,然后找出每个属于GetWindowThreadProcessID()的进程。这听起来很间接,效率很低,但并不像你想象的那么糟糕--在一个典型的情况下,你可能有十几个顶层窗口要遍历。
GetWindowThreadProcessID()
x7yiwoj43#
这里可能存在误解,.Net中的WinForms框架会自动指定创建的第一个窗口(例如,Application.Run(new SomeForm()))作为MainWindow。然而,win32 API不承认每个进程的“主窗口”的想法。消息循环完全能够处理系统和进程资源允许您创建的尽可能多的“主”窗口。因此,你的进程没有一个“主窗口”。一般情况下,你能做的最好的事情是使用EnumWindows()来激活给定进程上的所有非子窗口,并尝试使用一些技巧来找出哪一个是你想要的。幸运的是,大多数进程在大多数时间里只可能有一个“主”窗口运行,所以在大多数情况下你应该会得到很好的结果。
Application.Run(new SomeForm())
MainWindow
fzwojiic4#
这是我的解决方案,使用纯Win32/C++的基础上的顶部答案。这个想法是 Package 所需的一切到一个函数,而不需要外部回调函数或结构:
#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; }
lyfkaqu15#
虽然它可能与你的问题无关,但看看GetGUIThreadInfo Function。
anauzrmj6#
作为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; }
型最后,修改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; }
型
s2j5cfk07#
只是为了确保你没有混淆tid(线程id)和pid(进程id):
DWORD pid; DWORD tid = GetWindowThreadProcessId( this->m_hWnd, &pid);
ioekq8ef8#
如果你有一个命令行应用程序(而不是GUI应用程序),你可以使用GetConsoleWindow() winapi函数。@Hiale给出的最上面的答案将不起作用,因为is_main_window不会将控制台窗口标识为应用程序的主窗口。
is_main_window
8条答案
按热度按时间4urapxun1#
我检查了.NET如何确定主窗口。
我的发现表明它也使用
EnumWindows()
。这段代码应该类似于.NET的方式:
字符串
soat7uwm2#
我不相信Windows(相对于.NET)提供了一个直接的方法来实现这一点。
我所知道的唯一方法是枚举所有具有
EnumWindows()
的顶层窗口,然后找出每个属于GetWindowThreadProcessID()
的进程。这听起来很间接,效率很低,但并不像你想象的那么糟糕--在一个典型的情况下,你可能有十几个顶层窗口要遍历。x7yiwoj43#
这里可能存在误解,.Net中的WinForms框架会自动指定创建的第一个窗口(例如,
Application.Run(new SomeForm())
)作为MainWindow
。然而,win32 API不承认每个进程的“主窗口”的想法。消息循环完全能够处理系统和进程资源允许您创建的尽可能多的“主”窗口。因此,你的进程没有一个“主窗口”。一般情况下,你能做的最好的事情是使用EnumWindows()
来激活给定进程上的所有非子窗口,并尝试使用一些技巧来找出哪一个是你想要的。幸运的是,大多数进程在大多数时间里只可能有一个“主”窗口运行,所以在大多数情况下你应该会得到很好的结果。fzwojiic4#
这是我的解决方案,使用纯Win32/C++的基础上的顶部答案。这个想法是 Package 所需的一切到一个函数,而不需要外部回调函数或结构:
字符串
lyfkaqu15#
虽然它可能与你的问题无关,但看看GetGUIThreadInfo Function。
anauzrmj6#
作为Hiale解决方案的扩展,您可以提供一个不同的或经过修改的版本,以支持具有多个主窗口的进程。
首先,修改结构以允许存储多个句柄:
字符串
二、修改回调函数:
型
最后,修改main函数的返回值:
型
s2j5cfk07#
只是为了确保你没有混淆tid(线程id)和pid(进程id):
字符串
ioekq8ef8#
如果你有一个命令行应用程序(而不是GUI应用程序),你可以使用GetConsoleWindow() winapi函数。
@Hiale给出的最上面的答案将不起作用,因为
is_main_window
不会将控制台窗口标识为应用程序的主窗口。