WndHelper.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Drawing;
  4. using System.Linq;
  5. using System.Runtime.InteropServices;
  6. using System.Text;
  7. using System.Threading;
  8. using System.Threading.Tasks;
  9. namespace PTMedicalInsurance.Common.WinAPI
  10. {
  11. class WndHelper
  12. {
  13. // <summary>
  14. /// 枚举窗口时的委托参数
  15. /// </summary>
  16. /// <param name="hWnd"></param>
  17. /// <param name="lParam"></param>
  18. /// <returns></returns>
  19. public delegate bool WndEnumProc(IntPtr hWnd, int lParam);
  20. /// <summary>
  21. /// 枚举所有窗口
  22. /// </summary>
  23. /// <param name="lpEnumFunc"></param>
  24. /// <param name="lParam"></param>
  25. /// <returns></returns>
  26. [DllImport("user32")]
  27. public static extern bool EnumWindows(WndEnumProc lpEnumFunc, int lParam);
  28. /// <summary>
  29. /// 获取窗口的父窗口句柄
  30. /// </summary>
  31. /// <param name="hWnd"></param>
  32. /// <returns></returns>
  33. [DllImport("user32")]
  34. public static extern IntPtr GetParent(IntPtr hWnd);
  35. [DllImport("user32")]
  36. public static extern int GetClassName(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
  37. [DllImport("user32")]
  38. public static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab);
  39. [DllImport("user32")]
  40. public static extern bool GetWindowRect(IntPtr hWnd, ref LPRECT rect);
  41. [DllImport("user32.dll")]
  42. public static extern IntPtr SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, uint wFlags);
  43. [StructLayout(LayoutKind.Sequential)]
  44. public readonly struct LPRECT
  45. {
  46. public readonly int Left;
  47. public readonly int Top;
  48. public readonly int Right;
  49. public readonly int Bottom;
  50. }
  51. public const int HWND_TOP = 0;
  52. public const int HWND_BOTTOM = 1;
  53. public const int HWND_TOPMOST = -1;
  54. public const int HWND_NOTOPMOST = -2;
  55. /// <summary>
  56.   /// 设置窗体为TopMost
  57.   /// </summary>
  58.   /// <param name="hWnd"></param>
  59. public static void SetTopomost(IntPtr hWnd)
  60. {
  61. LPRECT rect = new LPRECT();
  62. GetWindowRect(hWnd, ref rect);
  63. SetWindowPos(hWnd, (IntPtr)HWND_TOPMOST, rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top, 0);
  64. }
  65. [DllImport("user32.dll")]
  66. [return: MarshalAs(UnmanagedType.Bool)]
  67. public static extern bool SetForegroundWindow(IntPtr hWnd);
  68. [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
  69. public static extern IntPtr GetForegroundWindow();
  70. /// <summary>
  71. /// 判断是否窗体
  72. /// </summary>
  73. /// <param name="hWnd"></param>
  74. /// <returns></returns>
  75. [DllImport("user32.dll", SetLastError = true)]
  76. public static extern bool IsWindow(IntPtr hWnd);
  77. /// <summary>
  78. /// 当前窗口是否最小化
  79. /// </summary>
  80. /// <param name="hWnd"></param>
  81. /// <returns></returns>
  82. [DllImport("user32.dll")]
  83. [return: MarshalAs(UnmanagedType.Bool)]
  84. public static extern bool IsIconic(IntPtr hWnd);
  85. /// <summary>
  86. /// 当前窗口是否最大化
  87. /// </summary>
  88. /// <param name="hWnd"></param>
  89. /// <returns></returns>
  90. [DllImport("user32.dll")]
  91. public static extern bool IsZoomed(IntPtr hWnd);
  92. /// <summary>
  93. /// 判断窗口是否可见
  94. /// </summary>
  95. /// <param name="hWnd"></param>
  96. /// <returns></returns>
  97. [DllImport("user32")]
  98. public static extern bool IsWindowVisible(IntPtr hWnd);
  99. [DllImport("user32.dll")]
  100. public static extern int ShowWindow(IntPtr hwnd, int nCmdShow);
  101. // 获取窗口文本长度
  102. /// <summary>
  103. /// 获取目标窗口标题的文本长度
  104. /// </summary>
  105. /// <param name="hWnd">目标窗口句柄</param>
  106. /// <returns>标题文本长度</returns>
  107. [DllImport("user32.dll")]
  108. public static extern int GetWindowTextLength(IntPtr hWnd);
  109. /// <summary>
  110. /// 获取窗口文本,文本会塞入StringBuilder中,需要指明字符串最大长度nMaxCount
  111. /// </summary>
  112. /// <param name="hwnd">窗口句柄</param>
  113. /// <param name="lpString">返回目标窗口的内容</param>
  114. /// <param name="nMaxCount">允许返回的字符数量上限</param>
  115. /// <returns>实际获取到的文本长度</returns>
  116. [DllImport("User32.dll", EntryPoint = "GetWindowText")]
  117. public static extern int GetWindowText(IntPtr hwnd, StringBuilder lpString, int nMaxCount);
  118. [DllImport("User32.dll", CharSet = CharSet.Auto)]
  119. public static extern int GetWindowThreadProcessId(IntPtr hwnd, out int ID);
  120. /// <summary>
  121. /// 获取 Win32 窗口的一些基本信息。
  122. /// </summary>
  123. public struct WindowInfo
  124. {
  125. public WindowInfo(IntPtr hWnd, string className, string title, bool isVisible, Rectangle bounds) : this()
  126. {
  127. Hwnd = hWnd;
  128. ClassName = className;
  129. Title = title;
  130. IsVisible = isVisible;
  131. Bounds = bounds;
  132. }
  133. /// <summary>
  134. /// 获取窗口句柄。
  135. /// </summary>
  136. public IntPtr Hwnd { get; }
  137. /// <summary>
  138. /// 获取窗口类名。
  139. /// </summary>
  140. public string ClassName { get; }
  141. /// <summary>
  142. /// 获取窗口标题。
  143. /// </summary>
  144. public string Title { get; }
  145. /// <summary>
  146. /// 获取当前窗口是否可见。
  147. /// </summary>
  148. public bool IsVisible { get; }
  149. /// <summary>
  150. /// 获取窗口当前的位置和尺寸。
  151. /// </summary>
  152. public Rectangle Bounds { get; }
  153. /// <summary>
  154. /// 获取窗口当前是否是最小化的。
  155. /// </summary>
  156. public bool IsMinimized => Bounds.Left == -32000 && Bounds.Top == -32000;
  157. }
  158. public struct wndInfo
  159. {
  160. public IntPtr hWnd;
  161. public string szWindowName;
  162. public string szClassName;
  163. }
  164. [DllImport("user32.dll")]
  165. private static extern int GetWindowTextW(IntPtr hWnd, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder lpString, int nMaxCount);
  166. [DllImport("user32.dll")]
  167. private static extern int GetClassNameW(IntPtr hWnd, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder lpString, int nMaxCount);
  168. public static wndInfo[] GetAllDesktopWindows()
  169. {
  170. List<wndInfo> wndList = new List<wndInfo>();
  171. // 使用委托实现窗口枚举逻辑
  172. EnumWindows(delegate (IntPtr hWnd, int lParam)
  173. {
  174. wndInfo wnd = new wndInfo();
  175. StringBuilder sb = new StringBuilder(256);
  176. // 获取窗口句柄
  177. wnd.hWnd = hWnd;
  178. // 获取窗口名称
  179. GetWindowTextW(hWnd, sb, sb.Capacity);
  180. wnd.szWindowName = sb.ToString();
  181. // 获取窗口类名
  182. GetClassNameW(hWnd, sb, sb.Capacity);
  183. wnd.szClassName = sb.ToString();
  184. // 添加到列表中
  185. wndList.Add(wnd);
  186. return true;
  187. }, 0);
  188. return wndList.ToArray();
  189. }
  190. /// <summary>
  191. /// 查找当前用户空间下所有符合条件的(顶层)窗口。如果不指定条件,将仅查找可见且有标题栏的窗口。
  192. /// </summary>
  193. /// <param name="match">过滤窗口的条件。如果设置为 null,将仅查找可见和标题栏不为空的窗口。</param>
  194. /// <returns>找到的所有窗口信息</returns>
  195. public static IReadOnlyList<WindowInfo> FindAllWindows(Predicate<WindowInfo> match = null)
  196. {
  197. windowList = new List<WindowInfo>();
  198. //遍历窗口并查找窗口相关WindowInfo信息
  199. EnumWindows(OnWindowEnum, 0);
  200. return windowList.FindAll(match ?? DefaultPredicate);
  201. }
  202. /// <summary>
  203. /// 遍历窗体处理的函数
  204. /// </summary>
  205. /// <param name="hWnd"></param>
  206. /// <param name="lparam"></param>
  207. /// <returns></returns>
  208. public static bool OnWindowEnum(IntPtr hWnd, int lparam)
  209. {
  210. // 仅查找顶层窗口。
  211. if (GetParent(hWnd) == IntPtr.Zero)
  212. {
  213. // 获取窗口类名。
  214. var lpString = new StringBuilder(512);
  215. GetClassName(hWnd, lpString, lpString.Capacity);
  216. var className = lpString.ToString();
  217. // 获取窗口标题。
  218. var lptrString = new StringBuilder(512);
  219. GetWindowText(hWnd, lptrString, lptrString.Capacity);
  220. var title = lptrString.ToString().Trim();
  221. // 获取窗口可见性。
  222. var isVisible = IsWindowVisible(hWnd);
  223. // 获取窗口位置和尺寸。
  224. LPRECT rect = default;
  225. GetWindowRect(hWnd, ref rect);
  226. var bounds = new Rectangle(rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top);
  227. // 添加到已找到的窗口列表。
  228. windowList.Add(new WindowInfo(hWnd, className, title, isVisible, bounds));
  229. }
  230. return true;
  231. }
  232. /// <summary>
  233. /// 默认的查找窗口的过滤条件。可见 + 非最小化 + 包含窗口标题。
  234. /// </summary>
  235. public static readonly Predicate<WindowInfo> DefaultPredicate = x => x.IsVisible && !x.IsMinimized && x.Title.Length > 0;
  236. /// <summary>
  237. /// 窗体列表
  238. /// </summary>
  239. public static List<WindowInfo> windowList;
  240. /// <summary>
  241. /// 遍历子窗体(控件)
  242. /// </summary>
  243. /// <param name="hwndParent">父窗口句柄</param>
  244. /// <param name="lpEnumFunc">遍历的回调函数</param>
  245. /// <param name="lParam">传给遍历时回调函数的额外数据</param>
  246. /// <returns></returns>
  247. [DllImport("user32.dll")]
  248. [return: MarshalAs(UnmanagedType.Bool)]
  249. public static extern bool EnumChildWindows(IntPtr hwndParent, WndEnumProc lpEnumFunc, int lParam);
  250. /// <summary>
  251. /// 查找窗体
  252. /// </summary>
  253. /// <param name="lpClassName">窗体的类名称,比如Form、Window。若不知道,指定为null即可</param>
  254. /// <param name="lpWindowName">窗体的标题/文字</param>
  255. /// <returns></returns>
  256. [DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
  257. public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
  258. /// <summary>
  259. /// 查找子窗体(控件)
  260. /// </summary>
  261. /// <param name="hwndParent">父窗体句柄,不知道窗体时可指定IntPtr.Zero</param>
  262. /// <param name="hwndChildAfter">子窗体(控件),通常不知道子窗体(句柄),指定0即可</param>
  263. /// <param name="lpszClass">子窗体(控件)的类名,通常指定null,它是window class name,并不等同于C#中的列名Button、Image、PictureBox等,两者并不相同,可通过GetClassName获取正确的类型名</param>
  264. /// <param name="lpszWindow">子窗体的名字或控件的Title、Text,通常为显示的文字</param>
  265. /// <returns></returns>
  266. [DllImport("user32.dll", EntryPoint = "FindWindowEx", SetLastError = true)]
  267. public static extern IntPtr FindWindowEx(IntPtr hwndParent, uint hwndChildAfter, string lpszClass, string lpszWindow);
  268. //消息发送API
  269. [DllImport("user32.dll", EntryPoint = "PostMessage")]
  270. public static extern bool PostMessage(IntPtr hWnd, int Msg, uint wParam, uint lParam);
  271. [DllImport("user32.dll", CharSet = CharSet.Auto)]
  272. static extern IntPtr SendMessage(IntPtr hWnd, int Msg, uint wParam, uint lParam);
  273. [DllImport("user32.dll")] private static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, uint dwExtraInfo);
  274. private const int KEYEVENTF_EXTENDEDKEY = 0x1;
  275. private const int KEYEVENTF_KEYUP = 0x2;
  276. const uint WM_KEYDOWN = 0x100;
  277. const uint WM_KEYUP = 0x101;
  278. const uint WM_SYSKEYDOWN = 0x104;
  279. const uint WM_SYSKEYUP = 0x105;
  280. const int VK_CONTROL = 0x11; // Ctrl键
  281. const int VK_A = 0x41; // A键
  282. const int VK_R = 0x52;
  283. const int VK_P = 0x50;
  284. const int VK_S = 0x53;
  285. const int VK_F = 0x46;
  286. const int VK_C = 0x43;
  287. public enum msgType
  288. {
  289. send = 0,
  290. post =1,
  291. keybd_event =2
  292. }
  293. public static void SendMsg(msgType mType,IntPtr hWnd,int key)
  294. {
  295. //SetTopomost(hWnd);
  296. SetForegroundWindow(hWnd);
  297. switch (mType)
  298. {
  299. case msgType.send:
  300. {
  301. Thread.Sleep(2000);
  302. SendMessage(hWnd, 0X100, (uint)key, 0);//
  303. SendMessage(hWnd, 0X101, (uint)key, 0);//
  304. break;
  305. }
  306. case msgType.post:
  307. {
  308. PostMessage(hWnd, 0X100, (uint)key, 0);//
  309. PostMessage(hWnd, 0X101, (uint)key, 0);//
  310. break;
  311. }
  312. case msgType.keybd_event:
  313. {
  314. keybd_event(Convert.ToByte(key), 0, 0, 0);
  315. keybd_event(Convert.ToByte(key), 0, KEYEVENTF_KEYUP, 0);
  316. break;
  317. }
  318. default:
  319. {
  320. SendMessage(hWnd, 0X100, (uint)key, 0);//
  321. SendMessage(hWnd, 0X101, (uint)key, 0);//
  322. break;
  323. }
  324. }
  325. //Lparam的解释壳参考
  326. //https://blog.csdn.net/deniece1/article/details/103588428 扫描码
  327. //https://blog.csdn.net/yizhe0731/article/details/103194401
  328. }
  329. }
  330. }