首先來說說windows 消息Hook,這個消息Hook就是我們常用的通過SetWindowsHookEx來設置一個Hook,這個函數通過將這個Hook插入到Hook鏈的最前端,而發送給我們已經Hook了的窗口的消息首先會被我們的Hook函數截獲,也就是我們優先於窗體捕獲到消息。
Windows Message Hook 可以實現全局Hook和局部Hook。局部Hook是在自身進程中創建一個Hook,可以用來捕獲自身進程中的消息;而全局Hook是可以捕獲操作系統下所有的指定的消息,需要借助於DLL來實現。全局鈎子必須要使用DLL,DLl存放了鈎子函數的代碼。在操作系統中安裝了全局鈎子后,只要進程收到可以發出鈎子的消息后,全局鈎子的DLl文件會被操作系統自動或強行地加載到該進程中。可以發現設置消息鈎子也是一種導入DLl的方法。
一.鈎子函數:
其實鈎子函數也就3個:
(1)設置鈎子:SetWindowsHookEx
(2)釋放鈎子:UnhookWindowsHookEx
(3)繼續鈎子:CallNextHookEx
在線程級的鈎子中經常用到 GetCurrentThreadID 函數來獲取當前線程的 ID
1. SetWindowsHookEx
HHOOK SetWindowsHookEx(
int idHook, // hook type(鈎子類型,即它處理的消息類型)
HOOKPROC lpfn, // hook procedure(回調函數的地址)
HINSTANCE hMod, // handle to application instance(實例句柄,標識包含lpfn所指的子程的DLL)
DWORD dwThreadId // thread identifier(線程ID)
);
第一個參數為鈎子的類型,鈎子的類型一共還有14種,表示在什么時機調用鈎子。下面會介紹。
第二個參數為鈎子的子程,實際上就是一個回調函數的地址,當相應的事件發生時系統就會調用這個回調函數。
第三個參數為這個鈎子綁定的進程的實例句柄,即包含回調函數的DLL的實例句柄,如果dwThreadId 標識當前進程創建的一個線程,而且子程代碼位於當前進程,hMod必須為NULL。 可以很簡單的設定其為本應用程序的實例句柄。
第四個參數為線程的ID,若為全局鈎子這個參數設置為0,若是線程鈎子可以使用GetCurrentThreadId來獲得當前線程的ID
返回值:若調用成功,返回的是這個鈎子過程的句柄;否則返回NULL
2.UnhookWindowsHookEx
鈎子在使用完之后需要用UnhookWindowsHookEx()卸載,否則會造成麻煩。釋放鈎子比較簡單,[1]()只有一個參數。函數原型如下:
UnhookWindowsHookEx( HHOOK hhk );
函數成功返回TRUE,否則返回FALSE。
3.CallNextHookEx
在鈎子子程中調用得到控制權的鈎子函數在完成對消息的處理后,如果想要該消息繼續傳遞,那么它必須調用另外一個 SDK中的API函數CallNextHookEx來傳遞它,以執行鈎子鏈表所指的下一個鈎子子程。這個函數成功時返回鈎子鏈中下一個鈎子過程的返回值, 返回值的類型依賴於鈎子的類型。
LRESULT CallNextHookEx
(
HHOOK hhk;
int nCode;
WPARAM wParam;
LPARAM lParam;
);
hhk為當前鈎子的句柄,由SetWindowsHookEx()函數返回。
NCode為傳給鈎子過程的事件代碼。
wParam和lParam 分別是傳給鈎子子程的wParam值,其具體含義與鈎子類型有關。
鈎子函數也可以通過直接返回TRUE來丟棄該消息,並阻止該消息的傳遞。否則的話,其他安裝了鈎子的應用程序將不會接收到鈎子的通知而且還有可能產生不正確的結果。