SetWindowsHookEx
將應(yīng)用程序定義的鉤子過程安裝到鉤子鏈中.您將安裝一個(gè)掛鉤程序來監(jiān)視系統(tǒng)的某些類型的事件.這些事件與特定線程或與調(diào)用線程在同一桌面中的所有線程相關(guān)聯(lián).
函數(shù)聲明
HHOOK WINAPI SetWindowsHookEx(
_In_ int idHook,
_In_ HOOKPROC lpfn,
_In_ HINSTANCE hMod,
_In_ DWORD dwThreadId
);
參數(shù)1:要安裝的掛鉤程序的類型
參數(shù)2:指向掛鉤過程的指針.如果參數(shù)4為0或不是當(dāng)前進(jìn)程的線程ID,則參數(shù)必須指向DLL中的函數(shù)過程.否則,可以指向當(dāng)前的函數(shù)過程(除了低級(jí)消息鉤子).
參數(shù)3:指向DLL句柄,如果參數(shù)4指向的是當(dāng)前進(jìn)程的線程,且過程函數(shù)也在當(dāng)前進(jìn)程關(guān)聯(lián)的代碼內(nèi)容,則必須設(shè)置為NULL.
參數(shù)4:要掛鉤的線程ID,如果為0,則掛鉤所有線程(同一桌面).
返回:如果函數(shù)成功,則返回掛鉤線程的句柄.如果函數(shù)失敗,返回值為NULL.要獲取擴(kuò)展錯(cuò)誤信息,請(qǐng)調(diào)用GetLastError.
說明:SetWindowsHookEx可以用于將DLL注入到另一個(gè)進(jìn)程中。 32位DLL不能被注入到64位進(jìn)程中薄料,64位DLL不能被注入到32位進(jìn)程中敞贡。 如果應(yīng)用程序需要在其他進(jìn)程中使用掛鉤,則需要32位應(yīng)用程序調(diào)用SetWindowsHookEx將32位DLL注入32位進(jìn)程摄职,64位應(yīng)用程序調(diào)用SetWindowsHookEx來注入64位 DLL進(jìn)入64位進(jìn)程誊役。 32位和64位DLL必須具有不同的名稱虑稼。
因?yàn)殂^子在應(yīng)用程序的上下文中運(yùn)行,所以它們必須與應(yīng)用程序的“位置”匹配势木。 如果32位應(yīng)用程序在64位Windows上安裝全局鉤子蛛倦,則將32位鉤子注入每個(gè)32位進(jìn)程(通常的安全邊界)。 在64位進(jìn)程中啦桌,線程仍被標(biāo)記為“掛鉤”溯壶。 但是,由于32位應(yīng)用程序必須運(yùn)行鉤子代碼甫男,系統(tǒng)會(huì)在掛鉤應(yīng)用程序的上下文中執(zhí)行鉤子; 具體來說且改,在調(diào)用SetWindowsHookEx的線程上。 這意味著掛鉤應(yīng)用程序必須消息循環(huán)板驳,否則可能會(huì)阻止64位進(jìn)程的正常運(yùn)行又跛。
如果64位應(yīng)用程序在64位Windows上安裝全局鉤子,則將64位鉤子注入到每個(gè)64位進(jìn)程中若治,而所有32位進(jìn)程都對(duì)掛鉤應(yīng)用程序使用回調(diào)慨蓝。
要將所有應(yīng)用程序掛在64位Windows安裝的桌面上,從適當(dāng)?shù)倪M(jìn)程安裝一個(gè)32位全局鉤子和一個(gè)64位全局鉤子端幼,并確保在掛鉤應(yīng)用程序中不斷地發(fā)送消息礼烈,以避免阻塞正常功能。如果您已經(jīng)有32位全局掛鉤應(yīng)用程序婆跑,并且不需要在每個(gè)應(yīng)用程序上下文中運(yùn)行此熬,則不需要?jiǎng)?chuàng)建64位版本。
如果hMod參數(shù)為NULL并且dwThreadId參數(shù)為零或指定由另一進(jìn)程創(chuàng)建的線程的標(biāo)識(shí)符滑进,則可能會(huì)發(fā)生錯(cuò)誤犀忱。
調(diào)用CallNextHookEx函數(shù)鏈接到下一個(gè)鉤子過程是可選的,但強(qiáng)烈建議; 否則扶关,已安裝鉤子的其他應(yīng)用程序?qū)⒉粫?huì)收到鉤子通知阴汇,因此可能會(huì)出現(xiàn)錯(cuò)誤的行為。 您應(yīng)該調(diào)用CallNextHookEx驮审,除非您絕對(duì)需要防止其他應(yīng)用程序看到通知鲫寄。
在終止之前,應(yīng)用程序必須調(diào)用UnhookWindowsHookEx函數(shù)來釋放與該鉤子關(guān)聯(lián)的系統(tǒng)資源疯淫。
掛鉤的范圍取決于掛鉤類型地来。 一些掛鉤只能用全局范圍設(shè)置; 其他的也可以只設(shè)置一個(gè)特定的線程,如下表所示熙掺。
掛鉤 范圍
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 全局
對(duì)于指定的鉤子類型未斑,首先調(diào)用線程鉤子,然后調(diào)用全局鉤子币绩。請(qǐng)注意蜡秽,在安裝鉤子的線程上府阀,而不是線程處理鉤子,可以調(diào)用WH_MOUSE芽突,WH_KEYBOARD试浙,WH_JOURNAL *,WH_SHELL和低級(jí)鉤子寞蚌。對(duì)于這些鉤子田巴,如果一個(gè)32位鉤子在鉤鏈中的64位鉤子的前面,則可能會(huì)調(diào)用32位和64位鉤子挟秤。
全局鉤子是一個(gè)共享資源壹哺,安裝程序會(huì)影響與調(diào)用線程相同的桌面中的所有應(yīng)用程序。所有全局鉤子函數(shù)都必須在庫中艘刚。全局鉤子應(yīng)該限于專用應(yīng)用程序或在應(yīng)用程序調(diào)試期間用作開發(fā)幫助管宵。不再需要鉤子的庫應(yīng)該刪除其掛鉤過程。
Windows Store應(yīng)用程序開發(fā)如果dwThreadId為零攀甚,則Windows Store應(yīng)用程序進(jìn)程和Windows Runtime代理進(jìn)程的窗口掛鉤DLL未被加載箩朴,除非它們由UIAccess進(jìn)程(輔助工具)安裝。該通知在安裝程序的線程上提供了這些鉤子:
WH_JOURNALPLAYBACK
WH_JOURNALRECORD
WH_KEYBOARD
WH_KEYBOARD_LL
WH_MOUSE
WH_MOUSE_LL
這種行為類似于鉤子DLL和目標(biāo)應(yīng)用程序進(jìn)程之間的架構(gòu)不匹配時(shí)發(fā)生的情況云稚,例如隧饼,當(dāng)鉤子DLL為32位沈堡,應(yīng)用程序進(jìn)程為64位時(shí)静陈。
您可以通過調(diào)用UnhookWindowsHookEx函數(shù)來釋放特定于線程的鉤子過程(從鉤鏈中刪除其地址),指定要釋放的掛鉤過程的句柄诞丽。一旦您的應(yīng)用程序不再需要鲸拥,就釋放一個(gè)掛鉤程序。
您可以使用UnhookWindowsHookEx發(fā)布全局鉤子過程僧免,但是此函數(shù)不會(huì)釋放包含掛鉤過程的DLL刑赶。這是因?yàn)樵谧烂嬷械拿總€(gè)應(yīng)用程序的進(jìn)程上下文中調(diào)用全局鉤子過程,導(dǎo)致對(duì)所有這些進(jìn)程的LoadLibrary函數(shù)進(jìn)行隱式調(diào)用懂衩。因?yàn)椴荒転榱硪粋€(gè)進(jìn)程調(diào)用FreeLibrary函數(shù)撞叨,所以沒有辦法釋放DLL。所有進(jìn)程明確鏈接到DLL的程序終止或調(diào)用FreeLibrary后浊洞,系統(tǒng)最終釋放DLL牵敷,所有調(diào)用hook過程的進(jìn)程都已經(jīng)在DLL外部恢復(fù)處理。
安裝全局掛鉤過程的另一種方法是在DLL中提供一個(gè)安裝功能以及掛鉤過程法希。使用這種方法枷餐,安裝應(yīng)用程序不需要DLL模塊的句柄。通過與DLL鏈接苫亦,應(yīng)用程序可以訪問安裝功能毛肋。安裝功能可以在調(diào)用SetWindowsHookEx時(shí)提供DLL模塊句柄和其他細(xì)節(jié)怨咪。該DLL還可以包含一個(gè)釋放全局掛鉤過程的函數(shù);當(dāng)終止時(shí),應(yīng)用程序可以調(diào)用這個(gè)掛鉤釋放功能润匙。
監(jiān)控系統(tǒng)事件
以下示例使用各種線程特定的鉤子過程來監(jiān)視系統(tǒng)對(duì)影響線程的事件诗眨。 它演示了如何處理以下類型的鉤子過程的事件:
WH_CALLWNDPROC
WH_CBT
WH_DEBUG
WH_GETMESSAGE
WH_KEYBOARD
WH_MOUSE
WH_MSGFILTER
用戶可以使用菜單安裝和刪除掛鉤過程。 當(dāng)安裝掛鉤過程并發(fā)生由過程監(jiān)視的事件時(shí)孕讳,該過程將有關(guān)事件的信息寫入應(yīng)用程序主窗口的客戶端區(qū)域辽话。