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 }
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 }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 上周热点回顾(2.17-2.23)