[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 = (IntPtr)((style.ToInt32() | 0x40000000L) ^ (0x00C00000 | 0x00080000 | 0x00040000));
        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;
}
原文地址:https://www.cnblogs.com/pumbaa/p/15133115.html