检查窗口是否有重叠的东西?

时间:2017-08-20 00:19:44

标签: wpf overlap intptr

如何检查窗口是否重叠?

我发现这个WinForms代码可以解决这个问题:

public static bool IsOverlapped(IWin32Window window)
{
    if (window == null)
        throw new ArgumentNullException("window");
    if (window.Handle == IntPtr.Zero)
        throw new InvalidOperationException("Window does not yet exist");
    if (!IsWindowVisible(window.Handle))
        return false;

    IntPtr hWnd = window.Handle;
    HashSet<IntPtr> visited = new HashSet<IntPtr> { hWnd };

    // The set is used to make calling GetWindow in a loop stable by checking if we have already
    //  visited the window returned by GetWindow. This avoids the possibility of an infinate loop.

    RECT thisRect;
    GetWindowRect(hWnd, out thisRect);

    while ((hWnd = GetWindow(hWnd, GW_HWNDPREV)) != IntPtr.Zero && !visited.Contains(hWnd))
    {
        visited.Add(hWnd);
        RECT testRect, intersection;
        if (IsWindowVisible(hWnd) && GetWindowRect(hWnd, out testRect) && IntersectRect(out intersection, ref thisRect, ref testRect))
            return true;
    }

    return false;
}

[DllImport("user32.dll")]
private static extern IntPtr GetWindow(IntPtr hWnd, int uCmd);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetWindowRect(IntPtr hWnd, [Out] out RECT lpRect);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool IntersectRect([Out] out RECT lprcDst, [In] ref RECT lprcSrc1, [In] ref RECT lprcSrc2);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool IsWindowVisible(IntPtr hWnd);

private const int GW_HWNDPREV = 3;

[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
    public int left;
    public int top;
    public int right;
    public int bottom;
}

但我不确定如何让它在WPF上运行,有人可以帮助我吗? 我已经尝试了很多东西..

3 个答案:

答案 0 :(得分:1)

如果要获取给定WPF窗口的句柄,可以使用System.Windows.Interop.WindowInteropHelper类。对IsOverlapped的更新将允许您与WinForms代码进行交互:

public static bool IsOverlapped(Window window)
{
    if (window == null)
        throw new ArgumentNullException("window");

    var hWnd = new WindowInteropHelper(window).Handle;
    if (hWnd == IntPtr.Zero)
        throw new InvalidOperationException("Window does not yet exist");
    if (!IsWindowVisible(hWnd))
        return false;

    HashSet<IntPtr> visited = new HashSet<IntPtr> { hWnd };

    // The set is used to make calling GetWindow in a loop stable by checking if we have already
    //  visited the window returned by GetWindow. This avoids the possibility of an infinate loop.

    RECT thisRect;
    GetWindowRect(hWnd, out thisRect);

    while ((hWnd = GetWindow(hWnd, GW_HWNDPREV)) != IntPtr.Zero && !visited.Contains(hWnd))
    {
        visited.Add(hWnd);
        RECT testRect, intersection;
        if (IsWindowVisible(hWnd) && GetWindowRect(hWnd, out testRect) && IntersectRect(out intersection, ref thisRect, ref testRect))
            return true;
    }

    return false;
}

答案 1 :(得分:1)

我这样解决了:

<div>

答案 2 :(得分:0)

public static bool IsOverlappedElement(FrameworkElement element)
{
    var hwndYourWindow = ((HwndSource)PresentationSource.FromVisual(Window.GetWindow(element))).Handle;
    var controlRect = GetAbsolutePlacement(element);
    var overlappingWindows = GetOverlappingWindowsRectangle(WindowsListFactory.Load(), hwndYourWindow, controlRect).ToList();
    return overlappingWindows.Any();
}

GetOverlappingWindowsRectangle方法输入:

  1. WindowsListFactory.Load()返回所有相关的活动Windows数据 (以下github存储库包含此功能... click here。)

  2. hwndYourWindow 是包含UI元素的窗口。

  3. controlRect 是您的元素路径(用于检测重叠)。

下面的函数将返回(实际)与您的视觉元素(或窗口)重叠的窗口。

    private IEnumerable<WindowEntry> GetOverlappingWindowsRectangle(IEnumerable<WindowEntry> filteredWindows, IntPtr interrupterHwnd, Rect displayedControl)
    {
        const uint GW_HWNDNEXT = 2;

        var byHandle = filteredWindows.ToDictionary(win => win.HWnd);

        for (IntPtr hWnd = GetTopWindow(IntPtr.Zero); hWnd != IntPtr.Zero; hWnd = GetWindow(hWnd, GW_HWNDNEXT))
        {
            if (interrupterHwnd == hWnd) break;

            if (byHandle.ContainsKey(hWnd) == false) continue;

            var result = GetWindowRect(new HandleRef(this, hWnd), out RECT rect);

            if (result == false) continue;

            byHandle[hWnd].Frame = CreateRectangle(rect);

            if (displayedControl.IntersectsWith(byHandle[hWnd].Frame) == false) continue;

            yield return byHandle[hWnd];
        }
    }

//Helper methods:

    private Rect CreateRectangle(RECT rect)
    {
        var rectangle = new Rect();
        rectangle.X = rect.Left;
        rectangle.Y = rect.Top;
        rectangle.Width = rect.Right - rect.Left + 1;
        rectangle.Height = rect.Bottom - rect.Top + 1;

        return rectangle;
    }

    private Rect GetAbsolutePlacement(FrameworkElement element, bool relativeToScreen = false)
    {
        var absolutePos = element.PointToScreen(new System.Windows.Point(0, 0));
        if (relativeToScreen)
        {
            return new Rect(absolutePos.X, absolutePos.Y, element.ActualWidth, element.ActualHeight);
        }
        var posMW = Application.Current.MainWindow.PointToScreen(new System.Windows.Point(0, 0));
        absolutePos = new System.Windows.Point(absolutePos.X - posMW.X, absolutePos.Y - posMW.Y);
        return new Rect(absolutePos.X, absolutePos.Y, element.ActualWidth, element.ActualHeight);
    }

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool GetWindowRect(HandleRef hWnd, out RECT lpRect);

    [DllImport("user32.dll")]
    private static extern IntPtr GetTopWindow(IntPtr hWnd);

    [DllImport("User32")]
    private static extern IntPtr GetWindow(IntPtr hWnd, uint wCmd);