如何获取新启动Firefox窗口的HWND?启动进程已退出
如何获取新启动Firefox窗口的HWND?
在以下示例代码中,我打开一个新的Firefox窗口,等待一段时间让窗口出现,然后想要获取它的HWND。但问题在于,PID为pi.dwProcessId的进程在启动后立即终止,因此无法枚举它的所有窗口。我不想通过枚举CreateProcessW()前后所有Firefox的HWND并对比的方式解决,希望得到更稳健的方案。
#include <exception> #include <stdio.h> #include "Windows.h" static HWND GetFirefoxWindow(DWORD createdFirefoxPID) { wchar_t buffer[64]; swprintf_s(buffer, L"PID of the created Firefox: %lu.\n", createdFirefoxPID); OutputDebugStringW(buffer); return NULL; } // Signature taken from // C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um\WinBase.h int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nShowCmd) { STARTUPINFOW si = { sizeof(si) }; PROCESS_INFORMATION pi = {}; wchar_t commandLine[2048] = LR"("C:\Program Files\Mozilla Firefox\firefox.exe")" LR"( -new-window https://example.com)"; if (!CreateProcessW(NULL, commandLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { return 1; } CloseHandle(pi.hProcess); CloseHandle(pi.hThread); Sleep(5000); const HWND hwnd = GetFirefoxWindow(pi.dwProcessId); return ERROR_SUCCESS; }
可行的稳健解决方案
方法1:通过Job对象跟踪Firefox关联进程
Firefox的启动进程只是临时启动器,真正的主窗口由后续衍生的主进程创建。可以通过Windows的Job对象跟踪所有关联进程,再从中定位Firefox主窗口:
- 创建Job对象并配置允许子进程脱离但保持跟踪;
- 以挂起状态创建启动进程,将其分配到Job后恢复运行;
- 等待临时启动进程退出,枚举Job中的所有关联进程;
- 对每个进程枚举窗口,匹配Firefox主窗口的类名
MozillaWindowClass并筛选可见窗口。
修改后的核心代码示例:
#include <exception> #include <stdio.h> #include <vector> #include "Windows.h" int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nShowCmd) { STARTUPINFOW si = { sizeof(si) }; PROCESS_INFORMATION pi = {}; wchar_t commandLine[2048] = LR"("C:\Program Files\Mozilla Firefox\firefox.exe")" LR"( -new-window https://example.com)"; // 创建Job对象 HANDLE hJob = CreateJobObjectW(NULL, NULL); if (hJob == NULL) return 1; // 配置Job允许子进程脱离但仍被跟踪 JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = {0}; jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_BREAKAWAY_OK | JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK; if (!SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli))) { CloseHandle(hJob); return 1; } // 以挂起状态创建进程 if (!CreateProcessW(NULL, commandLine, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) { CloseHandle(hJob); return 1; } // 将进程分配到Job if (!AssignProcessToJobObject(hJob, pi.hProcess)) { ResumeThread(pi.hThread); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); CloseHandle(hJob); return 1; } // 恢复进程运行 ResumeThread(pi.hThread); // 等待临时启动进程退出 WaitForSingleObject(pi.hProcess, INFINITE); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); // 获取Job中所有进程ID DWORD bytesReturned = 0; QueryInformationJobObject(hJob, JobObjectBasicProcessIdList, NULL, 0, &bytesReturned); if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { CloseHandle(hJob); return 1; } std::vector<BYTE> buffer(bytesReturned); PJOBOBJECT_BASIC_PROCESS_ID_LIST pProcessIds = reinterpret_cast<PJOBOBJECT_BASIC_PROCESS_ID_LIST>(buffer.data()); if (!QueryInformationJobObject(hJob, JobObjectBasicProcessIdList, pProcessIds, bytesReturned, &bytesReturned)) { CloseHandle(hJob); return 1; } Sleep(2000); // 等待主窗口创建完成 HWND targetHwnd = NULL; // 枚举每个进程的窗口,查找Firefox主窗口 for (DWORD i = 0; i < pProcessIds->NumberOfProcessIds; ++i) { DWORD currentPid = pProcessIds->ProcessIdList[i]; EnumWindows([](HWND hwnd, LPARAM lParam) -> BOOL { auto data = reinterpret_cast<DWORD*>(lParam); DWORD windowPid = 0; GetWindowThreadProcessId(hwnd, &windowPid); if (windowPid == data[0]) { wchar_t className[256]; GetClassNameW(hwnd, className, sizeof(className)/sizeof(wchar_t)); // 匹配Firefox主窗口类名且窗口可见 if (wcscmp(className, L"MozillaWindowClass") == 0 && IsWindowVisible(hwnd)) { *reinterpret_cast<HWND*>(&data[1]) = hwnd; return FALSE; // 找到后停止枚举 } } return TRUE; }, reinterpret_cast<LPARAM>(¤tPid)); if (targetHwnd != NULL) break; } CloseHandle(hJob); // 输出找到的HWND if (targetHwnd != NULL) { wchar_t buffer[64]; swprintf_s(buffer, L"Found Firefox window HWND: %p\n", targetHwnd); OutputDebugStringW(buffer); } return ERROR_SUCCESS; }
方法2:利用Firefox远程调试接口
启动Firefox时添加--remote-debugging-port=9222参数,通过HTTP请求获取已打开窗口的调试信息,再结合窗口标题匹配到目标HWND:
- 修改启动命令:
wchar_t commandLine[2048] = LR"("C:\Program Files\Mozilla Firefox\firefox.exe")" LR"( -new-window https://example.com --remote-debugging-port=9222)"; - 向
http://localhost:9222/json/list发送GET请求,解析返回的JSON数据,找到对应新窗口的条目; - 用条目中的
title字段调用FindWindowW或EnumWindows匹配到目标HWND。
这种方法无需底层系统调用,但需要处理HTTP请求和JSON解析,适合对系统API不熟悉的场景。
内容的提问来源于stack exchange,提问作者Dr. Gut
相关产品推荐
相关产品推荐

