[C#] 使用Win32 API嵌入窗口,键盘、鼠标光标不响应问题解决
/// <summary> /// 根据类名和窗口名称查找窗口 /// </summary> /// <param name="lpClassName"></param> /// <param name="lpWindowName"></param> /// <returns></returns> [DllImport("user32.dll", EntryPoint = "FindWindow")] public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); /// <summary> /// 更改指定子窗口的父窗口 /// </summary> /// <param name="hWndChild">子窗口句柄</param> /// <param name="hWndNewParent">父窗口句柄</param> /// <returns></returns> [DllImport("user32.dll", EntryPoint = "SetParent")] public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent); /// <summary> /// 更改子,弹出窗口或顶级窗口的大小,位置和z顺序。 /// </summary> /// <param name="hWnd">窗口句柄</param> /// <param name="hWndInsertAfter"></param> /// <param name="x"></param> /// <param name="y"></param> /// <param name="cx"></param> /// <param name="cy"></param> /// <param name="uFlags"></param> /// <returns></returns> [DllImport("user32.dll", EntryPoint = "SetWindowPos")] public static extern Boolean SetWindowPos(IntPtr hWnd, Int32 hWndInsertAfter, Int32 x, Int32 y, Int32 cx, Int32 cy, UInt32 uFlags); /// <summary> /// 检索有关指定窗口的信息 /// </summary> /// <param name="hWndChild"></param> /// <param name="nIndex"></param> /// <returns></returns> [DllImport("user32.dll", EntryPoint = "GetWindowLong")] public static extern IntPtr GetWindowLong(IntPtr hWndChild, Int32 nIndex); /// <summary> /// 更改指定窗口的属性 /// </summary> /// <param name="hWndChild"></param> /// <param name="nIndex"></param> /// <returns></returns> [DllImport("user32.dll", EntryPoint = "SetWindowLong")] public static extern IntPtr SetWindowLong(IntPtr hWndChild, Int32 nIndex, IntPtr dwNewLong); /// <summary> /// 从窗口句柄中检索进程句柄 /// </summary> /// <param name="hWnd">窗口句柄</param> /// <returns></returns> [DllImport("User32.dll", EntryPoint = "GetWindowThreadProcessId")] public static extern UInt32 GetWindowThreadProcessId(IntPtr hWnd, out UInt32 processId);/// <summary> /// 确定指定窗口的可见性状态 /// </summary> /// <param name="hWnd"></param> /// <returns></returns> [DllImport("User32.dll", EntryPoint = "IsWindowVisible")] public static extern Boolean IsWindowVisible(IntPtr hWnd);
SetParent函数不能更改窗口样式,而嵌入窗口需要给窗口添加WS_CHILD样式,并移除WS_POPUP样式,同时要去除边框、窗口标题,不能改变大小,使用SetWindowLong函数可修改窗口样式,使用SetWindowPos函数调整窗口大小,
有个注意事项,刚拿到窗口句柄,就修改窗口样式会不起作用,需要等窗口显示了再调用,使用IsWindowVisible函数判断窗口是否显示,这比Thread.Sleep()更稳更快,使用FindWindow函数查找窗口句柄。
/// <summary> /// 嵌入窗口 /// </summary> /// <param name="process"></param> /// <param name="hWndNewParent"></param> /// <param name="size"></param> /// <param name="lpClassName"></param> /// <param name="lpWindowName"></param> /// <returns></returns> public static bool SetParentWindow(IntPtr hWndNewParent, System.Drawing.Size size, string lpClassName, string lpWindowName, out Process childProcess, Process process = null) { var ret = FindWindow(lpClassName, lpWindowName, out IntPtr hWndChild, out childProcess, process); if (ret) { SpinWait.SpinUntil(() => { if (NativeMethods.IsWindowVisible(hWndChild)) return true; else { Thread.Sleep(100); return false; } }); // 设为无边框窗口 + 嵌入窗口前,设为子窗口 var style = NativeMethods.GetWindowLong(hWndChild, -16); style = new IntPtr((style.ToInt64() | 0x40000000L) & ~(0x00C00000L | 0x00080000L | 0x00040000L | 0x00000080L)); NativeMethods.SetWindowLong(hWndChild, -16, style); // 改变窗口大小 NativeMethods.SetWindowPos(hWndChild, 0, 0, 0, size.Width, size.Height, 0); // 嵌入窗口 return NativeMethods.SetParent(hWndChild, hWndNewParent) != IntPtr.Zero; } return false; } /// <summary> /// 查找指定窗口 /// </summary> /// <param name="lpClassName"></param> /// <param name="lpWindowName"></param> /// <param name="process"></param> /// <returns></returns> public static bool FindWindow(string lpClassName, string lpWindowName, out IntPtr hWnd, out Process childProcess, Process process = null) { childProcess = null; var hWndChild = hWnd = IntPtr.Zero; // 查找指定窗口 var ret = SpinWait.SpinUntil(() => { if (process == null || process.MainWindowHandle != IntPtr.Zero) return (hWndChild = NativeMethods.FindWindow(lpClassName, lpWindowName)) != IntPtr.Zero; Thread.Sleep(100); return false; }, 5000); if (ret) { hWnd = hWndChild; // 查找窗口所在进程 if (NativeMethods.GetWindowThreadProcessId(hWndChild, out UInt32 processId) != 0) childProcess = Process.GetProcessById((Int32)processId); } return ret; }
分类:
C#
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本