Enumerate windows like alt-tab does

I'm creating an alt-tab replacement for Vista but I have some problems listing all active programs.

I'm using EnumWindows to get a list of Windows, but this list is huge. It contains about 400 items when I only have 10 windows open. It seems to be a hwnd for every single control and a lot of other stuff.

So I have to filter this list somehow, but I can't manage to do it exactly as alt-tab does.

This is the code I use to filter the list right now. It works pretty well, but I get some unwanted windows like detached tool-windows in Visual Studio and I also miss windows like iTunes and Warcraft3.

private bool ShouldWindowBeDisplayed(IntPtr window)
{
    uint windowStyles = Win32.GetWindowLong(window, GWL.GWL_STYLE);

    if (((uint)WindowStyles.WS_VISIBLE & windowStyles) != (uint)WindowStyles.WS_VISIBLE ||
        ((uint)WindowExStyles.WS_EX_APPWINDOW & windowStyles) != (uint)WindowExStyles.WS_EX_APPWINDOW)
    {
        return true;
    }
    return false;
}

Solution 1:

Raymond Chen answered this a while back
(https://devblogs.microsoft.com/oldnewthing/20071008-00/?p=24863):

It's actually pretty simple although hardly anything you'd be able to guess on your own. Note: The details of this algorithm are an implementation detail. It can change at any time, so don't rely on it. In fact, it already changed with Flip and Flip3D; I'm just talking about the Classic Alt+Tab window here.

For each visible window, walk up its owner chain until you find the root owner. Then walk back down the visible last active popup chain until you find a visible window. If you're back to where you're started, then put the window in the Alt+Tab list. In pseudo-code:

BOOL IsAltTabWindow(HWND hwnd)
{
 // Start at the root owner
 HWND hwndWalk = GetAncestor(hwnd, GA_ROOTOWNER);

 // See if we are the last active visible popup
 HWND hwndTry;
 while ((hwndTry = GetLastActivePopup(hwndWalk)) != hwndTry) {
  if (IsWindowVisible(hwndTry)) break;
  hwndWalk = hwndTry;
 }
 return hwndWalk == hwnd;
}

Follow the link to Chen's blog entry for more details and some corner conditions.

Solution 2:

Thanks Mike B. The example from Raymonds blog pointed me in the correct direction.

There are however some exceptions that has to be made, Windows Live messenger got alot of hacks for creating shadows under windows etc :@

Here is my complete code, have been using it for one day now and havn't noticed any differences from the real alt tab. There's some underlying code not posted but it's no problem figuring out what it does. :)

    private static bool KeepWindowHandleInAltTabList(IntPtr window)
    {
        if (window == Win32.GetShellWindow())   //Desktop
            return false;

        //http://stackoverflow.com/questions/210504/enumerate-windows-like-alt-tab-does
        //http://blogs.msdn.com/oldnewthing/archive/2007/10/08/5351207.aspx
        //1. For each visible window, walk up its owner chain until you find the root owner. 
        //2. Then walk back down the visible last active popup chain until you find a visible window.
        //3. If you're back to where you're started, (look for exceptions) then put the window in the Alt+Tab list.
        IntPtr root = Win32.GetAncestor(window, Win32.GaFlags.GA_ROOTOWNER);

        if (GetLastVisibleActivePopUpOfWindow(root) == window)
        {
            WindowInformation wi = new WindowInformation(window);

            if (wi.className == "Shell_TrayWnd" ||                          //Windows taskbar
                wi.className == "DV2ControlHost" ||                         //Windows startmenu, if open
                (wi.className == "Button" && wi.windowText == "Start") ||   //Windows startmenu-button.
                wi.className == "MsgrIMEWindowClass" ||                     //Live messenger's notifybox i think
                wi.className == "SysShadow" ||                              //Live messenger's shadow-hack
                wi.className.StartsWith("WMP9MediaBarFlyout"))              //WMP's "now playing" taskbar-toolbar
                return false;

            return true;
        }
        return false;
    }

    private static IntPtr GetLastVisibleActivePopUpOfWindow(IntPtr window)
    {
        IntPtr lastPopUp = Win32.GetLastActivePopup(window);
        if (Win32.IsWindowVisible(lastPopUp))
            return lastPopUp;
        else if (lastPopUp == window)
            return IntPtr.Zero;
        else
            return GetLastVisibleActivePopUpOfWindow(lastPopUp);
    }