WindowUtil.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Drawing;
  5. using System.Linq;
  6. using System.Runtime.InteropServices;
  7. using System.Text;
  8. using System.Threading.Tasks;
  9. using System.Windows;
  10. using System.Windows.Controls;
  11. using System.Windows.Forms;
  12. using System.Windows.Interop;
  13. using static GeekDesk.Util.FileIcon;
  14. namespace GeekDesk.Util
  15. {
  16. public class WindowUtil
  17. {
  18. public enum GetWindowCmd : uint
  19. {
  20. GW_HWNDFIRST = 0,
  21. GW_HWNDLAST = 1,
  22. GW_HWNDNEXT = 2,
  23. GW_HWNDPREV = 3,
  24. GW_OWNER = 4,
  25. GW_CHILD = 5,
  26. GW_ENABLEDPOPUP = 6
  27. }
  28. [Flags]
  29. public enum SetWindowPosFlags
  30. {
  31. SWP_NOSIZE = 0x0001,
  32. SWP_NOMOVE = 0x0002,
  33. SWP_NOZORDER = 0x0004,
  34. SWP_NOREDRAW = 0x0008,
  35. SWP_NOACTIVATE = 0x0010,
  36. SWP_FRAMECHANGED = 0x0020,
  37. SWP_SHOWWINDOW = 0x0040,
  38. SWP_HIDEWINDOW = 0x0080,
  39. SWP_NOCOPYBITS = 0x0100,
  40. SWP_NOOWNERZORDER = 0x0200,
  41. SWP_NOSENDCHANGING = 0x0400
  42. }
  43. [DllImport("user32.dll")]
  44. public static extern IntPtr WindowFromPoint(System.Drawing.Point p);
  45. //取得前台窗口句柄函数
  46. [DllImport("user32.dll")]
  47. public static extern IntPtr GetForegroundWindow();
  48. //取得桌面窗口句柄函数
  49. [DllImport("user32.dll")]
  50. public static extern IntPtr GetDesktopWindow();
  51. [DllImport("user32.dll", CharSet = CharSet.Auto)]
  52. public static extern IntPtr FindWindow(string className, string windowName);
  53. [DllImport("user32.dll")]
  54. public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string className, string windowName);
  55. [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
  56. public static extern IntPtr GetWindow(HandleRef hWnd, int nCmd);
  57. [DllImport("user32.dll")]
  58. public static extern IntPtr SetParent(IntPtr child, IntPtr parent);
  59. [DllImport("user32.dll", EntryPoint = "GetDCEx", CharSet = CharSet.Auto, ExactSpelling = true)]
  60. public static extern IntPtr GetDCEx(IntPtr hWnd, IntPtr hrgnClip, int flags);
  61. [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
  62. public static extern bool SetWindowPos(HandleRef hWnd, HandleRef hWndInsertAfter, int x, int y, int cx, int cy, int flags);
  63. [DllImport("user32.dll")]
  64. public static extern int ReleaseDC(IntPtr window, IntPtr handle);
  65. [DllImport("user32.dll")]
  66. public static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
  67. [DllImport("user32.dll")]
  68. public static extern int GetWindowLong(IntPtr hWnd, int nIndex);
  69. [DllImport("user32.dll")]
  70. public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
  71. [DllImport("User32.dll", CharSet = CharSet.Auto)]
  72. public static extern int GetWindowThreadProcessId(IntPtr hwnd, out int ID); //获取线程ID
  73. /// <summary>
  74. /// 枚举窗口时的委托参数
  75. /// </summary>
  76. /// <param name="hWnd"></param>
  77. /// <param name="lParam"></param>
  78. /// <returns></returns>
  79. public delegate bool WndEnumProc(IntPtr hWnd, int lParam);
  80. /// <summary>
  81. /// 枚举所有窗口
  82. /// </summary>
  83. /// <param name="lpEnumFunc"></param>
  84. /// <param name="lParam"></param>
  85. /// <returns></returns>
  86. [DllImport("user32.dll")]
  87. public static extern bool EnumWindows(WndEnumProc lpEnumFunc, int lParam);
  88. /// <summary>
  89. /// 获取窗口的父窗口句柄
  90. /// </summary>
  91. /// <param name="hWnd"></param>
  92. /// <returns></returns>
  93. [DllImport("user32.dll")]
  94. public static extern IntPtr GetParent(IntPtr hWnd);
  95. [DllImport("user32.dll")]
  96. public static extern bool IsWindowVisible(IntPtr hWnd);
  97. [DllImport("user32.dll")]
  98. public static extern int GetClassName(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
  99. [DllImport("user32.dll")]
  100. public static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab);
  101. [DllImport("user32.dll")]
  102. public static extern bool GetWindowRect(IntPtr hWnd, ref LPRECT rect);
  103. // Import GetDC and ReleaseDC functions from user32.dll
  104. [DllImport("user32.dll")]
  105. public static extern IntPtr GetDC(IntPtr hWnd);
  106. [DllImport("gdi32.dll")]
  107. public static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
  108. [StructLayout(LayoutKind.Sequential)]
  109. public readonly struct LPRECT
  110. {
  111. public readonly int Left;
  112. public readonly int Top;
  113. public readonly int Right;
  114. public readonly int Bottom;
  115. }
  116. private const int GWL_STYLE = -16;
  117. private const int WS_MAXIMIZEBOX = 0x10000;
  118. public static void DisableMaxWindow(Window window)
  119. {
  120. var hwnd = new WindowInteropHelper(window).Handle;
  121. var value = GetWindowLong(hwnd, GWL_STYLE);
  122. SetWindowLong(hwnd, GWL_STYLE, (int)(value & ~WS_MAXIMIZEBOX));
  123. }
  124. /// <summary>
  125. /// 获取 Win32 窗口的一些基本信息。
  126. /// </summary>
  127. public struct WindowInfo
  128. {
  129. public WindowInfo(IntPtr hWnd, string className, string title, bool isVisible, Rectangle bounds) : this()
  130. {
  131. Hwnd = hWnd;
  132. ClassName = className;
  133. Title = title;
  134. IsVisible = isVisible;
  135. Bounds = bounds;
  136. }
  137. /// <summary>
  138. /// 获取窗口句柄。
  139. /// </summary>
  140. public IntPtr Hwnd { get; }
  141. /// <summary>
  142. /// 获取窗口类名。
  143. /// </summary>
  144. public string ClassName { get; }
  145. /// <summary>
  146. /// 获取窗口标题。
  147. /// </summary>
  148. public string Title { get; }
  149. /// <summary>
  150. /// 获取当前窗口是否可见。
  151. /// </summary>
  152. public bool IsVisible { get; }
  153. /// <summary>
  154. /// 获取窗口当前的位置和尺寸。
  155. /// </summary>
  156. public Rectangle Bounds { get; }
  157. /// <summary>
  158. /// 获取窗口当前是否是最小化的。
  159. /// </summary>
  160. public bool IsMinimized => Bounds.Left == -32000 && Bounds.Top == -32000;
  161. }
  162. /// <summary>
  163. /// 遍历窗体处理的函数
  164. /// </summary>
  165. /// <param name="hWnd"></param>
  166. /// <param name="lparam"></param>
  167. /// <returns></returns>
  168. private static bool OnWindowEnum(IntPtr hWnd, int lparam)
  169. {
  170. // 仅查找顶层窗口。
  171. //if (GetParent(hWnd) == IntPtr.Zero)
  172. //{
  173. // 获取窗口类名。
  174. var lpString = new StringBuilder(512);
  175. GetClassName(hWnd, lpString, lpString.Capacity);
  176. var className = lpString.ToString();
  177. // 获取窗口标题。
  178. var lptrString = new StringBuilder(512);
  179. GetWindowText(hWnd, lptrString, lptrString.Capacity);
  180. var title = lptrString.ToString().Trim();
  181. // 获取窗口可见性。
  182. var isVisible = IsWindowVisible(hWnd);
  183. // 获取窗口位置和尺寸。
  184. LPRECT rect = default;
  185. GetWindowRect(hWnd, ref rect);
  186. var bounds = new Rectangle(rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top);
  187. // 添加到已找到的窗口列表。
  188. windowList.Add(new WindowInfo(hWnd, className, title, isVisible, bounds));
  189. //}
  190. return true;
  191. }
  192. /// <summary>
  193. /// 默认的查找窗口的过滤条件。可见 + 非最小化 + 包含窗口标题。
  194. /// </summary>
  195. private static readonly Predicate<WindowInfo> DefaultPredicate = x => x.IsVisible && !x.IsMinimized && x.Title.Length > 0;
  196. /// <summary>
  197. /// 窗体列表
  198. /// </summary>
  199. private static List<WindowInfo> windowList;
  200. /// <summary>
  201. /// 查找当前用户空间下所有符合条件的(顶层)窗口。如果不指定条件,将仅查找可见且有标题栏的窗口。
  202. /// </summary>
  203. /// <param name="match">过滤窗口的条件。如果设置为 null,将仅查找可见和标题栏不为空的窗口。</param>
  204. /// <returns>找到的所有窗口信息</returns>
  205. public static IReadOnlyList<WindowInfo> FindAllWindows(Predicate<WindowInfo> match = null)
  206. {
  207. windowList = new List<WindowInfo>();
  208. //遍历窗口并查找窗口相关WindowInfo信息
  209. EnumWindows(OnWindowEnum, 0);
  210. return windowList;
  211. }
  212. public static void SetOwner(Window window, Window parentWindow)
  213. {
  214. SetOwner(window, new WindowInteropHelper(parentWindow).Handle);
  215. }
  216. public static void SetOwner(Window window, IntPtr parentHandle)
  217. {
  218. WindowInteropHelper helper = new WindowInteropHelper(window);
  219. helper.Owner = parentHandle;
  220. }
  221. /// <summary>
  222. ///
  223. /// </summary>
  224. /// <param name="window"></param>
  225. /// <returns></returns>
  226. public static bool WindowIsTop(Window window)
  227. {
  228. IntPtr handle = new WindowInteropHelper(window).Handle;
  229. IntPtr deskHandle = GetDesktopHandle(window, DesktopLayer.Progman);
  230. IntPtr topHandle = GetForegroundWindow();
  231. //暂时不能正确获取桌面handle 但发现焦点在桌面时 window title为空
  232. string windowTitle = GetWindowTitle(topHandle);
  233. return topHandle.Equals(handle) || topHandle.Equals(deskHandle) || string.IsNullOrEmpty(windowTitle);
  234. }
  235. private static string GetWindowTitle(IntPtr handle)
  236. {
  237. const int nChars = 256;
  238. StringBuilder Buff = new StringBuilder(nChars);
  239. if (GetWindowText(handle, Buff, nChars) > 0)
  240. {
  241. return Buff.ToString();
  242. }
  243. return null;
  244. }
  245. public const int GW_CHILD = 5;
  246. public static IntPtr GetDesktopHandle(Window window, DesktopLayer layer)
  247. {
  248. HandleRef hWnd;
  249. IntPtr hDesktop = new IntPtr();
  250. switch (layer)
  251. {
  252. case DesktopLayer.Progman:
  253. hDesktop = FindWindow("Progman", null);//第一层桌面
  254. break;
  255. case DesktopLayer.SHELLDLL:
  256. hDesktop = FindWindow("Progman", null);//第一层桌面
  257. hWnd = new HandleRef(window, hDesktop);
  258. hDesktop = GetWindow(hWnd, GW_CHILD);//第2层桌面
  259. break;
  260. case DesktopLayer.FolderView:
  261. hDesktop = FindWindow("Progman", null);//第一层桌面
  262. hWnd = new HandleRef(window, hDesktop);
  263. hDesktop = GetWindow(hWnd, GW_CHILD);//第2层桌面
  264. hWnd = new HandleRef(window, hDesktop);
  265. hDesktop = GetWindow(hWnd, GW_CHILD);//第3层桌面
  266. hWnd = new HandleRef(window, hDesktop);
  267. hDesktop = GetWindow(hWnd, GW_CHILD);//第4层桌面
  268. break;
  269. }
  270. return hDesktop;
  271. }
  272. }
  273. public enum DesktopLayer
  274. {
  275. Progman = 0,
  276. SHELLDLL = 1,
  277. FolderView = 2
  278. }
  279. }