2009-05-05 3 views
18

나는 실행중인 각 응용 프로그램과 상호 작용하는 응용 프로그램을 만들고 있습니다. 지금은 창 z 순서를 얻는 방법이 필요합니다. 예를 들어, 파이어 폭스와 메모장이 돌아가고 있다면, 어느 것이 앞에 있는지 알아야합니다.Windows에서 z-order를 얻는 방법은 무엇입니까?

아이디어가 있으십니까? 각 응용 프로그램의 기본 창에 대해이 작업을 수행하는 것 외에도 자식 및 자매 창 (동일한 프로세스에 속하는 창)을 위해이 작업을 수행해야합니다.

답변

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

니스와 :

더 신뢰성이 필요하면
int GetZOrder(IntPtr hWnd) 
{ 
    var z = 0; 
    for (var h = hWnd; h != IntPtr.Zero; h = GetWindow(h, GW.HWNDPREV)) z++; 
    return z; 
} 

:에주의 섹션에 따르면

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

(루프가 외부 변경에 대한 원 자성이 아니기 때문에 GetWindow, EnumChildWindows은 루프에서 GetWindow을 호출하는 것보다 안전합니다. 부모가 null 호출 EnumChildWindows에 대한 매개 변수 섹션에 따르면 EnumWindows에 해당합니다.) 그리고 대신도 동시 변경에서 원자 및 안전하지 않을 것입니다 각 창에 대한 EnumWindows에 대한 별도의 호출의

, 보내 각 창을 params 배열로 비교하여 z 순서를 모두 동시에 검색 할 수 있습니다.

+1

양식 및 작업 표시 줄과 같이 두 개의 겹쳐진 창을 비교할 때 작동하지 않습니다. 창이 작업 표시 줄 위에있을 때 작업 표시 줄 z 순서는 작업 표시 줄이 위에 있다는 것을 나타내는 창보다 높습니다. – Codebeat

+0

사실, 나는 내 마음을 바꿨다. @Erwinus, [Microsoft에 따르면] (https://msdn.microsoft.com/en-us/library/windows/desktop/ms632599%28v=vs.85%29.aspx#zorder) 최상위 창은 z- order * before * other windows. 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; 
     } 
    } 
}