【问题标题】:Intercepting Window Messages for another Window拦截另一个窗口的窗口消息
【发布时间】:2013-12-19 19:27:07
【问题描述】:

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

但是,我发现了一个错误/功能请求,其中包含一个解决方案,但如何实现它超出了我的能力范围,我不熟悉直接在 WinAPI 中工作。开发人员说我需要:

2。特定于操作系统(windows) - 创建浏览器后(CefLifeSpanHandler.OnAfterCreated)获取窗口句柄和子类 它们(窗口子类化技术)。其实现在我们有本地人 具有类 CefBrowserWindow 的窗口(由 CefBrowser.GetHost().GetWindowHandle()),然后是子窗口 Chrome_WidgetWin_0,然后是 Chrome_RenderWidgetHostHWND。为了 拦截 WM_MOUSEMOVE 你对 Chrome_WidgetWin_0 感兴趣 窗口,可以通过 CefBrowserWindow 轻松获取。只是玩 用 Spy++ 精确查看。

https://bitbucket.org/xilium/xilium.cefglue/issue/4/mouse-events-unaccessible

我做了一些谷歌搜索,但我不知道如何挂钩。我的表单上有这个功能:

    [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,但我不知道该怎么做。

【问题讨论】:

标签: c# winapi pinvoke


【解决方案1】:

我找到了解决方案。我在 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()提供的窗口句柄

需要注意的一点是,Hook Procedure 需要具有某种更大的范围。 C# 看不到它与本机进程挂钩,如果你让它超出范围,它会被垃圾收集。为了解决这个问题,我将它们设为类属性。

支持文件:

我的两个钩子(代码不好,我对封送数据不做任何事情):

    private int MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam) {
        //Marshall the data from the callback.
        MouseHookStruct MyMouseHookStruct = (MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseHookStruct));

        if (nCode < 0) {
            return CallNextHookEx(hHookMouse, nCode, wParam, lParam);
        } else {
            if (wParam.ToInt32() == WM_MOUSEMOVE) {
                Screensaver_OnMouseMove(this, null);
            }
            return CallNextHookEx(hHookMouse, nCode, wParam, lParam);
        }
    }

    private int KeyboardHookProc(int nCode, IntPtr wParam, IntPtr lParam) {
        //Marshall the data from the callback.
        KeyboardHookStruct keyInfo = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
        int VK_ESCAPE = 0x1B;

        if (nCode < 0) {
            return CallNextHookEx(hHookKeyboard, nCode, wParam, lParam);
        } else {
            int keyCode = wParam.ToInt32();

            if (keyCode == VK_ESCAPE) {
                Application.Exit();
            }

            return CallNextHookEx(hHookKeyboard, nCode, wParam, lParam);
        }

    }

这是暴露钩子所需的外部和代码,这是类级别的范围:

    public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);

    //Declare the hook handle as an int.
    static int hHookMouse = 0;
    static int hHookKeyboard = 0;

    //Declare the mouse hook constant.
    //For other hook types, you can obtain these values from Winuser.h in the Microsoft SDK.
    private const int WH_KEYBOARD = 2;
    private const int WH_MOUSE = 7;
    private const int WM_MOUSEMOVE = 0x0200;

    //Declare the wrapper managed POINT class.
    [StructLayout(LayoutKind.Sequential)]
    public class POINT {
        public int x;
        public int y;
    }

    //Declare the wrapper managed MouseHookStruct class.
    [StructLayout(LayoutKind.Sequential)]
    public class MouseHookStruct {
        public POINT pt;
        public int hwnd;
        public int wHitTestCode;
        public int dwExtraInfo;
    }
    public struct KeyboardHookStruct {
        public int vkCode;
        public int scanCode;
        public int flags;
        public int time;
        public int dwExtraInfo;
    }

    //This is the Import for the SetWindowsHookEx function.
    //Use this function to install a thread-specific hook.
    [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
    public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, uint threadId);

    //This is the Import for the UnhookWindowsHookEx function.
    //Call this function to uninstall the hook.
    [DllImport("user32.dll", CharSet = CharSet.Auto,
     CallingConvention = CallingConvention.StdCall)]
    public static extern bool UnhookWindowsHookEx(int idHook);

    //This is the Import for the CallNextHookEx function.
    //Use this function to pass the hook information to the next hook procedure in chain.
    [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
    public static extern int CallNextHookEx(int idHook, int nCode, IntPtr wParam, IntPtr lParam);

    [DllImport("user32.dll")]
    static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);

    public HookProc KeyboardHookProcedure { get; set; }

    public HookProc MouseHookProcedure { get; set; }

我不确定这是否完全需要,特别是因为被钩住的线程正在关闭,但为了更好地衡量,不要忘记在听完后清理你的钩子。我在表单的 dispose 方法上执行此操作:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多