C++ 为什么EnumWindows返回的窗口比我预期的多?

C++ 为什么EnumWindows返回的窗口比我预期的多?,c++,windows,visual-c++,styles,C++,Windows,Visual C++,Styles,在VC++中,我使用EnumWindows(…)、GetWindow(…)和GetWindowLong()来获取窗口列表,并检查窗口是否为顶部窗口(没有其他窗口作为所有者),以及窗口是否可见(WS_visible)。然而,虽然我的桌面上只显示了5个窗口,但这个窗口给了我50个窗口,真有趣!这里的任何Windows极客请帮助我澄清…您所说的带有X按钮和标题栏等的窗口并不是唯一的窗口。按钮、下拉菜单、标签、图标、文本框、任务栏以及几乎所有其他内容都是一个窗口。因此,EnumWindows正在做它应该

在VC++中,我使用EnumWindows(…)、GetWindow(…)和GetWindowLong()来获取窗口列表,并检查窗口是否为顶部窗口(没有其他窗口作为所有者),以及窗口是否可见(WS_visible)。然而,虽然我的桌面上只显示了5个窗口,但这个窗口给了我50个窗口,真有趣!这里的任何Windows极客请帮助我澄清…

您所说的带有X按钮和标题栏等的窗口并不是唯一的窗口。按钮、下拉菜单、标签、图标、文本框、任务栏以及几乎所有其他内容都是一个窗口。因此,
EnumWindows
正在做它应该做的事情:枚举所有顶级窗口

1即使这是真的,
EnumWindows
只枚举顶级窗口。这意味着:

EnumWindows函数不枚举子窗口,系统拥有的具有WS_子样式的少数顶级窗口除外


但是,桌面上的许多东西也是窗口,而不仅仅是您正在考虑的“窗口”。

Raymond在MSDN博客上的这篇文章中介绍了在任务栏(或类似的Alt Tab框)中仅列出窗口的方法:

这是检查alt tab中是否显示窗口的超级函数:

BOOL IsAltTabWindow(HWND hwnd)
{
    TITLEBARINFO ti;
    HWND hwndTry, hwndWalk = NULL;

    if(!IsWindowVisible(hwnd))
        return FALSE;

    hwndTry = GetAncestor(hwnd, GA_ROOTOWNER);
    while(hwndTry != hwndWalk) 
    {
        hwndWalk = hwndTry;
        hwndTry = GetLastActivePopup(hwndWalk);
        if(IsWindowVisible(hwndTry)) 
            break;
    }
    if(hwndWalk != hwnd)
        return FALSE;

    // the following removes some task tray programs and "Program Manager"
    ti.cbSize = sizeof(ti);
    GetTitleBarInfo(hwnd, &ti);
    if(ti.rgstate[0] & STATE_SYSTEM_INVISIBLE)
        return FALSE;

    // Tool windows should not be displayed either, these do not appear in the
    // task bar.
    if(GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_TOOLWINDOW)
        return FALSE;

    return TRUE;
}
这里的源代码:

由@jondinham提供的服务对我来说确实非常有效。所以我制定了自己的解决方案

1.以前解决方案遇到的问题

在Windows10家庭版1909上运行,我得到了两个额外的意外窗口“计算器”和“设置”

此外,无法检测的windows,因为以下操作失败:

// the following removes some task tray programs and "Program Manager"
ti.cbSize = sizeof(ti);
GetTitleBarInfo(hwnd, &ti);
if(ti.rgstate[0] & STATE_SYSTEM_INVISIBLE)
    return FALSE;
然而,我认为这个漏洞可能是由于腾讯QQ的特殊性造成的,我甚至不能用它的“窗口”来达到最高点

也许有人能帮我弄清楚为什么会发生这种情况,并帮助@jondinham改进以前的解决方案

2.我的解决方案

我试图检查窗口的图标,过滤掉没有自己图标或使用与系统默认图标相同的图标的窗口。我使用和中的代码片段并进行了一些修改。这个解决方案对我很有效

