You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 5 WPF全局低级键盘钩子触发ExecutionEngineException崩溃如何解决

问题根因

崩溃的核心原因是托管回调委托被GC意外回收。
你调用SetWindowsHookEx时直接传入Handler方法,编译器会隐式生成一个LowLevelKeyboardProc委托实例,但这个实例没有被你的代码持有任何强引用,GC执行回收时会直接清理该无引用的委托。后续系统触发钩子回调时,会访问已被释放的托管内存,最终触发ExecutionEngineException异常。

修复方案

  1. 将回调委托作为类的成员变量显式持有,避免GC回收
  2. 补充钩子卸载逻辑,避免资源泄漏

修复后的完整代码

public partial class MainWindow : Window {
    private const int WH_KEYBOARD_LL = 13;
    private const int WM_KEYDOWN = 0x0100;
    private const int WM_SYSKEYDOWN = 0x0104;

    private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);

    // 显式持有委托实例,防止GC回收
    private LowLevelKeyboardProc _keyboardProc;

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod,
        uint dwThreadId);

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
        IntPtr wParam, IntPtr lParam);
    
    [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Ansi)]
    static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string lpFileName);

    // 补充卸载钩子的API
    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern bool UnhookWindowsHookEx(IntPtr hhk);

    private IntPtr _hook;


    public bool Hook() {
        if (_hook == IntPtr.Zero) {
            // 先给成员委托赋值,再传入API
            _keyboardProc = Handler;
            var modPtr = LoadLibrary("user32.dll");
            _hook = SetWindowsHookEx(WH_KEYBOARD_LL, _keyboardProc, modPtr, 0);
        }
        return _hook != IntPtr.Zero;
    }

    private IntPtr Handler(int code, IntPtr param, IntPtr lParam) {
        return CallNextHookEx(_hook, code, param, lParam);
    }

    public MainWindow() {
        InitializeComponent();
        Hook();
        // 窗口关闭时卸载钩子
        Closing += (s, e) => {
            if (_hook != IntPtr.Zero) {
                UnhookWindowsHookEx(_hook);
                _hook = IntPtr.Zero;
            }
        };
    }
}

修改后可稳定复现的崩溃问题会完全消失,快速多次按键也不会再触发异常。

内容的提问来源于stack exchange,提问作者CShark

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 23:39:00