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

WinAPI:SetWindowsHookEx 安裝鉤子完整指南

     編輯:Delphi

SetWindowsHookEx 核心函數詳解

SetWindowsHookEx 是 Windows 鉤子機制的入口函數,用於將自定義回調函數插入系統訊息處理鏈中,實現全域或線程級的訊息攔截、監控、修改甚至阻斷。

函數原型

function SetWindowsHookEx(
  idHook: Integer;       // 鉤子類型
  lpfn: TFNHookProc;     // 回調函數指標
  hmod: HINST;           // 包含回調函數的模組句柄 (EXE/DLL)
  dwThreadId: DWORD      // 目標線程 ID,0 表示系統級全域鉤子
): HHOOK; stdcall;       // 返回鉤子句柄,0 表示失敗

關鍵參數深度解析

1. idHook:鉤子類型選項表

常數值層級用途
WH_MSGFILTER-1線程級攔截對話框/選單/捲軸等控件互動訊息
WH_JOURNALRECORD0系統級記錄所有輸入事件(巨集錄製)
WH_JOURNALPLAYBACK1系統級回放記錄的輸入事件(巨集回放)
WH_KEYBOARD2系統/線程攔截鍵盤訊息 (WM_KEYDOWN 等)
WH_GETMESSAGE3系統/線程攔截 GetMessage/PeekMessage 取得的訊息
WH_CALLWNDPROC4系統/線程攔截 SendMessage 發送前的訊息
WH_CBT5系統/線程攔截視窗建立/啟動/關閉/移動等系統基本操作
WH_SYSMSGFILTER6系統級系統範圍內控件互動訊息
WH_MOUSE7系統/線程攔截滑鼠訊息
WH_HARDWARE8系統/線程攔截非標準硬體輸入
WH_DEBUG9系統/線程其他鉤子調用前調試用
WH_SHELL10系統/線程攔截 Shell 相關通知(視窗開啟/關閉、任務列變化)
WH_FOREGROUNDIDLE11系統/線程前台線程閒置時調用
WH_CALLWNDPROCRET12系統/線程攔截 SendMessage 返回後的訊息

2. hmod 與 dwThreadId:模組與線程綁定規則

  • 系統級鉤子 (dwThreadId = 0):回調函數必須位於 DLL 中,hmod 傳入該 DLL 的 HInstance。EXE 直接傳遞回調地址會失敗(返回 0,GetLastError = ERROR_INVALID_PARAMETER)。
  • 線程級鉤子 (dwThreadId > 0):回調可在 EXE 內,hmod 傳入 HInstance 或 0(當前模組)。目標線程必須有訊息佇列(GUI 線程)。
  • 獲取線程 ID:GetCurrentThreadId(當前)、GetWindowThreadProcessId(指定視窗)。

完整範例:線程級鍵盤鉤子 (EXE 內實現)

unit MainUnit;
interface
uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;
type
  TForm1 = class(TForm)
    Button1, Button2: TButton;
    procedure Button1Click(Sender: TObject); // 安裝
    procedure Button2Click(Sender: TObject); // 卸載
    procedure FormDestroy(Sender: TObject);
  private
    hHook: HHOOK;
    function KeyboardProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
  end;
var Form1: TForm1;
implementation {$R *.dfm}

function TForm1.KeyboardProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
begin
  if nCode = HC_ACTION then
  begin
    // wParam: 虛擬鍵碼, lParam: 掃描碼/狀態位
    OutputDebugString(PChar(Format('Key: %d, State: %x', [wParam, lParam])));
  end;
  Result := CallNextHookEx(hHook, nCode, wParam, lParam); // 必須傳遞
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  if hHook = 0 then
    hHook := SetWindowsHookEx(WH_KEYBOARD, @KeyboardProc, HInstance, GetCurrentThreadId);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  if hHook <> 0 then
  begin
    UnhookWindowsHookEx(hHook);
    hHook := 0;
  end;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  if hHook <> 0 then UnhookWindowsHookEx(hHook);
end;
end.

系統級鉤子 DLL 範例架構

{ HookDll.dpr }
library HookDll;
uses Windows, SysUtils;
var hHook: HHOOK = 0;

function KeyboardProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
begin
  if nCode = HC_ACTION then
    // 記錄或處理全域鍵盤事件
  Result := CallNextHookEx(hHook, nCode, wParam, lParam);
end;

function InstallHook: Boolean; stdcall;
begin
  hHook := SetWindowsHookEx(WH_KEYBOARD, @KeyboardProc, HInstance, 0); // 系統級
  Result := hHook <> 0;
end;

function UninstallHook: Boolean; stdcall;
begin
  if hHook <> 0 then
  begin
    Result := UnhookWindowsHookEx(hHook);
    if Result then hHook := 0;
  end else Result := True;
end;

exports InstallHook, UninstallHook;
begin
end.

效能與穩定性建議

  • 回調必須極快返回:避免檔案 I/O、資料庫、同步物件等阻塞操作,否則導致全系統輸入延遲。
  • 使用 Low-Level 鉤子 (LL):WH_KEYBOARD_LL、WH_MOUSE_LL 不需 DLL,回調在安裝進程內執行,但仍需注意效能。
  • 錯誤處理:安裝失敗時檢查 GetLastError,常見錯誤:1428 (ERROR_HOOK_NEEDS_HMOD)、1429 (ERROR_GLOBAL_ONLY_HOOK)。
  • 及時卸載:視窗關閉、DLL 卸載、例外發生時都要確保 UnhookWindowsHookEx 執行。

常見應用場景

  • 熱鍵註冊 (WH_KEYBOARD_LL)
  • 視窗管理/自動化 (WH_CBT, WH_SHELL)
  • 輸入法/螢幕鍵盤 (WH_KEYBOARD)
  • 巨集錄製/回放 (WH_JOURNALRECORD/PLAYBACK)
  • 除錯/診斷工具 (WH_DEBUG, WH_GETMESSAGE)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved