首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

Windows 線程鉤子實戰:SetWindowsHookEx 完整應用指南

     編輯:關於VC++

核心概念:線程鉤子機制

在 Windows 程式設計中,線程鉤子是實現跨進程消息攔截的關鍵技術。透過 SetWindowsHookEx 函數,開發者可以將自定義的回調函數注入目標線程的消息隊列,從而監控或修改系統消息流向。這在實現全局熱鍵、視窗子類化、輸入法編輯器等場景中極為常見。

關鍵參數深度解析

HHOOK g_hHook = SetWindowsHookEx(
    WH_SYSMSGFILTER | WH_MSGFILTER,  // 組合鉤子類型:系統消息過濾 + 消息過濾
    (HOOKPROC)HookShowWindow,        // 回調函數指標
    g_hInst,                         // 包含回調函數的 DLL 模組句柄
    progID                           // 目標線程 ID
);

模組句柄 (g_hInst) 的正確獲取方式

這是新手最容易踩坑的地方。由於鉤子回調函數必須駐留在 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;
}

目標線程 ID (progID) 的獲取

透過 FindWindow 定位目標視窗,再取其建立線程 ID:

DWORD progID = GetWindowThreadProcessId(
    FindWindow(_T("xvt320mditask100"), NULL)->m_hWnd, 
    NULL
);

鉤子的安裝與卸載

SetWindowsHookEx 成功時返回鉤子句柄 g_hHook,務必妥善保存以便後續卸載:

// 卸載鉤子
UnhookWindowsHookEx(g_hHook);

常見陷阱與最佳實踐

  • DLL 邊界:回調函數必須導出,且不能使用 C++ 名稱修飾(建議用 extern "C" 或 __declspec(dllexport))
  • 線程親和性:WH_GETMESSAGE 類鉤子需目標線程有消息迴圈
  • 效能考量:回調函數應極簡、極快,避免阻塞目標線程
  • 64 位相容:32 位 DLL 僅能鉤住 32 位進程,64 位同理,需分別編譯

完整範例架構

典型專案包含三部分:

  1. HookDLL:含 DllMain、回調函數、SetHook/Unhook 導出函數
  2. HostEXE:載入 DLL、呼叫 SetHook、傳遞目標視窗類別名/標題
  3. 共用頭檔:定義導出函數原型、自定義消息常數

掌握上述要點,即可靈活運用線程鉤子解決跨進程通訊、UI 自動化等棘手問題。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved