2009-05-05 11 views
18

Je fais une application où j'interagis avec chaque application en cours d'exécution. En ce moment, j'ai besoin d'un moyen d'obtenir l'ordre z de la fenêtre. Par exemple, si Firefox et le bloc-notes sont en cours d'exécution, j'ai besoin de savoir lequel est devant.Comment obtenir la commande z dans windows?

Des idées? En plus de faire cela pour la fenêtre principale de chaque application, je dois aussi le faire pour ses fenêtres enfants et soeurs (fenêtres appartenant au même processus).

Répondre

10

Vous pouvez utiliser la fonction GetTopWindow pour rechercher toutes les fenêtres enfants d'une fenêtre parent et renvoyer un handle vers la fenêtre enfant la plus élevée dans l'ordre z. La fonction GetNextWindow récupère un handle à la fenêtre suivante ou précédente dans l'ordre 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

Et le "bureau" devrait pouvoir être utilisé comme la fenêtre parente en spécifiant null pour le parent. Par conséquent, vous pouvez facilement obtenir la fenêtre de niveau supérieur sur le bureau. –

+0

Ce n'est pas fiable. 'GetNextWindow' appelle simplement' GetWindow'. De la référence ['GetWindow'] (https://msdn.microsoft.com/en-us/library/ms633515 (v = vs.85) .aspx):" _Une application qui appelle GetWindow pour effectuer cette tâche risque d'être interceptée dans une boucle infinie ou référençant un handle à une fenêtre qui a été détruite._ " – 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

Nice et laconique:

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

Si vous avez besoin plus de fiabilité:

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

(Selon la section Remarques sur GetWindow, EnumChildWindows est plus sûr que d'appeler GetWindow dans une boucle parce que votre boucle GetWindow n'est pas atomique à des changements extérieurs. Selon la section Paramètres pour EnumChildWindows, appeler avec un parent nul équivaut à EnumWindows.)

Alors, au lieu d'un appel séparé à EnumWindows pour chaque fenêtre, ce qui serait également ne pas être atomique et à l'abri des changements simultanés, vous envoyez chaque fenêtre que vous voulez comparer dans un tableau params afin que leurs ordres z puissent tous être récupérés en même temps.

+1

Ne fonctionne pas, lors de la comparaison de deux fenêtres se chevauchant comme un formulaire et la barre des tâches par exemple. Lorsque la fenêtre est sur la barre des tâches, l'ordre z de la barre des tâches est plus élevé que la fenêtre qui suggère que la barre des tâches est en haut, ce qui n'est pas le cas. – Codebeat

+0

En fait, j'ai changé d'avis. @Erwinus, [selon Microsoft] (https://msdn.microsoft.com/en-us/library/windows/desktop/ms632599%28v=vs.85%29.aspx#zorder) les fenêtres de niveau supérieur apparaissent dans z- commandez * avant * d'autres fenêtres, ce qui implique qu'un plus petit nombre de z-order signifie que la fenêtre est réellement plus haute. La façon dont fonctionne 'EnumWindows' et 'GW_HWNDPREV' et' GW_HWNDNEXT' le confirme. Les autres réponses sont d'accord. Je déteste faire ce compteur à l'API Windows. – jnm2

+0

@HansPassant, je respecterais votre opinion à ce sujet. Y a-t-il d'autres pièges? – jnm2

0

Voici ma solution C#: La fonction renvoie l'index zIndex parmi les frères et sœurs du HWND donné, en commençant à 0 pour le zOrder le plus bas.

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