隐式DLL链接适配键盘钩子却不适配WH_SHELL钩子问题排查
WH_SHELL全局钩子调用SetWindowsHookExW失败返回NULL的问题
已通过隐式链接DLL实现WH_KEYBOARD_LL全局钩子,用于PC自动化任务,运行正常。但添加WH_SHELL全局钩子时,SetWindowsHookExW调用失败,hhShell返回NULL。
EXE项目(Visual C++ 2022)代码
// pcautomation.h #pragma once #define WINVER 0x0500 #include <Windows.h> LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); // pcautomation.cpp #include "<path>\pcautomation.h" #include "<path>\keyboardCallback.h" #include "<path>\shellCallback.h" using namespace std; HHOOK hhKybd; HHOOK hhShell; int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int cmdShow) { // ... <register application window, etc> ... // 此部分正常工作 hhKybd = SetWindowsHookExW(WH_KEYBOARD_LL, (HOOKPROC) KeyboardHookProc, NULL, 0); if (NULL == hhKybd) return 0; // 此部分调用失败,hhShell为NULL hhShell = SetWindowsHookExW(WH_SHELL, (HOOKPROC) WHShellProc, NULL, 0); if (NULL == hhShell) return 0; // ... <message loop, etc> ... return 0; } LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { // ... return DefWindowProc(hwnd, msg, wParam, lParam); }
DLL项目代码
pcautomation-dll.h
#pragma once #ifdef NAX_PCA_DLL_EXPORTS #define NAX_PCA_DLL_API __declspec(dllexport) #else #define NAX_PCA_DLL_API __declspec(dllimport) #endif #define WINVER 0x0500 #include <Windows.h>
pcautomation-dll.cpp
#include "<path>\pcautomation-dll.h" #include "<path>\keyboardCallback.h" #include "<path>\shellCallback.h" BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; }
keyboardCallback.h
#pragma once #include <Windows.h> LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam);
keyboardCallback.cpp
#include "<path>\keyboardCallback.h" using namespace std; LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam) { ... CallNextHookEx(NULL, nCode, wParam, lParam); }
shellCallback.h
#pragma once #include <Windows.h> LRESULT CALLBACK WHShellProc(int nCode, WPARAM wParam, LPARAM lParam);
shellCallback.cpp
#include "<path>\shellCallback.h" using namespace std; LRESULT CALLBACK WHShellProc(int nCode, WPARAM wParam, LPARAM lParam) { if (nCode < 0) return(CallNextHookEx(NULL, nCode, wParam, lParam)); if (nCode == HSHELL_WINDOWCREATED) { ... } return 0; }
source.def
LIBRARY pcautomation-dll EXPORTS KeyboardHookProc WHShellProc
配置情况
VS 2022已完成隐式DLL链接的相关配置:
- 将
source.def设置为DLL项目链接器的模块定义文件 - 添加DLL生成的lib文件作为EXE项目的链接依赖
- 设置解决方案编译顺序为先编译DLL,再编译EXE
疑问点
两个钩子的SetWindowsHookExW均将dwThreadId设为0以实现全局钩子。根据文档,当dwThreadId指定当前进程线程且钩子过程在当前进程代码中时,hMod参数需设为NULL,但WH_KEYBOARD_LL钩子未指定当前进程线程却传入NULL仍能正常工作。想确认WH_SHELL钩子是否存在特殊性,是否必须传入DLL的显式句柄?担心需要改为显式DLL链接,但现有DLL的使用场景较多,改动成本较高。
内容的提问来源于stack exchange,提问作者neilalex
相关产品推荐
相关产品推荐

