2008-10-16 18 views
23

Estoy creando un reemplazo de alt-tab para Vista, pero tengo algunos problemas para enumerar todos los programas activos.Enumerar ventanas como alt-tab hace

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

Respuesta

23

Raymond Chen respondió este un tiempo atrás (http://blogs.msdn.com/oldnewthing/archive/2007/10/08/5351207.aspx):

En realidad es bastante simple, aunque casi cualquier cosa que sería capaz de adivinar por su cuenta. Nota: Los detalles de este algoritmo son un detalle de implementación . Puede cambiar en cualquier momento, por lo que no confíe en él. De hecho, ya cambió con Flip y Flip3D; Solo estoy hablando de la ventana Classic Alt + Tab aquí.

Para cada ventana visible, suba su cadena de propietario hasta que encuentre el propietario raíz . Luego vuelva a bajar la cadena emergente activa visible hasta que encuentre una ventana visible. Si ha vuelto al donde se inició, coloque 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 al blog de Chen para más detalles y algunas condiciones de esquina.

+0

Tenga en cuenta que esta implementación no respeta los estilos extendidos 'WS_EX_TOOLWINDOW' y' WS_EX_APPWINDOW' mencionados en la publicación de blog de Raymond. –

+3

Aquí hay un ejemplo más completo y robusto basado en este método https://github.com/christianrondeau/GoToWindow/blob/e41b822e7254fdc40a40fbbeec251e6ffc1959f8/GoToWindow.Api/WindowsListFactory.cs#L45 Es de una utilidad alt-tab alternativa, que parece mostrar exactamente qué menú regular de alt-tab hace. – blade

11

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

Sin embargo, hay algunas excepciones que se tiene que hacer, Windows Live Messenger tiene un montón de trucos para la creación de sombras debajo de las ventanas, etc: @

Aquí está mi código completo, han estado usando durante un día de vez en havn No notó 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); 
    } 
+5

¿De dónde viene 'WindowInformation'? Lo busqué en Google de varias maneras y no he reconocido nada útil. ¿Es un tipo personalizado? –

+0

Puede usar esto: https://github.com/akfish/MwLib/blob/master/Native/WindowInfo.cs – joshcomley

Cuestiones relacionadas