看了很多資料,都提到系統(tǒng)鉤子(Hook)必須是一個dll,這樣Windows才能在所有進(jìn)程中共享鉤子代碼。
與鉤子相關(guān)的3個Windows API函數(shù)是:
SetWindowsHookEx、UnhookWindowsHookEx、CallNextHookEx,它們的簡要說明如下:
idHook -- 系統(tǒng)鉤子類型,實際上是一個int值,具體的定義請看MSDN
lpfn -- 鉤子回調(diào)函數(shù)指針,當(dāng)收到鉤子消息時就執(zhí)行這個回調(diào)函數(shù),回調(diào)函數(shù)有3個參數(shù),不同類型的鉤子這3個參數(shù)有不同的含義,具體請看MSDN。
hMod -- DLL實例句柄(我猜是這樣,我不熟悉Win32API編程),當(dāng)鉤子為系統(tǒng)鉤子時這個參數(shù)是必須的,如果是單個程序或者線程使用的鉤子那么可以不用這個值。
dwThreadId -- 線程ID,如果是單個程序或者線程使用的鉤子這個參數(shù)是必須的。
SetWindowsHookEx返回所設(shè)置的鉤子的句柄。
BOOL UnhookWindowsHookEx(HHOOK hhk);
hhk -- 所要注銷的鉤子的句柄
UnhookWindowsHookEx返回注銷鉤子是否成功。
hhk -- 起始鉤子句柄,如果是在鉤子回調(diào)函數(shù)中調(diào)用CallNextHookEx時傳的通常是本鉤子句柄。
nCode -- 鉤子回調(diào)函數(shù)參數(shù)1,具體含義視鉤子類型而定。
wParam -- 鉤子回調(diào)函數(shù)參數(shù)2,具體含義視鉤子類型而定。
lParam -- 鉤子回調(diào)函數(shù)參數(shù)3,具體含義視鉤子類型而定。
從以上3個函數(shù)的簡要說明可以看出所用到的參數(shù)幾乎都是簡單的參數(shù),稍微復(fù)雜就是回調(diào)函數(shù)(在C#中用delegate類型來實現(xiàn),后面會提到),但是最讓人頭疼的就是DLL的實例句柄,C#制作的DLL并不像C做的DLL有DllMain入口可以接受到DLL實例句柄。
我目前唯一的辦法就是使用C做一個系統(tǒng)鉤子DLL再讓C#調(diào)用。底下是DLL的代碼。
然后在C#項目中創(chuàng)建一個系統(tǒng)鉤子類,提供創(chuàng)建鉤子和注銷鉤子的接口,代碼如下
上面用到的User32.HookProc類型不是.NET框架提供的,是自己定義的一個委托類型,聲明如下
現(xiàn)在你的C#程序就可以使用各種系統(tǒng)鉤子了,我們目前已經(jīng)使用的有低級別鼠標(biāo)鉤子和低級別鍵盤鉤子。
應(yīng)用低級別鼠標(biāo)鉤子時會遇到這樣一個問題:
低級別鼠標(biāo)鉤子的回調(diào)函數(shù)lParam是一個MSLLHOOKSTRUCT結(jié)構(gòu)體指針,C#中怎么獲取這個結(jié)構(gòu)體的實例呢?實現(xiàn)代碼如下
通過聲明非安全代碼來獲取指針?biāo)笇ο蟆?
MSLLHOOKSTRUCT結(jié)構(gòu)體的C#定義如下: