EnumWindows no longer finds Metro/Modern UI windows: a workaround

In the final release of Windows 8, the EnumWindows function no longer lists Metro/Modern UI windows:

Note For Windows 8 and later, EnumWindows enumerates only top-level windows of desktop apps.

This change was made some time around the consumer preview release. I’m not sure why Microsoft did this, but there is a simple workaround. Instead of calling EnumWindows, call this function:

VOID EnumWindowsWithMetro(
    __in WNDENUMPROC lpEnumFunc,
    __in LPARAM lParam
    )
{
    HWND childWindow = NULL;
    ULONG i = 0;

    while (i < 1000 && (childWindow = FindWindowEx(NULL, childWindow, NULL, NULL)))
    {
        if (!lpEnumFunc(childWindow, lParam))
            return;

        i++;
    }
}

The reason this works is that FindWindowEx, unlike EnumWindows, does not ignore Metro windows. We just call FindWindowEx in a loop to keep retrieving the next window in the list until there are no more. Note the i < 1000 condition, which is there to prevent infinite loops (highly unlikely but possible, to my knowledge).

8 Comments

  1. Thanks, How can I use it in C# ? In windows 7 I used EnumWindows win = new EnumWindows(), and after method GetWindows();
    Thank you

      1. It’s possible to give me a example? My Idea is to get windows preperties like as size, title etc.. but about metro apps.. and ofcourse too about elements in app…

          1. Yes, it’s the same what I have in my desktop App. Working perfect in windows desktop apps, but it doesn’t see the metro/Windows Store apps.. the same thing is in the Window Detective… Is another way how to do it?

  2. Another solution is to use the undocumented api from win32u.dll, it has the prototype:

    NTSTATUS WINAPI NtUserBuildHwndListW10
    (
    HDESK in_hDesk,
    HWND in_hWndNext,
    BOOL in_EnumChildren,
    BOOL in_RemoveImmersive,
    DWORD in_ThreadID,
    UINT in_Max,
    HWND *out_List,
    UINT *out_Cnt
    );

    Pass it in a HWND list with Max entries, set all other parameters to zero, the output Cnt gives the number of returned entries. If the resultcode is STATUS_BUFFER_TOO_SMALL then reallocate the list with more entries and try again.

    Compared to pre-Win10 versions a parameter RemoveImmersive is added. If TRUE then the same list is returned as EnumWindows (without immersive windows). If FALSE then the full list is returned.

    The first entry of the list is 0x00000001 as handle and must be ignored.

    The advantage of this api is that the is no posibility of changing of the window list during calls to FindWIndowEx (a lock is set during bulding of the list)

    The EnumWindows, EnumDesktopWindows, EnumChildWindows, FindWindow, FindWindowEx all use this api.

    Hereby a request to Microsoft to add a public api EnumWindowsEx or EnumAllWindows so developers have a safe method to enumerate all windows. I understand they added the filter to EnumWindows to fix custom tasklists out there which display visible but cloaked immersive/metro/uwp windows. But an method should be supported for developers to get the full list.

  3. btw the api name is NtUserBuildHwndList not NtUserBuildHwndListW10, I called it like that internally because it is not the same api as the original NtUserBuildHwndList in earlier versions

Leave a Reply to wj32 Cancel reply