2008-10-16 7 views
23

Je crée un remplacement alt-tab pour Vista mais j'ai quelques problèmes énumérant tous les programmes actifs. J'utilise EnumWindows pour obtenir une liste de Windows, mais cette liste est énorme. Il contient environ 400 articles quand j'ai seulement 10 fenêtres ouvertes. Cela semble être un truc pour chaque contrôle et beaucoup d'autres choses.Enumerate windows comme alt-tab fait

Je dois donc filtrer cette liste, mais je n'arrive pas à la faire exactement comme le fait Alt Tab.

C'est le code que j'utilise pour filtrer la liste maintenant. Cela fonctionne plutôt bien, mais j'ai des fenêtres non désirées comme des fenêtres d'outils détachées dans Visual Studio et des fenêtres comme iTunes et Warcraft3 me manquent aussi.

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

Répondre

23

Raymond Chen a répondu à cette un certain temps (http://blogs.msdn.com/oldnewthing/archive/2007/10/08/5351207.aspx):

Il est en fait assez simple bien quoi que ce soit à peine vous seriez en mesure de deviner sur votre propre. Remarque: Les détails de cet algorithme sont un détail d'implémentation . Il peut changer à tout moment, donc ne comptez pas dessus. En fait, il a déjà changé avec Flip et Flip3D; Je suis juste en parlant de la fenêtre Classic Alt + Tab ici.

Pour chaque fenêtre visible, parcourez sa chaîne propriétaire jusqu'à trouver le propriétaire racine . Puis redescendez la dernière chaîne de pop-up active jusqu'à ce que vous trouviez une fenêtre visible. Si vous êtes de retour à où vous avez démarré, placez la fenêtre dans la liste Alt + Tab. En 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; 
} 

Suivez le lien vers l'entrée de blog de Chen pour plus de détails et des conditions d'angle.

+0

Notez que cette implémentation n'honore pas les styles étendus 'WS_EX_TOOLWINDOW' et' WS_EX_APPWINDOW' mentionnés dans l'article de Raymond. –

+3

Voici un exemple plus complet et robuste basé sur cette méthode https://github.com/christianrondeau/GoToWindow/blob/e41b822e7254fdc40a40fbbeec251e6ffc1959f8/GoToWindow.Api/WindowsListFactory.cs#L45 Il s'agit d'un utilitaire alternatif alt-tab, qui semble montrer exactement ce que fait le menu alt-tab régulier. – blade

11

Merci Mike B. L'exemple du blog Raymonds m'a indiqué dans la bonne direction.

Il y a cependant quelques exceptions qui doit être fait, Windows Live Messenger a beaucoup de hacks pour créer des ombres sous les fenêtres etc: @

Voici mon code complet, ont été utilisé pendant un jour à l'autre et havn 't remarqué aucune différence de l'onglet alt réel. Il y a du code sous-jacent qui n'est pas publié, mais il n'y a aucun problème à comprendre ce qu'il fait. :)

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

D'où provient 'WindowInformation'? Je l'ai googlé de plusieurs façons et je n'ai rien reconnu d'utile. Est-ce un type personnalisé? –

+0

Vous pouvez utiliser ceci: https://github.com/akfish/MwLib/blob/master/Native/WindowInfo.cs – joshcomley

Questions connexes