2009-05-05 8 views
18

Ich mache eine Anwendung, wo ich mit jeder laufenden Anwendung interagieren. Gerade jetzt brauche ich eine Möglichkeit, die Z-Reihenfolge des Fensters zu bekommen. Zum Beispiel, wenn Firefox und Notepad laufen, muss ich wissen, welches vorne ist.Wie bekomme ich die Z-Reihenfolge in Windows?

Irgendwelche Ideen? Abgesehen davon, dass ich dies für das Hauptfenster jeder Anwendung mache, muss ich es auch für seine Kinder- und Schwesterfenster (Fenster, die zu demselben Prozess gehören) tun.

Antwort

10

Mit der GetTopWindow-Funktion können Sie alle untergeordneten Fenster eines übergeordneten Fensters durchsuchen und ein Handle an das untergeordnete Fenster zurückgeben, das in z-Reihenfolge am höchsten ist. Die GetNextWindow-Funktion ruft ein Handle für das nächste oder vorherige Fenster in Z-Reihenfolge ab.

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

Und der "Desktop" sollte in der Lage sein, als das übergeordnete Fenster verwendet werden, indem Sie null für das übergeordnete Element angeben. Daher können Sie das oberste Fenster auf dem Desktop leicht erreichen. –

+0

Dies ist nicht zuverlässig. 'GetNextWindow' ruft nur' GetWindow' an. Aus der [GetWindow-Referenz] (https://msdn.microsoft.com/en-us/library/ms633515 (v = V.85) .aspx): "_Eine Anwendung, die GetWindow zum Ausführen dieser Aufgabe aufruft, läuft Gefahr, abgefangen zu werden in einer Endlosschleife oder Verweis auf ein Handle zu einem Fenster, das zerstört wurde. _ " – 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

Nizza und lapidar:

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

Wenn Sie mehr Zuverlässigkeit benötigen:

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

(entsprechend dem Abschnitt Bemerkungen zu GetWindow, EnumChildWindows ist sicherer als Aufruf GetWindow in einer Schleife, weil Ihre GetWindow Schleife nicht atomare Änderungen von außen ist. für EnumChildWindows auf den Abschnitt Parameter entsprechend, mit einer Null-Mutter Aufruf entspricht EnumWindows.)

Dann anstelle einen separaten Aufruf an EnumWindows für jedes Fenster, die auch atomare und sicher werden nicht von gleichzeitigen Änderungen würden, Sie senden jedes Fenster, das Sie in einem Parameter-Array vergleichen möchten, damit alle z-Befehle gleichzeitig abgerufen werden können.

+1

Funktioniert nicht, wenn zwei überlappende Fenster wie ein Formular und die Taskleiste zum Beispiel verglichen werden. Wenn sich das Fenster über der Taskleiste befindet, ist die Taskleiste z-Reihenfolge höher als das Fenster, das anzeigt, dass die Taskleiste oben ist, was nicht der Fall ist. – Codebeat

+0

Eigentlich habe ich meine Meinung geändert. @Erwinus, [nach Microsoft] (https://msdn.microsoft.com/en-us/library/windows/desktop/ms632599%28v=vs.85%29.aspx#zorder) Top-Level-Fenster erscheinen in z- ordnet * vor * anderen Fenstern an, was bedeutet, dass eine kleinere Z-Ordnungsnummer bedeutet, dass das Fenster tatsächlich höher ist. Die Art, wie "EnumWindows" und "GW_HWNDPREV" und "GW_HWNDNEXT" funktionieren, bestätigt dies. Die anderen Antworten stimmen hier überein. Ich verabscheue diesen Zähler gegenüber der Windows-API. – jnm2

+0

@HansPassant, ich würde Ihre Meinung zu diesem Thema respektieren. Gibt es noch andere Probleme? – jnm2

0

Hier ist meine C# -Lösung: Die Funktion gibt den zIndex unter den Geschwistern der angegebenen HWND, beginnend bei 0 für die niedrigste 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; 
     } 
    } 
} 
Verwandte Themen