CallWndProcRetProc 配合 WH_CALLWNDPROCRET 鉤子類型,在目標視窗程序處理完 SendMessage 發送的訊息並返回後被呼叫。與 WH_CALLWNDPROC (發送前) 形成前後夾擊,可完整觀測同步訊息的完整生命週期。
function CallWndProcRetProc(
nCode: Integer; // 鉤子代碼
wParam: WPARAM; // 保留,通常 0
lParam: LPARAM // 指向 CWPRETSTRUCT 結構
): LRESULT; stdcall;
type
tagCWPRETSTRUCT = record
lResult: LRESULT; // 視窗程序返回值 (SendMessage 的返回值)
message: UINT; // 訊息 ID
wParam: WPARAM; // 訊息參數 1
lParam: LPARAM; // 訊息參數 2
hwnd: HWND; // 目標視窗句柄
end;
關鍵差異:lResult 欄位包含視窗程序實際返回的結果,這是 WH_CALLWNDPROC (CWPSTRUCT) 沒有的。
SendMessage (同步發送),PostMessage (非同步) 不觸發。WM_QUERYENDSESSION) 的返回值,診斷關機攔截失敗。lResult (傳值),但可記錄供事後分析。WH_CALLWNDPROC 計算 SendMessage 往返耗時。BM_CLICK) 是否正確返回。{ HookDll.dpr }
library HookDll;
uses Windows, SysUtils;
var hHook: HHOOK = 0;
LogFile: TextFile;
function CallWndProcRetProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
var p: PCWPRETSTRUCT;
begin
if nCode = HC_ACTION then
begin
p := PCWPRETSTRUCT(lParam);
// 僅記錄特定訊息減少噪音
if p.message = WM_DESTROY then
begin
AssignFile(LogFile, 'C:\Temp\HookLog.txt');
if FileExists('C:\Temp\HookLog.txt') then Append(LogFile) else Rewrite(LogFile);
WriteLn(LogFile, Format('[%s] HWND:%x Msg:WM_DESTROY Result:%d',
[DateTimeToStr(Now), p.hwnd, p.lResult]));
CloseFile(LogFile);
end;
end;
Result := CallNextHookEx(hHook, nCode, wParam, lParam);
end;
function InstallHook: Boolean; stdcall;
begin
hHook := SetWindowsHookEx(WH_CALLWNDPROCRET, @CallWndProcRetProc, 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.
| 特性 | WH_CALLWNDPROC (前) | WH_CALLWNDPROCRET (後) |
|---|---|---|
| 觸發時機 | SendMessage 進入目標視窗程序前 | 視窗程序返回後,SendMessage 返回前 |
| 結構體 | CWPSTRUCT (無 lResult) | CWPRETSTRUCT (含 lResult) |
| 可修改訊息 | 是 (修改 wParam/lParam 影響處理) | 否 (訊息已處理完畢) |
| 可獲取返回值 | 否 | 是 (lResult) |
| 典型用途 | 訊息過濾、參數修改、攔截 | 返回值審計、效能測量、驗證 |
message,只處理關心的訊息。