C# 获取指定窗口的上层窗口

 如何获取当前窗口层级上方的所有窗口信息

User32有函数GetWindow function (winuser.h) - Win32 apps | Microsoft Docs,可以根据已知窗口句柄,获取指定类型的窗口。

1     [DllImport("user32.dll", SetLastError = true)]
2     public static extern IntPtr GetWindow(IntPtr hwnd, uint windowType);

这里我们获取上层窗口:GW_HWNDPREV = 3

 1     public static List<WindowInfo> GetAllAboveWindows(IntPtr hwnd)
 2     {
 3         var windowInfos = new List<WindowInfo>();
 4         var intPtr = User32.GetWindow(hwnd, 3);
 5         if (intPtr == IntPtr.Zero)
 6         {
 7             return windowInfos;
 8         }
 9         var windowDetail = GetWindowDetail(intPtr);
10         windowInfos.AddRange(GetAllAboveWindows(intPtr));
11         windowInfos.Add(windowDetail);
12         return windowInfos;
13     }

获取所有窗口,输出到测试窗口

 1     private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
 2     {
 3         var currentIntPtr = new WindowInteropHelper(this).Handle;
 4         var windows = WindowEnumerator.GetAllAboveWindows(new IntPtr(131450));
 5         var windowInfos = windows.Where(I => I.IsVisible && !I.IsMinimized && I.Bounds.Width > 1 && I.Bounds.Height > 1
 6                                         && I.Hwnd!= currentIntPtr).ToList();
 7         foreach (var windowInfo in windowInfos)
 8         {
 9             WindowsTextBlock.Text +=
10                 $"Hwnd:{windowInfo.Hwnd},Title:{windowInfo.Title},IsMinimized:{windowInfo.IsMinimized},IsVisible:{windowInfo.IsVisible},ClassName:{windowInfo.ClassName},Bounds:{windowInfo.Bounds}\r\n";
11         }
12     }

输出所有窗口信息如下 :

由输出信息,可以了解到,任务栏是在所有非置顶窗口的最上方的。

所以我们要除去任务栏:

1     var windowInfos = windows.Where(I => I.IsVisible && !I.IsMinimized && I.Bounds.Width > 1 && I.Bounds.Height > 1
2                                     && I.Hwnd!= currentIntPtr
3                                     &&!(I.ClassName.StartsWith("Shell_") && I.ClassName.EndsWith("TrayWnd"))).ToList();

 

 User32相关函数:

 1     public static class User32
 2     {
 3         [DllImport("user32.dll", SetLastError = true)]
 4         public static extern IntPtr GetWindow(IntPtr hwnd, uint windowType);
 5 
 6         public delegate bool WndEnumProc(IntPtr hWnd, int lParam);
 7         [DllImport("user32")]
 8         public static extern bool EnumWindows(WndEnumProc lpEnumFunc, int lParam);
 9 
10         [DllImport("user32")]
11         public static extern IntPtr GetParent(IntPtr hWnd);
12 
13         [DllImport("user32")]
14         public static extern bool IsWindowVisible(IntPtr hWnd);
15 
16         [DllImport("user32")]
17         public static extern int GetWindowText(IntPtr hWnd, StringBuilder lptrString, int nMaxCount);
18 
19         [DllImport("user32")]
20         public static extern int GetClassName(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
21 
22         [DllImport("user32")]
23         public static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab);
24 
25         [DllImport("user32")]
26         public static extern bool GetWindowRect(IntPtr hWnd, ref LPRECT rect);
27 
28 
29         [StructLayout(LayoutKind.Sequential)]
30         public readonly struct LPRECT
31         {
32             public readonly int Left;
33             public readonly int Top;
34             public readonly int Right;
35             public readonly int Bottom;
36         }
37     }
38     /// <summary>
39     /// 获取 Win32 窗口的一些基本信息。
40     /// </summary>
41     public readonly struct WindowInfo
42     {
43         public WindowInfo(IntPtr hWnd, string className, string title, bool isVisible, Rect bounds) : this()
44         {
45             Hwnd = hWnd;
46             ClassName = className;
47             Title = title;
48             IsVisible = isVisible;
49             Bounds = bounds;
50         }
51 
52         /// <summary>
53         /// 获取窗口句柄。
54         /// </summary>
55         public IntPtr Hwnd { get; }
56 
57         /// <summary>
58         /// 获取窗口类名。
59         /// </summary>
60         public string ClassName { get; }
61 
62         /// <summary>
63         /// 获取窗口标题。
64         /// </summary>
65         public string Title { get; }
66 
67         /// <summary>
68         /// 获取当前窗口是否可见。
69         /// </summary>
70         public bool IsVisible { get; }
71 
72         /// <summary>
73         /// 获取窗口当前的位置和尺寸。
74         /// </summary>
75         public Rect Bounds { get; }
76 
77         /// <summary>
78         /// 获取窗口当前是否是最小化的。
79         /// </summary>
80         public bool IsMinimized => Bounds.Left == -32000 && Bounds.Top == -32000;
81     }
View Code

 WindowEnumerator测试类:

 1     /// <summary>
 2     /// 包含枚举当前用户空间下所有窗口的方法。
 3     /// </summary>
 4     public class WindowEnumerator
 5     {
 6         /// <summary>
 7         /// 查找当前用户空间下所有符合条件的窗口(仅查找顶层窗口)。如果不指定条件,将返回所有窗口。
 8         /// </summary>
 9         /// <param name="match">过滤窗口的条件。</param>
10         /// <returns>找到的所有窗口信息。</returns>
11         public static IReadOnlyList<WindowInfo> FindAll(Predicate<WindowInfo> match = null)
12         {
13             var windowList = new List<WindowInfo>();
14             User32.EnumWindows(OnWindowEnum, 0);
15             return match == null ? windowList : windowList.FindAll(match);
16 
17             bool OnWindowEnum(IntPtr hWnd, int lparam)
18             {
19                 // 仅查找顶层窗口。
20                 if (User32.GetParent(hWnd) == IntPtr.Zero)
21                 {
22                     var windowDetail = GetWindowDetail(hWnd);
23                     // 添加到已找到的窗口列表。
24                     windowList.Add(windowDetail);
25                 }
26 
27                 return true;
28             }
29         }
30 
31         private static WindowInfo GetWindowDetail(IntPtr hWnd)
32         {
33             // 获取窗口类名。
34             var lpString = new StringBuilder(512);
35             User32.GetClassName(hWnd, lpString, lpString.Capacity);
36             var className = lpString.ToString();
37 
38             // 获取窗口标题。
39             var lptrString = new StringBuilder(512);
40             User32.GetWindowText(hWnd, lptrString, lptrString.Capacity);
41             var title = lptrString.ToString().Trim();
42 
43             // 获取窗口可见性。
44             var isVisible = User32.IsWindowVisible(hWnd);
45 
46             // 获取窗口位置和尺寸。
47             User32.LPRECT rect = default;
48             User32.GetWindowRect(hWnd, ref rect);
49             var bounds = new Rect(rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top);
50 
51             return new WindowInfo(hWnd, className, title, isVisible, bounds);
52         }
53         public static List<WindowInfo> GetAllAboveWindows(IntPtr hwnd)
54         {
55             var windowInfos = new List<WindowInfo>();
56             var intPtr = User32.GetWindow(hwnd, 3);
57             if (intPtr == IntPtr.Zero)
58             {
59                 return windowInfos;
60             }
61             var windowDetail = GetWindowDetail(intPtr);
62             windowInfos.AddRange(GetAllAboveWindows(intPtr));
63             windowInfos.Add(windowDetail);
64             return windowInfos;
65         }
66         public static List<WindowInfo> GetAllBelowWindows(IntPtr hwnd)
67         {
68             var windowInfos = new List<WindowInfo>();
69             var intPtr = User32.GetWindow(hwnd, 2);
70             if (intPtr == IntPtr.Zero)
71             {
72                 return windowInfos;
73             }
74             var windowDetail = GetWindowDetail(intPtr);
75             windowInfos.AddRange(GetAllBelowWindows(intPtr));
76             windowInfos.Add(windowDetail);
77             return windowInfos;
78         }
79     }
View Code

 

posted @ 2022-03-15 20:14  唐宋元明清2188  阅读(1058)  评论(1编辑  收藏  举报