You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

调用SetWindowsHookEx()传递钩子协议时出错,键盘记录器开发遇阻

解决低级键盘钩子SetWindowsHookEx传递过程的错误问题

最近我也踩过低级键盘钩子的坑,结合你给出的CLogger类代码片段,咱们来一步步排查SetWindowsHookEx调用失败的核心问题:


1. 最可能的原因:类成员函数与钩子过程的签名不兼容

SetWindowsHookEx要求的HOOKPROC是普通全局函数指针,但你的KbdHookProc是类的非静态成员函数——这类函数会隐含一个this指针作为第一个参数,导致函数签名和系统要求的HOOKPROC完全不匹配,系统根本无法正确调用它。

修正方案:把钩子过程改为静态成员函数

静态成员函数没有隐含的this指针,签名可以完美匹配HOOKPROC。修改后的类声明示例:

class CLogger { 
public: 
    static CLogger *Logger(); 
    bool OpenLogFile(const char*, const char*); 
    void WriteToLogFile(UINT, FILE*, char&); 
    void __cdecl Hook(); 
    void __cdecl Unhook();
    // 改为静态成员函数,匹配HOOKPROC签名
    static LRESULT __stdcall KbdHookProc(int nCode, WPARAM wParam, LPARAM lParam); 
private: 
    CLogger() {}; 
    // 添加静态钩子句柄,用于保存和释放钩子
    static HHOOK m_hHook; 
    // 其他私有成员...
};

然后在静态钩子过程里,通过单例Logger()访问类的非静态成员:

LRESULT __stdcall CLogger::KbdHookProc(int nCode, WPARAM wParam, LPARAM lParam) {
    if (nCode >= 0) {
        // 通过单例获取类实例,处理按键逻辑
        CLogger* pLogger = CLogger::Logger();
        if (pLogger) {
            // 这里可以调用pLogger的非静态成员函数处理按键记录
        }
    }
    // 必须传递钩子链,否则会影响其他程序的键盘功能
    return CallNextHookEx(m_hHook, nCode, wParam, lParam);
}

2. 检查SetWindowsHookEx的参数调用是否正确

调用时要注意几个关键参数的正确性:

void CLogger::Hook() {
    m_hHook = SetWindowsHookEx(WH_KEYBOARD_LL, 
                               (HOOKPROC)CLogger::KbdHookProc, 
                               GetModuleHandle(NULL), 
                               0);
    if (!m_hHook) {
        // 调用GetLastError()获取具体错误码,快速定位问题
        DWORD errCode = GetLastError();
        // 比如错误码127=找不到过程(大概率是函数签名问题),5=权限不足
    }
}
  • 第一个参数必须是WH_KEYBOARD_LL(低级键盘钩子的专属标识)
  • 第三个参数用GetModuleHandle(NULL)获取当前进程的模块句柄(低级钩子不需要注入DLL,系统会直接在你的进程内调用钩子过程)
  • 第四个参数填0表示全局钩子(监控所有线程的按键)

3. 其他容易忽略的坑

  • 调用约定必须严格匹配:钩子过程必须是__stdcall,如果写成__cdecl会导致栈错误,直接触发SetWindowsHookEx失败。
  • 权限问题:Windows Vista及以上系统,程序需要以管理员身份运行,否则可能无法设置全局低级钩子。
  • 钩子释放要及时:在Unhook函数里必须调用UnhookWindowsHookEx(m_hHook),避免钩子残留导致系统异常。

建议你在SetWindowsHookEx失败后立即调用GetLastError(),根据错误码能更快锁定问题根源。

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

火山引擎 最新活动