18

In VC++, I use EnumWindows(...), GetWindow(...), and GetWindowLong(), to get the list of windows and check whether the window is top window (no other window as owner), and whether the window is visible (WS_VISIBLE). However, although my desktop is showing only 5 windows, this EnumWindows is giving me 50 windows, how funny! Any Windows geek here please help me clarify...

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
jondinham
  • 8,271
  • 17
  • 80
  • 137

4 Answers4

37

The way to list out only windows in taskbar (or similarly in Alt-Tab box) is described by Raymond in this article on MSDN blog:

Which windows appear in the Alt+Tab list?

And this is the super function to check whether a window is shown in 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;
}

Credited to the source code here:
http://www.dfcd.net/projects/switcher/switcher.c

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
jondinham
  • 8,271
  • 17
  • 80
  • 137
  • 1
    Anyone know why this function doesn't seem to consider the `WS_EX_TOOLWINDOW` and `WS_EX_APPWINDOW` extended style cases mentioned by Raymond in his blog post? Does `STATE_SYSTEM_INVISIBLE` cover it or is this function not an exact match with the one Raymond describes? – adam smith Aug 13 '12 at 19:59
  • @adamsmith toolwindow isn't top window, it won't be shown in taskbar or alt-tab menu. because parent window of toolwindow is not null – jondinham Aug 14 '12 at 04:50
  • 6
    An additional improvement is to remove tool windows from the list, which also shouldn't be shown. As @DavidHeffernan mentioned in the other answer, this is documented [in the following MSDN article](http://http//msdn.microsoft.com/en-us/library/aa969325.aspx). I've improved the code above with the check: `if(GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_TOOLWINDOW) return FALSE;` – Sam Jansen Aug 17 '12 at 08:56
4

The windows that you are talking about, with an X button and a title bar, etc. are not the only kind of windows. Buttons, dropdown menus, labels, icons, text boxes, the task bar, and just about everything else is a window too1. So EnumWindows is doing exactly what it's supposed to do: enumerate all the top level windows.

1 Even though this is true, EnumWindows only enumerates the top level windows. That means it won't enumerate any child windows:

The EnumWindows function does not enumerate child windows, with the exception of a few top-level windows owned by the system that have the WS_CHILD style.

However, many things on your desktop are windows as well, not just the "windows" you're thinking about.

Seth Carnegie
  • 73,875
  • 22
  • 181
  • 249
  • so any idea to get rid of unrelated "so-called" windows? i just want a list of visible windows (application windows, not dialog, not buttons, etc) – jondinham Sep 01 '11 at 22:46
  • 3
    You probably want just the [windows that appear in the taskbar](http://http://msdn.microsoft.com/en-us/library/aa969325.aspx). "The Shell creates a button on the taskbar whenever an application creates a window that isn't owned. To ensure that the window button is placed on the taskbar, create an unowned window with the WS_EX_APPWINDOW extended style. To prevent the window button from being placed on the taskbar, create the unowned window with the WS_EX_TOOLWINDOW extended style. As an alternative, you can create a hidden window and make this hidden window the owner of your visible window." – David Heffernan Sep 01 '11 at 22:59
  • yes, i want the list of windows appearing in the taskbar. i know how to hide, show a window in different mode; but i don't know how to get this list – jondinham Sep 02 '11 at 04:58
  • 1
    @DavidHeffernan Your link is missing ':' in "http//msdn...", broken in Firefox which expands this to www.http.com – jv-dev Mar 22 '18 at 14:41
  • @alias65536 Sorry. I can't fix it now. You could have included a corrected link in your comment. – David Heffernan Mar 22 '18 at 14:55
  • 1
    @DavidHeffernan I'm talking about this [windows that appear in the taskbar](http://msdn.microsoft.com/en-us/library/aa969325.aspx) link – jv-dev Mar 22 '18 at 20:11
1

The answer provided by @jondinham does work perfectly for me. So I work out my own solution.

1.Problems I met with previous solution

Running on Windows 10 home edition 1909., I get two extra unexpected Windows "Calculator" and "Setting".

In addition, windows of Tencent QQ can not be detected, because the following fails:

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

However, I think the bug may be resulted by the particularity of Tencent QQ, I can not even make its' window TOPMOST with DeferWindowPos.

Perhaps someone can help me figure out why this happened and help improving the previous solution by @jondinham.

2.My Solution

I tried to examing the icons of the windows, and filter out windows that does not have its own icon or uses the icon same as the system default. I use code snippets from answer and answer and do some modification. This solution works very well for me.

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.Problems with my solution

My solution can not deal with Windows Store APP, according to this question.

hellohawaii
  • 3,074
  • 6
  • 21
1

For all people looking to find a way to remove Invisible windows like Settings or Microsoft Store from the list:

These windows are cloaked, meaning they still have the dwStyle WS_VISIBLE, but the user can't see them.

You can detect this using the function DwmGetWindowAttribute. The dwAttribute you want to get is DWMWA_CLOAKED (enum constant 14). Only if the value in pvAttribute after the method call is 0, the window is not cloacked.

LinusDev
  • 26
  • 1