2008-10-16 13 views
23

Tworzę zastępczy alt-tab dla Vista, ale mam problemy z listą wszystkich aktywnych programów.Wyliczanie okien, takich jak alt-tab ma

Używam EnumWindows, aby uzyskać listę systemów Windows, ale ta lista jest ogromna. Zawiera około 400 pozycji, gdy mam tylko 10 otwartych okien. Wygląda na to, że jest to hwnd dla każdej kontroli i wielu innych rzeczy.

Muszę więc jakoś filtrować tę listę, ale nie mogę tego zrobić dokładnie tak, jak robi to karta alt.

To jest kod, którego używam do filtrowania listy już teraz. Działa całkiem nieźle, ale dostaję niechciane okna, takie jak odłączone okna narzędzi w Visual Studio, a także brakuje mi okien takich jak iTunes i 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; 
} 

Odpowiedz

23

Raymond Chen odpowiedziało na to jakiś czas temu (http://blogs.msdn.com/oldnewthing/archive/2007/10/08/5351207.aspx):

To rzeczywiście dość prosta, choć prawie nic byłbyś w stanie odgadnąć na własną rękę. Uwaga: Szczegóły tego algorytmu są szczegółami implementacji . Może się zmienić w dowolnym momencie, więc nie polegaj na nim. W rzeczywistości już zmieniono za pomocą Flip i Flip3D; Jestem tylko mówi o klasycznym oknie Alt + Tab tutaj.

W każdym widocznym oknie przejdź do łańcucha właściciela , aż znajdziesz właściciela root'a . Następnie idź w dół widocznego ostatniego aktywnego łańcucha wyskakujących okienek, aż znajdziesz widoczne okno. Jeśli wrócisz do , gdzie jesteś uruchomiony, umieść okno na liście Alt + Tab. W pseudo-kod:

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 do wpisu na blogu Chena Więcej informacji oraz pewnych warunkach narożnych.

+0

Zauważ, że ta realizacja nie czci '' WS_EX_APPWINDOW' WS_EX_TOOLWINDOW' i rozszerzony style mowa w Raymonda blogu. –

+3

Oto bardziej kompletny i solidny przykład oparty na tej metodzie https://github.com/christianrondeau/GoToWindow/blob/e41b822e7254fdc40a40fbbeec251e6ffc1959f8/GoToWindow.Api/WindowsListFactory.cs#L45 Jest z alternatywnego narzędzia alt-tab, które wydaje się pokazywać dokładnie to, co robi regularne menu z kartami alt. – blade

11

Dzięki Mike B. Przykład z bloga Raymondsa wskazał mi właściwy kierunek.

Istnieją jednak pewne wyjątki, które muszą być wykonane, Windows Live Messenger dostał dużo hacków do tworzenia cieni pod oknami itp: @

Tu jest mój pełny kod, używam go na jeden dzień i teraz havn Nie zauważyłem żadnych różnic w prawdziwej zakładce alt. Kod źródłowy nie został opublikowany, ale nie ma problemu z ustaleniem, co robi. :)

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

Skąd pochodzi "WindowInformation"? Przeszukałem go na wiele sposobów i nie rozpoznałem niczego przydatnego. Czy to jest niestandardowy typ? –

+0

Możesz użyć tego: https://github.com/akfish/MwLib/blob/master/Native/WindowInfo.cs – joshcomley