C# 截取另一个窗口的窗口消息

C# 截取另一个窗口的窗口消息,c#,winapi,pinvoke,C#,Winapi,Pinvoke,我正在使用CefGlue制作一个带有嵌入式webkit浏览器的应用程序,我需要在浏览器窗口中监听鼠标移动。winforms控件不会将鼠标事件传递给该控件,因此我无法侦听它们 然而,我发现了一个bug/feature请求,其中包含一个解决方案,但我无法理解如何实现它,我不熟悉直接在WinAPI中工作。开发商说我需要: 二,。特定于操作系统(windows)-在创建浏览器(CeffLifeSpanHandler.OnAfterCreated)后获取窗口句柄和子类 它们(窗口子类化技术)。事实上,现在

我正在使用CefGlue制作一个带有嵌入式webkit浏览器的应用程序,我需要在浏览器窗口中监听鼠标移动。winforms控件不会将鼠标事件传递给该控件,因此我无法侦听它们

然而,我发现了一个bug/feature请求,其中包含一个解决方案,但我无法理解如何实现它,我不熟悉直接在WinAPI中工作。开发商说我需要:

二,。特定于操作系统(windows)-在创建浏览器(CeffLifeSpanHandler.OnAfterCreated)后获取窗口句柄和子类 它们(窗口子类化技术)。事实上,现在我们有了本地人 类为CefBrowserWindow的窗口(由返回) CefBrowser.GetHost().GetWindowHandle()),然后是子窗口 Chrome_WidgetWin_0,然后是Chrome_RenderWidgetHostHWND。对于 拦截WM_鼠标移动您对Chrome_WidgetWin_0感兴趣 窗口,可通过CefBrowserWindow轻松获取。玩玩 使用Spy++进行精确查看

我用谷歌搜索了一下,但我不知道该怎么做。我的表格上有以下功能:

    [System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
    protected override void WndProc(ref Message m) {
        base.WndProc(ref m);

        switch (m.Msg) {
            case WM_MOUSEMOVE:
                Console.WriteLine("Mouse move!");
                break;
            default:
                Console.WriteLine(m.ToString());
                break;
        }
    }

但是当我控制鼠标时,我从来没有看到鼠标移动。我怀疑我需要监听
CefBrowser.GetHost().GetWindowHandle()
的WndProc,但我不确定该怎么做。

我找到了一个解决方案。我在WebLifeSpanHandler的OnAfterCreated事件中调用此函数

        browser.Created += (sender, eventargs) => {
            Console.WriteLine("Created.");
            BrowserWindowPointer = browser.CefBrowser.GetHost().GetWindowHandle();
            Console.WriteLine("BrowserWindowPointer: " + BrowserWindowPointer);
            uint BrowserThreadId = GetWindowThreadProcessId(BrowserWindowPointer, IntPtr.Zero);
            Console.WriteLine("Browser PID: " + BrowserThreadId);

            MouseHookProcedure = new HookProc(this.MouseHookProc);

            hHookMouse = SetWindowsHookEx(WH_MOUSE,
                        MouseHookProcedure,
                        (IntPtr)0,
                        BrowserThreadId);

            if (hHookMouse == 0) {
                Console.WriteLine("MouseHook Failed. Making cursor always visible.");
                Cursor.Show();
            }

            KeyboardHookProcedure = new HookProc(this.KeyboardHookProc);
            hHookKeyboard = SetWindowsHookEx(WH_KEYBOARD,
                        KeyboardHookProcedure,
                        (IntPtr)0,
                        BrowserThreadId);
        };
我要找的函数是GetWindowThreadProcessId,我可以使用
browser.CefBrowser.GetHost().GetWindowHandle()提供的窗口句柄

需要注意的一点是,钩子过程需要有更大的范围。C#没有看到它挂接到本机进程中,如果您让它超出范围,它将进行垃圾收集。为了解决这个问题,我将它们设置为类属性

证明文件:

  • 如何在Visual C#.NET中设置Windows钩子提供了钩住鼠标事件的基础。修改为使用浏览器线程id
  • MouseProc回调函数如何处理鼠标窗口钩子
  • 键盘PROC回调函数如何处理键盘窗口挂钩。包括LPRAM的结构。重要提示:wParam包含输入密钥的虚拟密钥代码
  • 虚拟钥匙代码钥匙及其虚拟钥匙代码列表,这样我就可以知道用户正在按哪个按钮
我的两个钩子(不是好代码,我不处理封送的数据):

我不确定这是否完全是必需的,特别是因为被钩住的线在接近时会消失,但为了更好的测量,在你听完之后,别忘了清理你的钩子。我在表单的dispose方法中执行此操作:

    protected override void Dispose(bool disposing) {
        base.Dispose();

        if (disposing) {
            if (hHookKeyboard != 0) {
                UnhookWindowsHookEx(hHookKeyboard);
            }
            if (hHookMouse != 0) {
                UnhookWindowsHookEx(hHookMouse);
            }
        }
    }

我找到了解决办法。我在WebLifeSpanHandler的OnAfterCreated事件中调用此函数

        browser.Created += (sender, eventargs) => {
            Console.WriteLine("Created.");
            BrowserWindowPointer = browser.CefBrowser.GetHost().GetWindowHandle();
            Console.WriteLine("BrowserWindowPointer: " + BrowserWindowPointer);
            uint BrowserThreadId = GetWindowThreadProcessId(BrowserWindowPointer, IntPtr.Zero);
            Console.WriteLine("Browser PID: " + BrowserThreadId);

            MouseHookProcedure = new HookProc(this.MouseHookProc);

            hHookMouse = SetWindowsHookEx(WH_MOUSE,
                        MouseHookProcedure,
                        (IntPtr)0,
                        BrowserThreadId);

            if (hHookMouse == 0) {
                Console.WriteLine("MouseHook Failed. Making cursor always visible.");
                Cursor.Show();
            }

            KeyboardHookProcedure = new HookProc(this.KeyboardHookProc);
            hHookKeyboard = SetWindowsHookEx(WH_KEYBOARD,
                        KeyboardHookProcedure,
                        (IntPtr)0,
                        BrowserThreadId);
        };
我要找的函数是GetWindowThreadProcessId,我可以使用
browser.CefBrowser.GetHost().GetWindowHandle()提供的窗口句柄

需要注意的一点是,钩子过程需要有更大的范围。C#没有看到它挂接到本机进程中,如果您让它超出范围,它将进行垃圾收集。为了解决这个问题,我将它们设置为类属性

证明文件:

  • 如何在Visual C#.NET中设置Windows钩子提供了钩住鼠标事件的基础。修改为使用浏览器线程id
  • MouseProc回调函数如何处理鼠标窗口钩子
  • 键盘PROC回调函数如何处理键盘窗口挂钩。包括LPRAM的结构。重要提示:wParam包含输入密钥的虚拟密钥代码
  • 虚拟钥匙代码钥匙及其虚拟钥匙代码列表,这样我就可以知道用户正在按哪个按钮
我的两个钩子(不是好代码,我不处理封送的数据):

我不确定这是否完全是必需的,特别是因为被钩住的线在接近时会消失,但为了更好的测量,在你听完之后,别忘了清理你的钩子。我在表单的dispose方法中执行此操作:

    protected override void Dispose(bool disposing) {
        base.Dispose();

        if (disposing) {
            if (hHookKeyboard != 0) {
                UnhookWindowsHookEx(hHookKeyboard);
            }
            if (hHookMouse != 0) {
                UnhookWindowsHookEx(hHookMouse);
            }
        }
    }