You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 10:37:10