鉤子函數雖然不多, 但其參數複雜, 應該從參數入手才能深入進去.
UnhookWindowsHookEx 只需要 SetWindowsHookEx 返回的鉤子控制代碼作參數, 這個簡單;
先看看 SetWindowsHookEx 的聲明:
SetWindowsHookEx( idHook: Integer; {鉤子類型} lpfn: TFNHookProc; {函數指標} hmod: HINST; {包含鉤子函數的模組(EXE、DLL)的控制代碼} dwThreadId: DWORD {關聯的線程}): HHOOK;
第一個參數非常麻煩, 從後面說:
參數四 dwThreadId : 在設定全域鉤子時這個參數一般是 0, 表示關聯所有線程; 本例是線程級的鉤子, 所以是
GetCurrentThreadId.
參數三 hmod: 是模組執行個體的控制代碼, 在 EXE 和 DLL 中都可以用 HInstance 得到當前執行個體的控制代碼; 直接用 API 也可以:
GetModuleHandle(nil).
參數二 lpfn: 是鉤子函數的指標, 用 @ 和 Addr 函數都可以得到函數指標; 這裡的關鍵是那個鉤子函數:
首先不同的鉤子類型對應著不同的鉤子函數結構, Win32 共有 14 種鉤子類型, 這是 詳細注釋;
本例用的是鍵盤鉤子, 鍵盤鉤子的回呼函數的參數結構在 這裡, 我們定義的函數名無所謂, 參數必須按照Windows的規定來.
還有, 這個回呼函數的調用慣例必須是: stdcall; 我們在上例中是先在介面區聲明, 如果不要聲明直接實現, 也不能忘了這個 stdcall.
根據以上說明, 做如下修改:
SetWindowsHookEx 的參數有變通;
並且取消了鉤子函數在介面區的聲明, 是直接實現的;
取消了攔截條件, 現在只要是鍵盤訊息全都攔截.
unit Unit1;interfaceuses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs;type TForm1 = class(TForm) procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); end;var Form1: TForm1;implementation{$R *.DFM}var hook: HHOOK; {定義一個鉤子控制代碼}{現在這個鉤子函數沒有在介面區聲明, 這裡必須指定參數調用方式: stdcall}function KeyHook(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;begin Beep; Result := CallNextHookEx(hook, nCode, wParam, lParam);end;{設定鍵盤鉤子}procedure TForm1.FormCreate(Sender: TObject);begin hook := SetWindowsHookEx(WH_KEYBOARD, Addr(KeyHook), HInstance, GetCurrentThreadId);end;{釋放鍵盤鉤子}procedure TForm1.FormDestroy(Sender: TObject);begin UnhookWindowsHookEx(hook);end;end.
鉤子函數為什麼非得使用 stdcall 調用機制? 因為鉤子函數不是被應用程式調用, 而是被系統調用的.