[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; }