WH_CBT钩子SetWindowsHookEx仅触发一次窗口Resize写入问题
WH_CBT钩子仅触发一次窗口Resize记录的问题修复
核心问题排查
- 钩子作用域限制:如果
SetWindowsHookEx传入了当前线程ID,钩子只能监控当前线程内的窗口,其他进程/线程的窗口Resize不会触发。必须设置全局钩子(线程ID传0),同时保证DLL能被其他进程正确加载注入。 - 文件写入模式错误:若每次打开文件用覆盖模式(如
CREATE_ALWAYS),会清空之前的内容,看起来像只写入了一次。需改用追加模式打开文件。 - 钩子函数逻辑漏洞:比如未正确调用
CallNextHookEx导致钩子被系统强制移除,或文件句柄未关闭引发资源泄漏,导致后续写入失败。
具体修复步骤
1. 配置全局钩子
主程序中调用SetWindowsHookEx时,最后一个线程ID参数传0,确保钩子覆盖所有GUI进程:
// 主程序钩子初始化代码 HMODULE hDll = LoadLibrary(L"YourHookDll.dll"); HOOKPROC cbtProc = (HOOKPROC)GetProcAddress(hDll, "CBTProc"); HHOOK hHook = SetWindowsHookEx(WH_CBT, cbtProc, hDll, 0);
注意:DLL需放在系统路径或与主程序同目录,确保其他进程能加载。
2. 修正文件写入逻辑
在DLL的钩子函数中,用追加模式打开文件,避免覆盖原有内容:
// DLL中负责写入日志的函数 void LogResizeEvent() { HANDLE hFile = CreateFile(L"resize_log.txt", GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile != INVALID_HANDLE_VALUE) { // 将文件指针移动到末尾,实现追加写入 SetFilePointer(hFile, 0, NULL, FILE_END); const char* logContent = "resized\n"; DWORD bytesWritten; WriteFile(hFile, logContent, strlen(logContent), &bytesWritten, NULL); CloseHandle(hFile); // 必须关闭句柄,防止资源泄漏 } }
3. 正确处理HCBT_SIZE事件
钩子函数仅在窗口Resize触发的HCBT_SIZE事件中执行写入,且必须调用CallNextHookEx:
// DLL导出的钩子函数 extern "C" __declspec(dllexport) LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam) { if (nCode >= 0 && nCode == HCBT_SIZE) { LogResizeEvent(); } // 必须调用下一个钩子,否则系统可能会移除当前钩子 return CallNextHookEx(NULL, nCode, wParam, lParam); }
4. 确保DLL函数正确导出
通过__declspec(dllexport)或.def文件导出钩子函数,主程序才能正确获取函数地址:
// DLL头部声明 extern "C" __declspec(dllexport) LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam);
额外注意事项
- 32/64位程序需匹配:主程序是64位则DLL也要编译为64位,否则无法注入64位进程;32位同理。
- 钩子函数要轻量化:避免在钩子函数中执行耗时操作,否则会导致目标进程卡顿,甚至钩子被系统移除。
- 测试时关闭杀毒软件:部分安全软件会拦截全局钩子注入,导致功能失效。
内容的提问来源于stack exchange,提问作者MRX
相关产品推荐
相关产品推荐

