Enumerar ventanas como Alt-Tab hace

Estoy creando un reemplazo de alt-tab para Vista, pero tengo algunos problemas para enumerar todos los progtwigs activos.

Estoy usando EnumWindows para obtener una lista de Windows, pero esta lista es enorme. Contiene alrededor de 400 elementos cuando solo tengo 10 ventanas abiertas. Parece ser un hwnd para cada control y muchas otras cosas.

Así que tengo que filtrar esta lista de alguna manera, pero no puedo hacerlo exactamente como lo hace alt-tab.

Este es el código que uso para filtrar la lista en este momento. Funciona bastante bien, pero tengo algunas ventanas no deseadas, como ventanas de herramientas separadas en Visual Studio y también echo de menos ventanas como iTunes y 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; } 

Raymond Chen respondió esto hace un tiempo ( http://blogs.msdn.com/oldnewthing/archive/2007/10/08/5351207.aspx ):

En realidad es bastante simple, aunque no hay nada que puedas adivinar por tu cuenta. Nota: Los detalles de este algoritmo son un detalle de implementación. Puede cambiar en cualquier momento, así que no confíe en ello. De hecho, ya cambió con Flip y Flip3D; Solo estoy hablando de la ventana Classic Alt + Tab aquí.

Para cada ventana visible, recorra su cadena de propietarios hasta encontrar el propietario de la raíz. Luego recorra la cadena emergente activa visible hasta que encuentre una ventana visible. Si vuelves al punto de partida, coloca la ventana en la lista Alt + Tab. En pseudo-código:

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

Siga el enlace a la entrada del blog de Chen para más detalles y algunas condiciones de esquina.

Gracias Mike B. El ejemplo del blog Raymonds me indicó la dirección correcta.

Sin embargo, hay algunas excepciones que hay que hacer, Windows Live Messenger tiene muchos problemas para crear sombras en ventanas, etc.

Aquí está mi código completo, lo he usado por un día y no he notado ninguna diferencia con la pestaña alt real. Hay un código subyacente no publicado, pero no hay problema para averiguar qué hace. 🙂

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