如何在Windows中获得z顺序?

时间:2009-05-05 15:59:21

标签: c# .net windows z-order

我正在创建一个应用程序,我与每个正在运行的应用程序进行交互。现在,我需要一种获取窗口z顺序的方法。例如,如果Firefox和记事本正在运行,我需要知道哪一个在前面。

有什么想法吗?除了为每个应用程序的主窗口执行此操作外,我还需要为其子窗口和姐妹窗口(属于同一进程的窗口)执行此操作。

5 个答案:

答案 0 :(得分:9)

您可以使用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

答案 1 :(得分:7)

很好,很简洁:

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更安全,因为您的GetWindow循环不是外部更改的原子。 EnumChildWindows的参数部分,使用空父项调用等同于EnumWindows。)

然后,而不是对每个窗口单独调用EnumWindows,这对于并发更改也不是原子的和安全的,你可以在params数组中发送你想要比较的每个窗口,这样它们的z-order就可以了所有都可以同时检索。

答案 2 :(得分: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);

答案 3 :(得分: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;
        }
    }
}

答案 4 :(得分:0)

要获取Z订单,请使用GetWindow Windows API函数来实现此功能

[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd);

static int GetWindowZOrder(IntPtr hWnd)
{
    var zOrder = -1;
    while ((hWnd = GetWindow(hWnd, 2 /* GW_HWNDNEXT */)) != IntPtr.Zero) zOrder++;
    return zOrder;
}

返回值是一个从零开始的索引。返回-1表示无效的hWnd。

方法是从窗户向上到达顶部。攀爬总数就是Z阶的值。