Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does EnumWindows return more windows than I expected?

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...

like image 322
jondinham Avatar asked Sep 01 '11 22:09

jondinham


3 Answers

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

like image 183
jondinham Avatar answered Nov 11 '22 08:11

jondinham


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.

like image 25
Seth Carnegie Avatar answered Nov 11 '22 09:11

Seth Carnegie


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.

like image 1
hellohawaii Avatar answered Nov 11 '22 08:11

hellohawaii