如何获取EnumWindows() API未枚举到的Windows系统窗口?
解决EnumWindows无法枚举系统特殊可见窗口的方案
EnumWindows会漏掉开始菜单、Game Bar、闹钟面板这类用户可见的系统/特殊窗口,原因是它们要么属于UWP沉浸式窗口,要么是系统保护的窗口对象。以下是几种经过验证的处理方案:
1. 遍历完整窗口链(替代EnumWindows)
EnumWindows是高层封装,会过滤掉部分系统窗口。改用从桌面窗口开始,通过GetWindow递归遍历所有子窗口和同级窗口的方式,能抓到更多窗口:
#include <windows.h> #include <wchar.h> BOOL CALLBACK EnumAllWindowsProc(HWND hwnd, LPARAM lParam) { // 过滤不可见窗口 if (!IsWindowVisible(hwnd)) { return TRUE; } // 获取窗口标题和类名 WCHAR szTitle[256] = {0}; GetWindowTextW(hwnd, szTitle, 256); WCHAR szClass[256] = {0}; GetClassNameW(hwnd, szClass, 256); // 输出信息(可替换为自定义处理逻辑) wprintf(L"窗口标题:%ls | 窗口类名:%ls\n", szTitle, szClass); return TRUE; } void EnumAllWindows() { HWND hDesktop = GetDesktopWindow(); // 遍历桌面的直接子窗口 HWND hWnd = GetWindow(hDesktop, GW_CHILD); while (hWnd != NULL) { EnumAllWindowsProc(hWnd, 0); // 递归遍历当前窗口的所有子窗口 EnumChildWindows(hWnd, EnumAllWindowsProc, 0); // 切换到下一个同级窗口 hWnd = GetWindow(hWnd, GW_HWNDNEXT); } }
这种方式不会跳过系统级窗口,需要自己过滤无效窗口(比如无标题、不可见的)。
2. 启用UI Access权限(已验证有效)
你之前测试的带UI_ACCESS属性的工具能枚举这些窗口,是因为该权限允许程序访问受保护的系统窗口。给程序添加该权限的步骤:
- 在程序的manifest文件中添加配置:
<requestedExecutionLevel level="requireAdministrator" uiAccess="true" /> - 将程序放在受信任目录(如
C:\Program Files或C:\Program Files (x86)) - 给程序签名(测试时可用自签名证书)
注意:UI Access权限需要管理员权限,且程序路径必须安全,否则系统会阻止运行。
3. 针对UWP/沉浸式窗口的枚举(Windows 10+)
开始菜单、Game Bar这类属于UWP应用窗口,Win32 API默认无法直接枚举,可使用WinRT API获取这些窗口信息:
C# 示例
using Windows.UI.WindowManagement; using System.Diagnostics; async void EnumUwpWindows() { var allAppWindows = await AppWindow.GetAllAsync(); foreach (var window in allAppWindows) { Debug.WriteLine($"UWP窗口标题:{window.Title} | 窗口ID:{window.Id}"); } }
C++/WinRT 示例
#include <winrt/Windows.UI.WindowManagement.h> #include <winrt/Windows.Foundation.h> #include <iostream> using namespace winrt; using namespace Windows::UI::WindowManagement; using namespace Windows::Foundation; IAsyncAction EnumUwpWindows() { auto appWindows = co_await AppWindow::GetAllAsync(); for (auto const& window : appWindows) { std::wcout << L"UWP窗口标题:" << window.Title().c_str() << L"\n"; } }
4. 利用进程诊断API获取窗口(Windows 10+)
通过Windows.System.Diagnostics.ProcessDiagnosticInfo可以枚举所有进程,再获取每个进程关联的窗口信息,包括UWP进程:
using Windows.System.Diagnostics; using System.Diagnostics; void EnumProcessWindows() { foreach (var processInfo in ProcessDiagnosticInfo.GetForProcesses()) { foreach (var windowInfo in processInfo.WindowDiagnosticInfos) { Debug.WriteLine($"窗口标题:{windowInfo.Title} | 进程ID:{processInfo.ProcessId}"); } } }
这种方式能覆盖所有进程关联的窗口,包括被EnumWindows漏掉的系统窗口。
额外提示
- 部分特殊窗口有固定类名,比如开始菜单的
XamlExplorerHostWindow、Game Bar的ApplicationFrameWindow,可通过GetClassName识别并针对性处理。 - 若系统启用了多虚拟桌面,需先用
EnumDesktops枚举所有桌面,再在每个桌面上调用EnumDesktopWindows枚举窗口。
内容的提问来源于stack exchange,提问作者Kyuwan Kim
相关产品推荐
相关产品推荐

