Windows 訊息驅動架構下的攔截點。安裝 Hook 可監視指定執行緒/全系統的特定訊息類型,在目標視窗處理前先行攔截,可修改、記錄或阻斷訊息。
CallNextHookEx 傳遞HHOOK SetWindowsHookEx(
int idHook, // 類型:WH_KEYBOARD, WH_MOUSE, WH_GETMESSAGE...
HOOKPROC lpfn, // 鉤子函式位址
HINSTANCE hMod, // 含鉤子函式的 DLL 實例句柄
DWORD dwThreadId // 目標執行緒 ID,0 = 所有 GUI 執行緒
);
LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode < 0) return CallNextHookEx(hHook, nCode, wParam, lParam);
// 處理訊息...
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
nCode == HC_ACTION:必須處理nCode < 0 或 HC_NOREMOVE:直接傳遞鉤子函式在目標行程空間執行,需將主視窗句柄 HWND 與 HHOOK 放入 DLL 共享段:
#pragma data_seg("shared")
HWND hWnd = NULL;
HHOOK hHook = NULL;
#pragma data_seg()
#pragma comment(linker, "/SECTION:shared,RWS")
// 安裝/移除介面
__declspec(dllexport) bool SetHook(bool install, HWND hwnd, int threadId) {
::hWnd = hwnd;
if (install) {
hHook = SetWindowsHookEx(WH_KEYBOARD, KeyHookProc,
GetModuleHandle("KeyHookDll"), threadId);
} else {
UnhookWindowsHookEx(hHook);
}
return true;
}
// 鉤子函式
LRESULT CALLBACK KeyHookProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode < 0 || nCode == HC_NOREMOVE)
return CallNextHookEx(hHook, nCode, wParam, lParam);
if (lParam & 0x40000000) // 僅按下訊息
PostMessage(hWnd, WM_USER + 1, wParam, lParam);
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
// 對應 WM_USER+1
afx_msg LRESULT OnKey(WPARAM wParam, LPARAM lParam) {
char name[100];
GetKeyNameText(lParam, name, 100);
m_output += "使用者按鍵: " + CString(name) + "\r\n";
UpdateData(FALSE);
MessageBeep(MB_OK);
return 0;
}
全系統 Hook 會顯著降低系統回應速度(每個訊息額外處理),僅在必要時安裝,用畢即卸載。
參考:《Windows 核心編程》第 5 版、王艷平《Windows 程式設計》第 2 版