HICON get_windows_HICON_critical(HWND hwnd)
{
    // Get the window icon
    HICON icon = reinterpret_cast<HICON>(::SendMessageW(hwnd, WM_GETICON, ICON_SMALL, 0));
    if (icon == 0) {
      // Alternative method. Get from the window class
      icon = reinterpret_cast<HICON>(::GetClassLongPtrW(hwnd, GCLP_HICONSM));
    }
    // Alternative method: get the first icon from the main module (executable image of the process)
    if (icon == 0) {
      icon = ::LoadIcon(GetModuleHandleW(0), MAKEINTRESOURCE(0));
    }
//    // Alternative method. Use OS default icon
//    if (icon == 0) {
//      icon = ::LoadIcon(0, IDI_APPLICATION);
//    }
    if(icon == ::LoadIcon(0, IDI_APPLICATION)){
        // Filter out those with default icons
        icon = 0;
    }
    return icon;
}


static BOOL CALLBACK enumWindowCallback(HWND hWnd, LPARAM lparam) {
    int length = GetWindowTextLength(hWnd);
    char* buffer = new char[length + 1];
    GetWindowText(hWnd, buffer, length + 1);
    std::string windowTitle(buffer);

    // List visible windows with a non-empty title
    if (IsWindowVisible(hWnd) && length != 0) {
        HICON icon = get_windows_HICON_critical(hWnd);
        if(icon!=0){
            std::cout << hWnd << ":  " << windowTitle << std::endl;
        }
    }
    return TRUE;
}
HICON获取\u窗口\u HICON\u关键(HWND-HWND)
{
//获取窗口图标
HICON icon=reinterpret_cast(::sendmagesw(hwnd,WM_GETICON,icon_SMALL,0));
如果(图标==0){
//替代方法。从窗口类获取
icon=重新解释强制转换(::GetClassLongPtrW(hwnd,GCLP_HICONSM));
}
//替代方法:从主模块获取第一个图标(进程的可执行映像)
如果(图标==0){
icon=::LoadIcon(GetModuleHandleW(0),MAKEINTRESOURCE(0));
}
////替代方法。使用操作系统默认图标
//如果(图标==0){
//图标=::加载图标(0,IDI_应用程序);
//    }
如果(图标==::加载图标(0,IDI_应用程序)){
//过滤掉那些默认图标
图标=0;
}
返回图标;
}
静态布尔回调enumWindowCallback(HWND HWND,LPARAM LPARAM){
int length=GetWindowTextLength(hWnd);
字符*缓冲区=新字符[长度+1];
GetWindowText(hWnd,缓冲区,长度+1);
std::字符串窗口标题(缓冲区);
//列出具有非空标题的可见窗口
如果(IsWindowVisible(hWnd)&&length!=0){
HICON图标=获取windows HICON临界值(hWnd);
如果(图标!=0){

std::有没有想法摆脱不相关的“所谓”窗口?我只想要一个可见窗口的列表(应用程序窗口,不是对话框,不是按钮等),你可能只想要。"每当应用程序创建非自有窗口时,Shell都会在任务栏上创建一个按钮。若要确保窗口按钮放置在任务栏上,请使用WS_EX_APPWINDOW扩展样式创建一个无主窗口。若要防止窗口按钮放置在任务栏上,请使用WS_EX_TOOLWINDOW扩展样式创建无主窗口样式。作为一种替代方法,您可以创建一个隐藏窗口,并使此隐藏窗口成为可见窗口的所有者。“是的,我希望窗口列表显示在任务栏中。我知道如何隐藏、以不同模式显示窗口;但我不知道如何获取此信息。”list@DavidHeffernan您的链接在“http//msdn…”中缺少“:”。。。,在Firefox中被破坏,它将此扩展到www.http。com@DavidHeffernan我说的是这个链接我甚至看到一个叫做“开始按钮”的窗口这是因为启动按钮是一个窗口。任何人都知道为什么这个函数似乎不考虑雷蒙德在他的博客文章中提到的<代码> WSXEXOTKORKORK< <代码>和<代码> WSXEXAPAPWORK< /COD>扩展样式的例子?<代码> StaseSyStuleIdaby<代码>,还是这个函数与雷蒙德描述的函数不完全匹配?damsmith toolwindow不是顶部窗口,它不会显示在任务栏或alt tab菜单中。因为toolwindow的父窗口不是空的,一个额外的改进是从列表中删除工具窗口,它也不应该显示。正如@DavidHeffernan在另一个答案中提到的,这是有文档记录的。我通过检查改进了上面的代码:
if(GetWindowLong(hwnd,GWL_EXSTYLE)&WS_EX_TOOLWINDOW)返回FALSE;