SysMsgFilterProc 是 Windows 系統訊息過濾鉤子(WH_SYSMSGFILTER)的回調函數。此鉤子允許應用程式監控並過濾系統層級的訊息,特別是對話方塊、訊息方塊、功能表等系統 UI 產生的訊息。它屬於全域鉤子,必須在 DLL 中實現並透過 SetWindowsHookEx 安裝。
LRESULT CALLBACK SysMsgFilterProc(
_In_ int nCode,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
| 參數 | 類型 | 說明 |
|---|---|---|
| nCode | int | 鉤子代碼,決定如何處理訊息:MSGF_DIALOGBOX (0):對話方塊訊息MSGF_MESSAGEBOX (1):訊息方塊訊息MSGF_MENU (2):功能表訊息MSGF_SCROLLBAR (5):捲軸訊息MSGF_NEXTWINDOW (6):視窗切換訊息 (Alt+Tab) |
| wParam | WPARAM | 訊息類型(如 WM_KEYDOWN、WM_COMMAND 等) |
| lParam | LPARAM | 指向 MSG 結構的指標,包含完整訊息資訊 |
CallNextHookEx 並返回其結果| 特性 | WH_SYSMSGFILTER | WH_MSGFILTER |
|---|---|---|
| 範圍 | 全系統所有執行緒 | 僅安裝執行緒的訊息佇列 |
| 安裝需求 | 必須在 DLL 中,注入所有進程 | 同進程即可,無需 DLL |
| 攔截目標 | 系統模態對話框、訊息框、功能表 | 應用程式自身的模態迴圈 |
| 典型用途 | 系統級熱鍵、無障礙工具、UI 自動化 | 應用程式內部模態對話框快捷鍵 |
HookDLL.dpr
library HookDLL;
uses
Windows,
Messages,
SysUtils;
{$R *.res}
var
g_hHook: HHOOK = 0;
function SysMsgFilterProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
var
pMsg: PMSG;
begin
Result := 0;
if nCode >= 0 then
begin
// 僅處理訊息方塊訊息
if nCode = MSGF_MESSAGEBOX then
begin
pMsg := PMSG(lParam);
// 攔截 ESC 鍵關閉訊息方塊
if (pMsg.message = WM_KEYDOWN) and (pMsg.wParam = VK_ESCAPE) then
begin
// 這裡可以記錄日誌、播放聲音、或彈出自定義確認對話框
OutputDebugString('SysMsgFilter: ESC pressed on MessageBox, intercepted!');
Result := 1; // 攔截,阻止訊息方塊關閉
Exit;
end;
end;
end;
Result := CallNextHookEx(g_hHook, nCode, wParam, lParam);
end;
procedure InstallHook; stdcall;
begin
if g_hHook = 0 then
g_hHook := SetWindowsHookEx(WH_SYSMSGFILTER, @SysMsgFilterProc, HInstance, 0);
end;
procedure UninstallHook; stdcall;
begin
if g_hHook <> 0 then
begin
UnhookWindowsHookEx(g_hHook);
g_hHook := 0;
end;
end;
exports
InstallHook,
UninstallHook;
begin
DisableThreadLibraryCalls(HInstance);
end.
主程式調用
unit MainUnit;
interface
uses Windows, Forms, StdCtrls, Controls;
type
TForm1 = class(TForm)
btnShowMsgBox: TButton;
btnInstallHook: TButton;
btnUninstallHook: TButton;
procedure btnShowMsgBoxClick(Sender: TObject);
procedure btnInstallHookClick(Sender: TObject);
procedure btnUninstallHookClick(Sender: TObject);
private
procedure InstallHook; external 'HookDLL.dll' name 'InstallHook';
procedure UninstallHook; external 'HookDLL.dll' name 'UninstallHook';
end;
implementation
{$R *.dfm}
procedure TForm1.btnShowMsgBoxClick(Sender: TObject);
begin
MessageBox(Handle, '按 ESC 鍵測試攔截效果', '系統訊息方塊', MB_OK or MB_ICONINFORMATION);
end;
procedure TForm1.btnInstallHookClick(Sender: TObject);
begin
InstallHook;
ShowMessage('SysMsgFilter 鉤子已安裝');
end;
procedure TForm1.btnUninstallHookClick(Sender: TObject);
begin
UninstallHook;
ShowMessage('SysMsgFilter 鉤子已移除');
end;
end.
透過 MSGF_DIALOGBOX 代碼,可以為所有系統對話框(如檔案開啟/儲存對話框、列印對話框)添加自定義快捷鍵:
if nCode = MSGF_DIALOGBOX then
begin
pMsg := PMSG(lParam);
if (pMsg.message = WM_KEYDOWN) then
begin
case pMsg.wParam of
VK_F1: // F1 顯示線上說明
begin
// 發送自定義訊息給主程式顯示說明
PostMessage(FindWindow('MyAppClass', nil), WM_USER + 100, 0, 0);
Result := 1;
Exit;
end;
VK_F5: // F5 重新整理檔案列表
begin
// 模擬點擊「重新整理」按鈕
PostMessage(pMsg.hwnd, WM_COMMAND, MAKEWPARAM(ID_REFRESH, BN_CLICKED), 0);
Result := 1;
Exit;
end;
end;
end;
end;
OutputDebugString 配合 DebugView 監控回調觸發情況DisableThreadLibraryCalls 減少載入/卸載通知開銷nCode 值分佈,確認實際攔截到的訊息類型SetWindowsHookEx(WH_SYSMSGFILTER, ...) - 安裝系統訊息過濾鉤子CallNextHookEx - 傳遞給鉤子鏈中下一個處理程序UnhookWindowsHookEx - 移除鉤子GetMessage / PeekMessage - 訊息迴圈相關IsDialogMessage - 系統內部處理對話框鍵盤導航的 API