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

WinAPI 鉤子回調:CallWndProc 詳細解析

     編輯:Delphi

CallWndProc 回調函數

CallWndProc 配合 WH_CALLWNDPROC 鉤子類型,在SendMessage 將訊息發送給目標視窗程序之前被呼叫。它是同步訊息攔截的「入口哨」,可檢查、修改訊息參數、甚至決定是否允許訊息繼續傳遞。

函數原型

function CallWndProc(
  nCode: Integer;    // 鉤子代碼
  wParam: WPARAM;    // 保留,通常 0
  lParam: LPARAM     // 指向 CWPSTRUCT 結構
): LRESULT; stdcall;

CWPSTRUCT 結構詳解

type
  tagCWPSTRUCT = record
    message: UINT;     // 訊息 ID
    wParam: WPARAM;    // 參數 1
    lParam: LPARAM;    // 參數 2
    hwnd: HWND;        // 目標視窗句柄
  end;

注意:無 lResult 欄位,因為訊息尚未處理,無返回值。

核心能力:修改訊息參數

回調中可直接修改 PCWPSTRUCT(lParam)^.wParam、.lParam、甚至 .message、.hwnd,修改後的值將傳遞給目標視窗程序。這是實現全域訊息重映射的關鍵機制。

觸發範圍與部署

屬性系統級 (dwThreadId=0)線程級 (dwThreadId>0)
回調位置DLL (必須)EXE 可行
監控範圍全系統所有 SendMessage指定線程 SendMessage
跨進程支援不支援
典型用途全域熱鍵、UI 自動化、輔助技術模組內訊息調試、單元測試

典型應用場景

  • 全域熱鍵攔截:將特定 WM_KEYDOWN 映射為自定義命令訊息
  • UI 測試/自動化:記錄/重放 SendMessage 序列
  • 相容性修補:修正舊應用在新系統上傳遞錯誤參數的訊息
  • 安全防護:攔截危險訊息 (如 WM_COPYDATA 注入)

系統級 DLL 完整範例:全域將右鍵點擊轉為左鍵

{ HookDll.dpr }
library HookDll;
uses Windows;

var hHook: HHOOK = 0;

function CallWndProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
var p: PCWPSTRUCT;
begin
  if nCode = HC_ACTION then
  begin
    p := PCWPSTRUCT(lParam);
    // 將 WM_RBUTTONDOWN/UP/DBLCLK 映射為左鍵對應訊息
    case p.message of
      WM_RBUTTONDOWN: p.message := WM_LBUTTONDOWN;
      WM_RBUTTONUP:   p.message := WM_LBUTTONUP;
      WM_RBUTTONDBLCLK: p.message := WM_LBUTTONDBLCLK;
    end;
  end;
  Result := CallNextHookEx(hHook, nCode, wParam, lParam);
end;

function InstallHook: Boolean; stdcall;
begin
  hHook := SetWindowsHookEx(WH_CALLWNDPROC, @CallWndProc, 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.

效能與安全關鍵準則

  1. 極速過濾:回調第一行必須 if nCode < 0 then Exit(CallNextHookEx(...));第二行 if p.message <> TargetMsg then Exit(CallNextHookEx(...))。
  2. 不可阻塞:絕不可 在回調中呼叫 SendMessage、WaitForSingleObject、Sleep、檔案 I/O、資料庫操作。需異步處理請 PostMessage 給主線程。
  3. 修改 hwnd 風險極高:將訊息重導向其他視窗可能破壞視窗狀態機,極謹慎使用。
  4. 返回值:通常返回 CallNextHookEx 結果;若要攔截訊息 (不讓目標視窗收到),返回非零值 (如 1) 且不呼叫 CallNextHookEx。

WH_CALLWNDPROC vs WH_GETMESSAGE 對比

特性WH_CALLWNDPROCWH_GETMESSAGE
攔截對象SendMessage (同步)GetMessage/PeekMessage 取出的所有訊息
PostMessage不攔截攔截 (從佇列取出時)
修改參數可修改 wParam/lParam/message/hwnd可修改 MSG 結構
執行上下文目標線程 (接收端)接收線程 (取訊息端)
典型用途同步訊息重映射、參數修正全域訊息監控、熱鍵、記錄

現代替代方案

  • 應用內部:Application.OnMessage / TApplicationEvents.OnMessage (VCL) — 無鉤子開銷、類型安全
  • 低層級鍵盤/滑鼠:WH_KEYBOARD_LL/WH_MOUSE_LL — 不需 DLL、支援注入
  • UI 自動化:UI Automation (UIA) / Microsoft Active Accessibility (MSAA) — 標準化、無注入風險
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved