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 ListGetAllAboveWindows(IntPtr hwnd) 2 { 3 var windowInfos = new List (); 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 ///39 /// 获取 Win32 窗口的一些基本信息。 40 /// 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 /// 53 /// 获取窗口句柄。 54 /// 55 public IntPtr Hwnd { get; } 56 57 /// 58 /// 获取窗口类名。 59 /// 60 public string ClassName { get; } 61 62 /// 63 /// 获取窗口标题。 64 /// 65 public string Title { get; } 66 67 /// 68 /// 获取当前窗口是否可见。 69 /// 70 public bool IsVisible { get; } 71 72 /// 73 /// 获取窗口当前的位置和尺寸。 74 /// 75 public Rect Bounds { get; } 76 77 /// 78 /// 获取窗口当前是否是最小化的。 79 /// 80 public bool IsMinimized => Bounds.Left == -32000 && Bounds.Top == -32000; 81 }
WindowEnumerator测试类:
1 ///2 /// 包含枚举当前用户空间下所有窗口的方法。 3 /// 4 public class WindowEnumerator 5 { 6 /// 7 /// 查找当前用户空间下所有符合条件的窗口(仅查找顶层窗口)。如果不指定条件,将返回所有窗口。 8 /// 9 /// 过滤窗口的条件。 10 /// 找到的所有窗口信息。 11 public static IReadOnlyList FindAll(Predicate match = null) 12 { 13 var windowList = new List (); 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 GetAllAboveWindows(IntPtr hwnd) 54 { 55 var windowInfos = new List (); 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 GetAllBelowWindows(IntPtr hwnd) 67 { 68 var windowInfos = new List (); 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 }