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

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 GetAllAboveWindows(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 }

View Code

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 }

View Code