【问题标题】:Why does EnumWindows return more windows than I expected?为什么 EnumWindows 返回的窗口比我预期的要多?
【发布时间】:2011-11-08 19:02:54
【问题描述】:

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

【问题讨论】:

  • 我什至看到了一个名为“开始按钮”的窗口
  • 那是因为开始按钮是一个窗口。

标签: c++ windows visual-c++ styles


【解决方案1】:

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

Which windows appear in the Alt+Tab list?

这是检查窗口是否显示在 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;
}

感谢这里的源代码:
http://www.dfcd.net/projects/switcher/switcher.c

【讨论】:

  • 有人知道为什么这个函数似乎没有考虑 Raymond 在他的博客文章中提到的 WS_EX_TOOLWINDOWWS_EX_APPWINDOW 扩展样式案例吗? STATE_SYSTEM_INVISIBLE 是否涵盖了它,或者此功能与 Raymond 描述的功能不完全匹配?
  • @adamsmith toolwindow 不是顶部窗口,它不会显示在任务栏或 alt-tab 菜单中。因为toolwindow的父窗口不为null
  • 另一个改进是从列表中删除工具窗口,这也不应该显示。正如@DavidHeffernan 在另一个答案中提到的那样,这记录在in the following MSDN article 中。我通过检查改进了上面的代码:if(GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_TOOLWINDOW) return FALSE;
【解决方案2】:

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

1 尽管这是真的,EnumWindows 只枚举顶级窗口。这意味着it won't enumerate any child windows:

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

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

【讨论】:

  • 所以有什么想法可以摆脱不相关的“所谓”窗口吗?我只想要一个可见窗口列表(应用程序窗口,不是对话框,不是按钮等)
  • 您可能只需要windows that appear in the taskbar。 “每当应用程序创建一个不属于自己的窗口时,Shell 在任务栏上创建一个按钮。为确保窗口按钮放置在任务栏上,请创建一个具有 WS_EX_APPWINDOW 扩展样式的无主窗口。防止窗口按钮被放置在任务栏上,使用 WS_EX_TOOLWINDOW 扩展样式创建无主窗口。作为替代方案,您可以创建一个隐藏窗口,并让这个隐藏窗口成为可见窗口的所有者。"
  • 是的,我想要任务栏中出现的窗口列表。我知道如何隐藏,以不同的模式显示窗口;但我不知道如何获取此列表
  • @DavidHeffernan 您的链接在“http//msdn...”中缺少':',在 Firefox 中损坏,将其扩展到 www.http.com
  • @DavidHeffernan 我说的是这个windows that appear in the taskbar链接
【解决方案3】:

@jondinham 提供的answer 对我来说非常有效。所以我想出了自己的解决方案。

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

在 Windows 10 家庭版 1909 上运行。我得到了两个额外的意外 Windows“计算器”和“设置”。

另外,无法检测到Tencent QQ的窗口,原因如下:

// 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;

不过,我觉得这个bug可能是腾讯QQ的特殊性造成的,我什至不能用DeferWindowPos把它的窗口置顶。

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

2.我的解决方案

我尝试检查窗口的图标,并过滤掉没有自己图标或使用与系统默认图标相同的图标的窗口。我使用来自answeranswer 的代码sn-ps 并进行一些修改。这个解决方案对我来说效果很好。

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;
}

3.我的解决方案存在问题

我的解决方案不能处理Windows Store APP,根据this question.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-11-13
    • 1970-01-01
    • 1970-01-01
    • 2010-09-22
    • 1970-01-01
    • 1970-01-01
    • 2016-01-23
    • 1970-01-01
    相关资源
    最近更新 更多