SetWindowsHookEx
將應用程序定義的鉤子過程安裝到鉤子鏈中.您將安裝一個掛鉤程序來監視系統的某些類型的事件.這些事件與特定線程或與調用線程在同一桌面中的所有線程相關聯.
函數聲明
HHOOK WINAPI SetWindowsHookEx(
_In_ int idHook,
_In_ HOOKPROC lpfn,
_In_ HINSTANCE hMod,
_In_ DWORD dwThreadId
);
參數1:要安裝的掛鉤程序的類型
參數2:指向掛鉤過程的指針.如果參數4為0或不是當前進程的線程ID,則參數必須指向DLL中的函數過程.否則,可以指向當前的函數過程(除了低級消息鉤子).
參數3:指向DLL句柄,如果參數4指向的是當前進程的線程,且過程函數也在當前進程關聯的代碼內容,則必須設置為NULL.
參數4:要掛鉤的線程ID,如果為0,則掛鉤所有線程(同一桌面).
返回:如果函數成功,則返回掛鉤線程的句柄.如果函數失敗,返回值為NULL.要獲取擴展錯誤信息,請調用GetLastError.
說明:SetWindowsHookEx可以用于將DLL注入到另一個進程中。 32位DLL不能被注入到64位進程中,64位DLL不能被注入到32位進程中。 如果應用程序需要在其他進程中使用掛鉤,則需要32位應用程序調用SetWindowsHookEx將32位DLL注入32位進程,64位應用程序調用SetWindowsHookEx來注入64位 DLL進入64位進程。 32位和64位DLL必須具有不同的名稱。
因為鉤子在應用程序的上下文中運行,所以它們必須與應用程序的“位置”匹配。 如果32位應用程序在64位Windows上安裝全局鉤子,則將32位鉤子注入每個32位進程(通常的安全邊界)。 在64位進程中,線程仍被標記為“掛鉤”。 但是,由于32位應用程序必須運行鉤子代碼,系統會在掛鉤應用程序的上下文中執行鉤子; 具體來說,在調用SetWindowsHookEx的線程上。 這意味著掛鉤應用程序必須消息循環,否則可能會阻止64位進程的正常運行。
如果64位應用程序在64位Windows上安裝全局鉤子,則將64位鉤子注入到每個64位進程中,而所有32位進程都對掛鉤應用程序使用回調。
要將所有應用程序掛在64位Windows安裝的桌面上,從適當的進程安裝一個32位全局鉤子和一個64位全局鉤子,并確保在掛鉤應用程序中不斷地發送消息,以避免阻塞正常功能。如果您已經有32位全局掛鉤應用程序,并且不需要在每個應用程序上下文中運行,則不需要創建64位版本。
如果hMod參數為NULL并且dwThreadId參數為零或指定由另一進程創建的線程的標識符,則可能會發生錯誤。
調用CallNextHookEx函數鏈接到下一個鉤子過程是可選的,但強烈建議; 否則,已安裝鉤子的其他應用程序將不會收到鉤子通知,因此可能會出現錯誤的行為。 您應該調用CallNextHookEx,除非您絕對需要防止其他應用程序看到通知。
在終止之前,應用程序必須調用UnhookWindowsHookEx函數來釋放與該鉤子關聯的系統資源。
掛鉤的范圍取決于掛鉤類型。 一些掛鉤只能用全局范圍設置; 其他的也可以只設置一個特定的線程,如下表所示。
掛鉤 范圍
WH_CALLWNDPROC 線程或全局
WH_CALLWNDPROCRET 線程或全局
WH_CBT 線程或全局
WH_DEBUG 線程或全局
WH_FOREGROUNDIDLE 線程或全局
WH_GETMESSAGE 線程或全局
WH_JOURNALPLAYBACK 全局
WH_JOURNALRECORD 全局
WH_KEYBOARD 線程或全局
WH_KEYBOARD_LL 全局
WH_MOUSE 線程或全局
WH_MOUSE_LL 全局
WH_MSGFILTER 線程或全局
WH_SHELL 線程或全局
WH_SYSMSGFILTER 全局
對于指定的鉤子類型,首先調用線程鉤子,然后調用全局鉤子。請注意,在安裝鉤子的線程上,而不是線程處理鉤子,可以調用WH_MOUSE,WH_KEYBOARD,WH_JOURNAL *,WH_SHELL和低級鉤子。對于這些鉤子,如果一個32位鉤子在鉤鏈中的64位鉤子的前面,則可能會調用32位和64位鉤子。
全局鉤子是一個共享資源,安裝程序會影響與調用線程相同的桌面中的所有應用程序。所有全局鉤子函數都必須在庫中。全局鉤子應該限于專用應用程序或在應用程序調試期間用作開發幫助。不再需要鉤子的庫應該刪除其掛鉤過程。
Windows Store應用程序開發如果dwThreadId為零,則Windows Store應用程序進程和Windows Runtime代理進程的窗口掛鉤DLL未被加載,除非它們由UIAccess進程(輔助工具)安裝。該通知在安裝程序的線程上提供了這些鉤子:
WH_JOURNALPLAYBACK
WH_JOURNALRECORD
WH_KEYBOARD
WH_KEYBOARD_LL
WH_MOUSE
WH_MOUSE_LL
這種行為類似于鉤子DLL和目標應用程序進程之間的架構不匹配時發生的情況,例如,當鉤子DLL為32位,應用程序進程為64位時。
您可以通過調用UnhookWindowsHookEx函數來釋放特定于線程的鉤子過程(從鉤鏈中刪除其地址),指定要釋放的掛鉤過程的句柄。一旦您的應用程序不再需要,就釋放一個掛鉤程序。
您可以使用UnhookWindowsHookEx發布全局鉤子過程,但是此函數不會釋放包含掛鉤過程的DLL。這是因為在桌面中的每個應用程序的進程上下文中調用全局鉤子過程,導致對所有這些進程的LoadLibrary函數進行隱式調用。因為不能為另一個進程調用FreeLibrary函數,所以沒有辦法釋放DLL。所有進程明確鏈接到DLL的程序終止或調用FreeLibrary后,系統最終釋放DLL,所有調用hook過程的進程都已經在DLL外部恢復處理。
安裝全局掛鉤過程的另一種方法是在DLL中提供一個安裝功能以及掛鉤過程。使用這種方法,安裝應用程序不需要DLL模塊的句柄。通過與DLL鏈接,應用程序可以訪問安裝功能。安裝功能可以在調用SetWindowsHookEx時提供DLL模塊句柄和其他細節。該DLL還可以包含一個釋放全局掛鉤過程的函數;當終止時,應用程序可以調用這個掛鉤釋放功能。
監控系統事件
以下示例使用各種線程特定的鉤子過程來監視系統對影響線程的事件。 它演示了如何處理以下類型的鉤子過程的事件:
WH_CALLWNDPROC
WH_CBT
WH_DEBUG
WH_GETMESSAGE
WH_KEYBOARD
WH_MOUSE
WH_MSGFILTER
用戶可以使用菜單安裝和刪除掛鉤過程。 當安裝掛鉤過程并發生由過程監視的事件時,該過程將有關事件的信息寫入應用程序主窗口的客戶端區域。