2009-05-05 13 views
18

Tworzę aplikację, w której wchodzę w interakcję z każdą uruchomioną aplikacją. W tej chwili potrzebuję sposobu na uzyskanie kolejności okien w oknie. Na przykład, jeśli Firefox i Notatnik są uruchomione, muszę wiedzieć, który z nich jest z przodu.Jak uzyskać porządek "Z" w oknach?

Wszelkie pomysły? Poza robieniem tego dla głównego okna każdej aplikacji, muszę to zrobić również dla jego okien potomnych i siostrzanych (okien należących do tego samego procesu).

Odpowiedz

10

Możesz użyć funkcji GetTopWindow, aby przeszukać wszystkie okna podrzędne w oknie nadrzędnym i przywrócić uchwyt do okna podrzędnego, które ma najwyższą kolejność. Funkcja GetNextWindow pobiera uchwyt do następnego lub poprzedniego okna w kolejności z.

GetTopWindow: http://msdn.microsoft.com/en-us/library/ms633514(VS.85).aspx
GetNextWindow: http://msdn.microsoft.com/en-us/library/ms633509(VS.85).aspx

+3

A "pulpit" powinien być używany jako okno nadrzędne przez podanie wartości NULL dla elementu nadrzędnego. Dzięki temu możesz łatwo uzyskać okno najwyższego poziomu na pulpicie. –

+0

To nie jest niezawodne. 'GetNextWindow' po prostu wywołuje' GetWindow'. Z [odniesienia GetWindow] (https://msdn.microsoft.com/en-us/library/ms633515 (v = vs.85) .aspx): "_Anulacja, która wywołuje GetWindow w celu wykonania tego zadania, może zostać przyłapana w nieskończonej pętli lub odwołując się do uchwytu do okna, które zostało zniszczone._ " – zett42

1
  // Find z-order for window. 
      Process[] procs = Process.GetProcessesByName("notepad"); 
      Process top = null; 
      int topz = int.MaxValue; 
      foreach (Process p in procs) 
      { 
       IntPtr handle = p.MainWindowHandle; 
       int z = 0; 
       do 
       { 
        z++; 
        handle = GetWindow(handle, 3); 
       } while(handle != IntPtr.Zero); 

       if (z < topz) 
       { 
        top = p; 
        topz = z; 
       } 
      } 

      if(top != null) 
       Debug.WriteLine(top.MainWindowTitle); 
6

Nicea i lakoniczny:

int GetZOrder(IntPtr hWnd) 
{ 
    var z = 0; 
    for (var h = hWnd; h != IntPtr.Zero; h = GetWindow(h, GW.HWNDPREV)) z++; 
    return z; 
} 

Jeśli potrzebujesz więcej niezawodność:

/// <summary> 
/// Gets the z-order for one or more windows atomically with respect to each other. In Windows, smaller z-order is higher. If the window is not top level, the z order is returned as -1. 
/// </summary> 
int[] GetZOrder(params IntPtr[] hWnds) 
{ 
    var z = new int[hWnds.Length]; 
    for (var i = 0; i < hWnds.Length; i++) z[i] = -1; 

    var index = 0; 
    var numRemaining = hWnds.Length; 
    EnumWindows((wnd, param) => 
    { 
     var searchIndex = Array.IndexOf(hWnds, wnd); 
     if (searchIndex != -1) 
     { 
      z[searchIndex] = index; 
      numRemaining--; 
      if (numRemaining == 0) return false; 
     } 
     index++; 
     return true; 
    }, IntPtr.Zero); 

    return z; 
} 

(Według sekcji Uwagi o GetWindow, EnumChildWindows jest bezpieczniejsze niż wywoływanie GetWindow w pętli, ponieważ twoja pętla GetWindow nie jest atomowa dla zewnętrznych zmian. Według sekcji Parametry dla EnumChildWindows, dzwonisz z pustym rodzica jest równoważna EnumWindows.)

Wtedy zamiast osobnego wezwania do EnumWindows dla każdego okna, które również nie można być atomowy i bezpieczny z jednoczesnych zmian wyślesz każde okno, które chcesz porównać w tablicy params, aby wszystkie zamówienia z-Z można było pobrać w tym samym czasie.

+1

Nie działa, gdy porównuje się dwa nakładające się okna, na przykład formularz i pasek zadań. Gdy okno znajduje się nad paskiem zadań, kolejność z rzędu z menu jest wyższa niż okno sugerujące, że pasek zadań znajduje się na górze, a nie na pasku zadań. – Codebeat

+0

Właściwie to zmieniłem zdanie. @Erwinus, [zgodnie z Microsoft] (https://msdn.microsoft.com/en-us/library/windows/desktop/ms632599%28v=vs.85%29.aspx#zorder) okna najwyższego poziomu pojawiają się w z- order * before * other windows, co oznacza, że ​​mniejszy numer zamówienia z oznacza, że ​​okno jest rzeczywiście wyższe. Sposób, w jaki działają funkcje 'EnumWindows' i' GW_HWNDPREV' oraz 'GW_HWNDNEXT'. Inne odpowiedzi tutaj zgadzają się. Nie cierpię robić tego licznika względem interfejsu Windows API. – jnm2

+0

@HansPassant, szanuję twoją opinię na ten temat. Czy są jakieś inne gry? – jnm2

0

Oto moje rozwiązanie C#: Funkcja zwraca zIndex wśród rodzeństwa danego HWND, zaczynając od 0 dla najniższego zOrder.

using System; 
using System.Runtime.InteropServices; 

namespace Win32 
{ 
    public static class HwndHelper 
    { 
     [DllImport("user32.dll")] 
     private static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd); 

     public static bool GetWindowZOrder(IntPtr hwnd, out int zOrder) 
     { 
      const uint GW_HWNDPREV = 3; 
      const uint GW_HWNDLAST = 1; 

      var lowestHwnd = GetWindow(hwnd, GW_HWNDLAST); 

      var z = 0; 
      var hwndTmp = lowestHwnd; 
      while (hwndTmp != IntPtr.Zero) 
      { 
       if (hwnd == hwndTmp) 
       { 
        zOrder = z; 
        return true; 
       } 

       hwndTmp = GetWindow(hwndTmp, GW_HWNDPREV); 
       z++; 
      } 

      zOrder = int.MinValue; 
      return false; 
     } 
    } 
} 
Powiązane problemy