2009-05-05 16 views
18

Estoy haciendo una aplicación donde interactúo con cada aplicación en ejecución. En este momento, necesito una forma de obtener el orden Z de la ventana. Por ejemplo, si Firefox y el Bloc de notas se están ejecutando, necesito saber cuál está al frente.¿Cómo obtener el orden z en Windows?

¿Alguna idea? Además de hacer esto para la ventana principal de cada aplicación, también tengo que hacerlo para sus ventanas secundarias y secundarias (ventanas que pertenecen al mismo proceso).

Respuesta

10

Puede usar la función GetTopWindow para buscar en todas las ventanas secundarias de una ventana primaria y devolver un identificador a la ventana secundaria que es más alta en orden z. La función GetNextWindow recupera un manejador de la ventana siguiente o anterior en z-order.

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

Y el "escritorio" debe poder usarse como la ventana padre especificando nulo para el elemento primario. Por lo tanto, puede obtener fácilmente la ventana de nivel superior en el escritorio. –

+0

Esto no es confiable. 'GetNextWindow' simplemente llama a' GetWindow'. De la [referencia 'GetWindow'] (https://msdn.microsoft.com/en-us/library/ms633515 (v = vs.85) .aspx):" _Una aplicación que llama a GetWindow para realizar esta tarea corre el riesgo de ser atrapada en un bucle infinito o haciendo referencia a un identificador de una ventana que se ha destruido. " – 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

Niza y concisa:

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

Si necesita más fiabilidad:

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

(De acuerdo con la sección de observaciones en GetWindow, EnumChildWindows es más seguro que llamar GetWindow en un bucle porque su bucle GetWindow no es atómico a cambios externos. De acuerdo con la sección Parámetros para EnumChildWindows, llamando con una matriz nula es equivalente a EnumWindows.)

Entonces, en lugar de una llamada independiente a EnumWindows para cada ventana, que tampoco sería ser atómica y seguro de los cambios simultáneos, se envía cada ventana que desee comparar en una matriz de params para que sus órdenes z puedan recuperarse todas al mismo tiempo.

+1

No funciona, al comparar dos ventanas superpuestas, como un formulario y la barra de tareas, por ejemplo. Cuando la ventana está sobre la barra de tareas, el orden Z de la barra de tareas es más alto que la ventana que sugiere que la barra de tareas está en la parte superior, y no está. – Codebeat

+0

En realidad, cambié de opinión. @Erwinus, [según Microsoft] (https://msdn.microsoft.com/en-us/library/windows/desktop/ms632599%28v=vs.85%29.aspx#zorder) las ventanas de nivel superior aparecen en z- ordene * antes * otras ventanas, lo que implica que un número de orden Z más pequeño significa que la ventana es realmente más alta. La forma en que 'EnumWindows' y' GW_HWNDPREV' y 'GW_HWNDNEXT' funcionan lo confirma. Las otras respuestas aquí están de acuerdo. Me da pena hacer este contador a la API de Windows. – jnm2

+0

@HansPassant, respeto tu opinión sobre esto. ¿Hay algún otro problema? – jnm2

0

Aquí está mi solución de C#: La función devuelve zIndex entre los hermanos del HWND dado, comenzando en 0 para el zOrder más bajo.

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