2009-05-05 93 views
18

私は、実行中の各アプリケーションと対話するアプリケーションを作成しています。今、ウィンドウのzオーダーを取得する方法が必要です。たとえば、Firefoxとメモ帳が動作している場合は、どちらが正面かを知る必要があります。ウィンドウでzオーダーを取得するには?

アイデア?これを各アプリケーションのメインウィンドウで行う以外にも、子ウィンドウと姉妹ウィンドウ(同じプロセスに属するウィンドウ)で行う必要があります。

答えて

10

GetTopWindow関数を使用して、親ウィンドウのすべての子ウィンドウを検索し、子ウィンドウのハンドルをzオーダーで最も高いものに戻すことができます。 GetNextWindow関数は、次または前のウィンドウへのハンドルを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

"デスクトップ"は親ウィンドウとして使用できます。親にはnullを指定します。したがって、デスクトップ上のトップレベルウィンドウを簡単に取得できます。 –

+0

これは信頼できません。 'GetNextWindow'は単に' GetWindow'を呼び出します。 [GetWindow'リファレンス](https://msdn.microsoft.com/en-us/library/ms633515(v = vs.85).aspx)から: "このタスクを実行するためにGetWindowを呼び出すアプリケーションは、無限ループで、または破棄されたウィンドウへのハンドルを参照します._ – 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

ニースと簡潔:上の特記事項セクションによると

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

(:

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

あなたはより多くの信頼性を必要とする場合ループが外側の変更に対してアトミックではないため、GetWindow,EnumChildWindowsはループでGetWindowを呼び出すよりも安全です。 EnumChildWindowsのパラメータセクションによると、ヌルの親で呼び出すとEnumWindowsと同じです。)

代わりにも同時変更からアトミックと安全ではないことになる各ウィンドウについてEnumWindowsに別のコールの後、あなたが送りますそれぞれのウィンドウをparams配列で比較して、そのz-orderをすべて同時に取得できるようにします。

+1

たとえば、フォームやタスクバーのような2つの重なったウィンドウを比較すると機能しません。ウィンドウがタスクバーの上にあるとき、タスクバーのzオーダーは、タスクバーが上にあることを示唆するウィンドウよりも高くなります。 – Codebeat

+0

実際、私は気が変わった。 @Erwinus、[Microsoftによる](https://msdn.microsoft.com/en-us/library/windows/desktop/ms632599%28v=vs.85%29.aspx#zorder)トップレベルのウィンドウがz- *他のウィンドウの前に* order *を置く。これは、zオーダー番号が小さいほどウィンドウが実際に高いことを意味する。 'EnumWindows'と' GW_HWNDPREV'と 'GW_HWNDNEXT'のやり方は、これをサポートしています。他の答えはここに同意します。このカウンタをWindows APIにするのは嫌です。 – jnm2

+0

@HansPassant、私はこれについてあなたの意見を尊重したいと思います。他の落書きがありますか? – jnm2

0

私のC#ソリューションは次のとおりです。 この関数は、指定されたHWNDの兄弟の中でzIndexを返します。最も低いzOrderは0から始まります。

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; 
     } 
    } 
} 
関連する問題