鉤子 是一種機制,應用程式可以利用它攔截事件,例如訊息、滑鼠動作和擊鍵。 攔截特定事件類型的函式稱為 攔截程式。 掛勾程序可以對它收到的每個事件進行處理,然後修改或捨棄該事件。
鉤子的一些用途包括:
- 監視訊息以進行偵錯
- 提供巨集錄製和播放支援
- 提供 F1 說明鍵的支援
- 模擬滑鼠和鍵盤輸入
- 實作電腦型訓練 (CBT) 應用程式
注意
鉤子通常會讓系統變慢,因為它們會增加系統必須針對每個訊息執行的處理量。 您應該只在必要時安裝掛鈎,並儘快將其卸下。
本節討論下列事項:
掛鉤鏈
系統支援多種不同類型的掛鉤;每種類型提供對其訊息處理機制不同層面的存取。 例如,應用程式可以使用 WH_MOUSE 鉤子來監視滑鼠訊息流量。
系統會針對每種掛鈎類型維護個別的掛鈎鏈。 掛鉤鏈 是一個指向稱為 掛鉤程序的特殊、應用程式定義的回呼函式的指標清單。 當訊息與特定類型的攔截相關聯時,系統會將訊息傳遞至攔截鏈結中所參考的每個攔截程式,一個接一個接一個。 攔截程式可以採取的動作取決於涉及的攔截類型。 某些類型的掛勾程序只能監控訊息;而其他掛勾程序則可以修改訊息或在鏈中傳遞時阻止其進度,從而防止它們到達下一個掛勾程序或目標視窗。
掛勾程序
為了利用特定類型的攔截,開發人員會提供攔截程式,並使用 SetWindowsHookEx 函式將它安裝到與攔截相關聯的鏈結中。 攔截程序必須具有下列語法:
LRESULT CALLBACK HookProc(
int nCode,
WPARAM wParam,
LPARAM lParam
)
{
// process event
...
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
HookProc 是應用程式定義名稱的佔位符號。
nCode 參數是掛鉤程式用來判斷要執行動作的掛鉤代碼。 攔截程式代碼的值取決於攔截的類型;每個類型都有自己的攔截碼特性集。 wParam 和 lParam 參數的值取決於攔截程序代碼,但它們通常包含已傳送或張貼之訊息的相關信息。
SetWindowsHookEx 函式一律會在勾選鏈的開頭安裝勾選程序。 當有特定類型的掛鉤監視到事件發生時,系統會在與該掛鉤相關的掛鉤鏈開頭調用程式。 鏈結中的每個攔截程式都會判斷是否要將事件傳遞至下一個程式。 攔截程式會呼叫 CallNextHookEx 函式,將事件傳遞至下一個程式。
請注意,某些掛鉤類型的掛鉤程式只能監視訊息。 不論特定程式是否呼叫 CallNextHookEx,系統都會將訊息傳遞至每個攔截程式。
全域掛鉤 監視所有與呼叫線程在同一桌面的線程的訊息。 線程特定掛鉤 僅監控單一線程的訊息。 全域攔截程式可以在與呼叫線程相同的桌面上的任何應用程式內容中呼叫,因此程式必須位於個別的 DLL 模組中。 與線程相關的掛勾函式只會在所屬的線程中呼叫。 如果應用程式為自己的其中一個線程安裝攔截程式,攔截程式可以位於與應用程式程式代碼的其餘部分或 DLL 相同的模組中。 如果應用程式為不同應用程式的線程安裝攔截程式,則此程式必須位於 DLL 中。 如需詳細資訊,請參閱 Dynamic-Link 函式庫。
注意
您應該只在偵錯目的時使用全域掛勾,否則應避免使用它們。 全域攔截會損害系統效能,並導致與其他實作相同全域攔截類型的應用程式發生衝突。
掛鉤類型
每種攔截類型可讓應用程式監視系統訊息處理機制的不同層面。 下列各節說明可用的鉤子。
- WH_CALLWNDPROC 和WH_CALLWNDPROCRET
- WH_CBT
- WH_DEBUG
- WH_FOREGROUNDIDLE
- WH_GETMESSAGE
- WH_JOURNALPLAYBACK
- WH_JOURNALRECORD
- WH_KEYBOARD_LL
- WH_KEYBOARD
- WH_MOUSE_LL
- WH_MOUSE
- WH_MSGFILTER 和 WH_SYSMSGFILTER
- WH_SHELL
WH_CALLWNDPROC和WH_CALLWNDPROCRET
WH_CALLWNDPROC 和 WH_CALLWNDPROCRET 勾子可讓您監控傳送至視窗程序的訊息。 系統會先呼叫 WH_CALLWNDPROC 攔截程式,再將訊息傳遞至接收視窗程式,並在視窗程式處理訊息之後呼叫 WH_CALLWNDPROCRET 攔截程式。
WH_CALLWNDPROCRET 鉤子會將指向 CWPRETSTRUCT 結構的指標傳遞至鉤子程序。 結構包含處理訊息之視窗程序的傳回值,以及與訊息相關聯的訊息參數。 子類別化視窗不適用於進程之間設定的訊息。
如需詳細資訊,請參閱 callWndProc 和 CallWndRetProc 回呼函式。
WH_CBT
系統在啟動、建立、終結、最小化、最大化、移動或調整視窗大小之前;在完成系統命令之前;在從系統訊息隊列中移除滑鼠或鍵盤事件之前;在設定輸入焦點之前;或在與系統訊息隊列同步處理之前,會先呼叫 WH_CBT 攔截程式。 攔截程式傳回的值會決定系統是否允許或防止其中一項作業。 WH_CBT 掛勾主要用於電腦基礎訓練(CBT)應用程式。
如需詳細資訊,請參閱 CBTProc 回呼函式。
如需詳細資訊,請參閱 WinEvents。
WH_DEBUG
系統會先呼叫 WH_DEBUG 鉤掛程序,然後再呼叫與系統中其他任何鉤掛程序相關聯的程序。 您可以使用這個鉤子來判斷是否允許系統呼叫與其他類型的鉤子相關聯的鉤子程式。
如需詳細資訊,請參閱 DebugProc 回呼函式。
WH_FOREGROUNDIDLE
WH_FOREGROUNDIDLE 攔截可讓您在其前景線程閑置時執行低優先順序的工作。 當應用程式的前台執行緒即將進入空閒狀態時,系統會呼叫 WH_FOREGROUNDIDLE 掛鉤程序。
如需詳細資訊,請參閱 ForegroundIdleProc 回呼函式。
WH_GETMESSAGE
WH_GETMESSAGE 鉤子使應用程式能夠監視即將由 GetMessage 或 PeekMessage 函式傳回的訊息。 您可以使用 WH_GETMESSAGE 鉤子來監視滑鼠和鍵盤輸入,以及張貼至訊息佇列的其他訊息。
如需詳細資訊,請參閱 GetMsgProc 回呼函式。
WH_JOURNALPLAYBACK
警告
從 Windows 11 開始不再支援日誌攔截 API,並且將在未來版本中移除。 因此,我們強烈建議改為呼叫 SendInput TextInput API。
WH_JOURNALPLAYBACK 鉤子允許應用程式將訊息插入到系統訊息佇列中。 您可以使用這個掛勾,透過使用 WH_JOURNALRECORD播放一系列先前錄製的滑鼠和鍵盤事件。 只要安裝了 WH_JOURNALPLAYBACK 鉤子,就會停用一般的滑鼠和鍵盤輸入。 WH_JOURNALPLAYBACK 鉤子是全域性的鉤子,無法作為線程指定的鉤子使用。
WH_JOURNALPLAYBACK 攔截會傳回逾時值。 這個值會告知系統在處理從回放掛鉤獲得的當前訊息之前要等候多少毫秒。 這方便鉤子控制其重播事件的時機。
如需詳細資訊,請參閱 JournalPlaybackProc 回呼函式。
WH_日誌記錄
警告
從 Windows 11 開始不再支援日誌攔截 API,並且將在未來版本中移除。 因此,我們強烈建議改為呼叫 SendInput TextInput API。
WH_JOURNALRECORD 掛鉤用來監視和記錄輸入事件。 一般而言,您可以使用這個鉤子來記錄一系列的滑鼠和鍵盤事件,以便稍後使用 WH_JOURNALPLAYBACK播放。 WH_JOURNALRECORD 掛勾是全域掛勾,它不能當做執行緒特定的掛勾功能來使用。
如需詳細資訊,請參閱 JournalRecordProc 回呼函式。
WH_KEYBOARD_LL
WH_KEYBOARD_LL 鉤子允許您監視即將在線程輸入佇列中張貼的鍵盤輸入事件。
如需詳細資訊,請參閱 LowLevelKeyboardProc 回呼函式。
WH_KEYBOARD
WH_KEYBOARD 掛鉤使應用程式能夠監視即將由 GetMessage 或 PeekMessage 函數傳回的 WM_KEYDOWN 和 WM_KEYUP 訊息流量。 您可以使用 WH_KEYBOARD 掛鉤來監視發送到消息佇列的鍵盤輸入。
如需詳細資訊,請參閱 KeyboardProc 回呼函式。
WH_MOUSE_LL
WH_MOUSE_LL 攔截可讓您監視即將張貼在線程輸入佇列中的滑鼠輸入事件。
如需詳細資訊,請參閱 LowLevelMouseProc 回呼函式。
WH_MOUSE
WH_MOUSE 鉤子可讓您監視即將被 GetMessage 或 PeekMessage 函式返回的滑鼠訊息。 您可以使用 WH_MOUSE 掛鉤來監視張貼至消息佇列的滑鼠輸入。
如需詳細資訊,請參閱 MouseProc 回呼函式。
WH_MSGFILTER和WH_SYSMSGFILTER
WH_MSGFILTER 和 WH_SYSMSGFILTER 掛鉤可讓您監視功能表、滾動條、訊息框或對話框即將處理的訊息,以便偵測使用者按下 ALT+TAB 或 ALT+ESC 按鍵組合而不同視窗即將啟動。 WH_MSGFILTER 掛鉤只能監視訊息,這些訊息會被傳遞至安裝了掛鉤程序的應用程式所建立的功能表、滾動條、消息框或對話框。 WH_SYSMSGFILTER 掛鉤會監控所有應用程式的這類訊息。
WH_MSGFILTER 和 WH_SYSMSGFILTER 鉤子可以讓您在模態迴圈期間執行訊息篩選,這相當於在主要訊息迴圈中完成的篩選。 例如,應用程式通常會在從佇列擷取訊息的時間和分派訊息的時間之間,檢查主要迴圈中的新訊息,並視需要執行特殊處理。 不過,在強制回應迴圈期間,系統會擷取並分派訊息,而不允許應用程式在主要訊息循環中篩選訊息的機會。 如果應用程式安裝 WH_MSGFILTER 或 WH_SYSMSGFILTER 掛勾程式,系統會在模態循環期間呼叫該程式。
應用程式可以透過呼叫 CallMsgFilter 函式來直接呼叫 WH_MSGFILTER 勾點。 藉由使用此函式,應用程式可以在強制回應迴圈期間使用相同的程式代碼來篩選訊息,就像在主要訊息迴圈中使用的一樣。 若要這樣做,請將篩選作業封裝在 WH_MSGFILTER 攔截程式中,並在呼叫 GetMessage 和 DispatchMessage 函式之間呼叫 CallMsgFilter。
while (GetMessage(&msg, (HWND) NULL, 0, 0))
{
if (!CallMsgFilter(&qmsg, 0))
DispatchMessage(&qmsg);
}
CallMsgFilter 的最後一個自變數只會傳遞至攔截程式:您可以輸入任何值。 攔截程式藉由定義 MSGF_MAINLOOP等常數,可以使用這個值來判斷從中呼叫程式的位置。
如需詳細資訊,請參閱 MessageProc 和 SysMsgProc 回呼函式。
WH_SHELL
Shell 應用程式可以使用 WH_SHELL 鉤子來接收重要的系統通知。 系統會在外殼應用程式即將被激活,以及建立或摧毀最上層視窗時,呼叫 WH_SHELL 鉤子程序。
請注意,自定義外殼應用程式不會接收 WH_SHELL 訊息。 因此,任何將自己註冊為預設殼層的應用程式,都必須呼叫 SystemParametersInfo 函式,然後它(或任何其他應用程式)才能接收 WH_SHELL 訊息。 必須使用 SPI_SETMINIMIZEDMETRICS 和 MINIMIZEDMETRICS 結構來呼叫此函式。 將這個 結構的 iArrange 成員設定為 ARW_HIDE。
如需詳細資訊,請參閱 ShellProc 回呼函式。