在 Windows 程式設計中,線程鉤子是實現跨進程消息攔截的關鍵技術。透過 SetWindowsHookEx 函數,開發者可以將自定義的回調函數注入目標線程的消息隊列,從而監控或修改系統消息流向。這在實現全局熱鍵、視窗子類化、輸入法編輯器等場景中極為常見。
HHOOK g_hHook = SetWindowsHookEx(
WH_SYSMSGFILTER | WH_MSGFILTER, // 組合鉤子類型:系統消息過濾 + 消息過濾
(HOOKPROC)HookShowWindow, // 回調函數指標
g_hInst, // 包含回調函數的 DLL 模組句柄
progID // 目標線程 ID
);
這是新手最容易踩坑的地方。由於鉤子回調函數必須駐留在 DLL 中以實現跨進程注入,g_hInst 必須指向該 DLL 的模組句柄,而非 EXE 的句柄。正確做法是在 DllMain 中保存:
HINSTANCE g_hInst;
BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
g_hInst = (HINSTANCE)hModule; // 關鍵:保存 DLL 自身句柄
break;
case DLL_PROCESS_DETACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
}
return TRUE;
}
透過 FindWindow 定位目標視窗,再取其建立線程 ID:
DWORD progID = GetWindowThreadProcessId(
FindWindow(_T("xvt320mditask100"), NULL)->m_hWnd,
NULL
);
SetWindowsHookEx 成功時返回鉤子句柄 g_hHook,務必妥善保存以便後續卸載:
// 卸載鉤子
UnhookWindowsHookEx(g_hHook);
extern "C" 或 __declspec(dllexport))WH_GETMESSAGE 類鉤子需目標線程有消息迴圈典型專案包含三部分:
DllMain、回調函數、SetHook/Unhook 導出函數SetHook、傳遞目標視窗類別名/標題掌握上述要點,即可靈活運用線程鉤子解決跨進程通訊、UI 自動化等棘手問題。