Windows平台C++获取并过滤Alt+Tab/任务栏可见窗口
如何过滤出Alt+Tab或任务栏中显示的窗口?
我需要写一个C++程序,列出当前所有打开的窗口(比如浏览器、文件资源管理器、Discord这类),还要获取它们的位置和尺寸。目前我用EnumWindows实现了窗口枚举,但结果里混进了大量无标题窗口、程序管理器、未打开的设置窗口以及NVIDIA GeForce Overlay这类不需要的窗口。想请教怎么过滤掉那些不在Alt+Tab切换菜单或任务栏显示的窗口?
现有代码
#include <windows.h> #include <iostream> #pragma comment(lib, "User32.lib") BOOL IsAltTabWindow(HWND hwnd) { HWND hwndWalk = GetAncestor(hwnd, GA_ROOTOWNER); HWND hwndTry; while ((hwndTry = GetLastActivePopup(hwndWalk)) != hwndTry) { if (IsWindowVisible(hwndTry)) break; hwndWalk = hwndTry; } LONG_PTR extendedStyle = GetWindowLongPtr(hwnd, GWL_EXSTYLE); return (hwndWalk == hwnd) && ((extendedStyle & WS_EX_APPWINDOW) != 0 || (extendedStyle & WS_EX_TOOLWINDOW) == 0); } BOOL CALLBACK WindowCallback(HWND hwnd, LPARAM lParam) { const DWORD TITLE_SIZE = 1024; TCHAR windowTitle[TITLE_SIZE]; GetWindowText(hwnd, windowTitle, TITLE_SIZE); if (IsAltTabWindow(hwnd) && IsWindowVisible(hwnd)) std::cout << "Window (" << IsAltTabWindow(hwnd) << "): " << windowTitle << std::endl; return TRUE; } int main() { EnumWindows(WindowCallback, NULL); return 0; }
解决方案
要准确过滤出Alt+Tab和任务栏显示的窗口,需要更严谨的判断逻辑,原有的IsAltTabWindow函数存在漏洞,以下是改进后的实现:
核心过滤条件
一个窗口要出现在Alt+Tab或任务栏中,需满足:
- 窗口可见(
IsWindowVisible返回TRUE) - 不是工具窗口(无
WS_EX_TOOLWINDOW扩展样式) - 是顶层窗口的活动弹出窗口
- 有非空标题
- 不属于系统进程(如程序管理器、NVIDIA overlay)
改进后的完整代码
#include <windows.h> #include <iostream> #include <string> #pragma comment(lib, "User32.lib") #pragma comment(lib, "Kernel32.lib") // 判断窗口是否属于Alt+Tab/任务栏显示的窗口 BOOL IsAltTabWindow(HWND hwnd) { // 跳过不可见窗口 if (!IsWindowVisible(hwnd)) return FALSE; // 跳过工具窗口(不会出现在Alt+Tab中) LONG_PTR exStyle = GetWindowLongPtr(hwnd, GWL_EXSTYLE); if ((exStyle & WS_EX_TOOLWINDOW) != 0) return FALSE; // 确认是顶层窗口的活动弹出窗口 HWND rootOwner = GetAncestor(hwnd, GA_ROOTOWNER); HWND activePopup = GetLastActivePopup(rootOwner); if (activePopup != hwnd) return FALSE; // 跳过无标题窗口 const int titleLen = 1024; TCHAR title[titleLen] = {0}; GetWindowText(hwnd, title, titleLen); if (lstrlen(title) == 0) return FALSE; // 跳过系统程序管理器窗口 HWND progman = GetShellWindow(); if (hwnd == progman) return FALSE; // 跳过NVIDIA相关进程的窗口 DWORD pid = 0; GetWindowThreadProcessId(hwnd, &pid); HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid); if (hProcess) { TCHAR processName[MAX_PATH] = {0}; GetModuleFileNameEx(hProcess, NULL, processName, MAX_PATH); std::wstring procName(processName); if (procName.find(L"NVIDIA") != std::wstring::npos || procName.find(L"nv") != std::wstring::npos) { CloseHandle(hProcess); return FALSE; } CloseHandle(hProcess); } return TRUE; } // 获取窗口位置与尺寸 void GetWindowRectInfo(HWND hwnd, RECT& rect) { GetWindowRect(hwnd, &rect); } BOOL CALLBACK WindowCallback(HWND hwnd, LPARAM lParam) { if (IsAltTabWindow(hwnd)) { const int titleLen = 1024; TCHAR windowTitle[titleLen] = {0}; GetWindowText(hwnd, windowTitle, titleLen); RECT rect; GetWindowRectInfo(hwnd, rect); std::wcout << L"窗口标题:" << windowTitle << std::endl; std::wcout << L"位置:(" << rect.left << L", " << rect.top << L")" << std::endl; std::wcout << L"尺寸:宽" << rect.right - rect.left << L" 高" << rect.bottom - rect.top << L"\n" << std::endl; } return TRUE; } int main() { EnumWindows(WindowCallback, NULL); return 0; }
代码说明
- 严格过滤:补充了无标题窗口、系统程序管理器、NVIDIA进程窗口的判断,确保只保留用户可见的应用窗口。
- 位置尺寸输出:通过
GetWindowRect获取窗口的屏幕坐标和宽高,并加入到输出内容中。 - 中文兼容:使用
std::wcout输出宽字符,避免中文标题乱码。
内容的提问来源于stack exchange,提问作者SirGolem
相关产品推荐
相关产品推荐

