對於HOOK函式的一點認識

youhello發表於2007-11-26
種函式是Windows訊息處理機制的一部分,透過設定“鉤子”,應用程式可以在系統級對所有訊息、事件進行過濾,訪問在正常情況下無法訪問的訊息。當然,這麼做也是需要付出一定的代價的。由於多了這麼一道處理過程,系統效能會受到一定的影響,所以大家在必要的時候才使用“鉤子”,並在使用完畢及時將其刪除。[@more@]首先讓我們看看HOOK函式是怎麼安裝、呼叫和刪除的。應用程式通常是呼叫SetWindowsHookEx()函式來進行安裝的,其函式的原型如下:

SetWindowsHookEx(

Int idHook;

HOOKPROC lpfn;

HINSTANCE hMod;

DWORD dwThreadId;

);

引數說明:

idHook 是”鉤子”的型別,”鉤子”的型別一共有13種,具體如下表:

“鉤子”型別
解釋

WH_CALLWNDPROC
系統將訊息傳送到指定視窗之前的“鉤子”

WH_CALLWNDPROCRET
訊息已經在視窗中處理的“鉤子”

WH_CBT
基於計算機培訓的“鉤子”

WH_DEBUG
差錯“鉤子”

WH_FOREGROUNDIDLE
前臺空閒視窗“鉤子”

WH_GETMESSAGE
接收訊息投遞的“鉤子”

WH_JOURNALPLAYBACK
回放以前透過WH_JOURNALRECORD“鉤子”記錄的輸入訊息

WH_JOURNALRECORD
輸入訊息記錄“鉤子”

WH_KEYBOARD
鍵盤訊息“鉤子”

WH_MOUSE
滑鼠訊息“鉤子”

WH_MSGFILTER
對話方塊、訊息框、選單或捲軸輸入訊息“鉤子”

WH_SHELL
外殼“鉤子”

WH_SYSMSGFILTER
系統訊息“鉤子”


lpfn 指向“鉤子”過程的指標。

hMod “鉤子”過程所在模組的控制程式碼。

dwThreadId “鉤子”相關執行緒的標識。

  通常我們都是把”鉤子”做成動態連結庫,這樣的好處是可以是系統內的每個程式訪問。但是也可以在系統中直接呼叫,我的建議還是用動態庫。如果用動態庫的話,那麼SetWindowsHookEx()中的第三個引數就是該動態連結庫模組的控制程式碼;對於一個只供單個程式訪問的”鉤子”,可以將其”鉤子”過程放在安裝”鉤子”的同一個執行緒內,此時SetWindowsHookEx()中的第三個引數為該執行緒的hInstance。安裝”鉤子”有兩種方法:1.你可以把他做成動態連線庫檔案,和程式一起編譯。2.你可以在程式的任何地方直接呼叫。第2種的方法太麻煩,我不建議用,在這裡我就不詳細介紹啦。相比之下第1種比較簡單。其”鉤子”的過程都在動態連結庫內完成。SetWindowsHookEx()函式是一個安裝函式,如故一個由某種型別的”鉤子”監視的事件發生,系統就會呼叫相應型別的”鉤子”鏈開始處的”鉤子”過程,”鉤子”鏈的每個”鉤子”過程都要考慮是否把事件傳遞給下一個”鉤子”過程。如果要傳遞的話,就要呼叫CallNestHookEx()函式。這個函式成功時返回”鉤子”鏈中下一個”鉤子”過程的返回值,返回值的型別依賴於”鉤子”的型別。這個函式的原型如下:

LRESULT CallNextHookEx(

HHOOK hhk;

int nCode;

WPARAM wParam;

LPARAM lParam;

);

  其中hhk為當前”鉤子”的控制程式碼,由SetWindowsHookEx()函式返回。NCode為傳給”鉤子”過程的事件程式碼。wParam和lParam 分別是傳給”鉤子”過程的wParam值,其具體含義與”鉤子”型別有關。

釋放”鉤子”

  釋放”鉤子”比較簡單,他只有一個引數。當不在需要”鉤子”時,應及時將其釋放。他是呼叫UnhookWindowsHookEx()函式來實現的,函式原型如下:

UnhookWindowsHookEx(

HHOOK hhk;

);

函式成功返回TRUE,否則返回FALSE。

如果我這樣講您還是不明白的話,請看下面給出的一些典型“鉤子”程式碼和說明。

LRESULT WINAPI CallWndProc(int nCode,WPARAM wParam,LPARAM lParam)

{

if(nCode<0)

return CallNextHookEx(NULL,nCode,wParam,lParam);

switch(nCode)

{

case HC_ACTION:

//”鉤子”程式要處理什麼的程式碼

break;

default:

break;

}

return CallNextHookEx(NULL,nCode,wParam,lParam);

}

  這是WH_CALLWNDPROC”鉤子”的程式碼,此”鉤子”允許程式監視由函式SendMessage傳送給視窗過程的訊息。系統將訊息傳送到目的視窗之前呼叫WH_CALLWNDPROC “鉤子”過程。

LRESULT WINAPI CallwndProc(int nCode,WPARAM,wParam,LPARAM lParam)

{

if(nCode<0) return callNextHookEx(NULL,nCode,wParam,lParam);

switch(nCode)

{

case HC_ACTION:

switch(wParam)

{

Case PM_REMOVE:

//某個應用程式呼叫了GetMessage函式或者是帶PM_REMOVE引數的//PeekMessage函式,從訊息佇列中移去一個訊息。

Break;

Case PM_NOREMOVE:

//某個應用程式以PM_NOREMOVE為引數呼叫PeekMessage函式

break;

default:

break;

}

break;

default:

break;

}

return CallNextHookEx(NULL,nCode,wParam,lParam);

}

  這是呼叫WH_GETMESSAGE的函式,此函式允許應用程式監視函式GetMessage和 PeekMessage返回的訊息。應用程式可以用鉤子WH_GETMESSAGE來監視滑鼠和鍵盤的輸入以及其他系統傳送到訊息佇列中的訊息。

LRESULT CALLBACK CBTProc(int nCode,WPARAM wParam,LPARAM lParam)

{

If(nCode<0) Return callNextHookEx(NULL,nCode,wParam,lParam);

Switch(nCode)

{

case HCBT_ACTIVATE:

//系統將啟用一個視窗

break;

case HCBT_CLICKSKIPPED:

//系統從系統訊息佇列中移去一個滑鼠訊息

break;

case HCBT_CREATEWND:

//系統將建立一個視窗

break;

case HCBT_DESTROYWND:

//系統將關閉一個視窗

break;

case HCBT_KEYSKIPPED:

//系統從系統訊息佇列中移去一個鍵盤訊息

break;

case HCBT_MINMAX:

//系統將最大化或最小化一個視窗

break;

case HCBT_MOVESIZE:

//系統將移動一個視窗或改變一個視窗的大小

break;

case HCBT_QS:

//系統在系統訊息佇列中檢索到WM_QUEUESYNC訊息

break;

case HCBT_SETFOCUS:

//系統設定鍵盤輸入視窗

break;

case HCBT_SYSCOMMAND:

//將要執行一個系統命令

break;

default:

//可以新增其他程式碼

break;

}

return CallNextHookEx(NULL,nCode,wParam,lParam);

}

  每種”鉤子”型別都有其對應的函式,這些函式的引數都是一樣的,有興趣的朋友可以在MSDN中找的他們的詳細說明。

下面我給出一個完整的”鉤子”安裝和刪除的過程的程式碼。

#include "stdafx.h"

#include "hook.h"

HINSTANCE hInstance;

HHOOK hhkKeyboard;

BOOL APIENTRY DllMain( HANDLE hModule,DWORD ul_reason_for_call, LPVOID lpReserved)

{

switch (ul_reason_for_call)

{

case DLL_PROCESS_ATTACH:

case DLL_THREAD_ATTACH:

case DLL_THREAD_DETACH:

case DLL_PROCESS_DETACH:

break;

}

hInstance=(HINSTANCE)hModule;

return TRUE;

}

LRESULT KeyboardProc(int nCode,WPARAM wParam,LPARAM lParam)

{

MessageBeep(-1);

return CallNextHookEx(NULL,nCode,wParam,lParam);

}

HOOK_API BOOL EnableKeyboardCapture()

{

if(!(hhkKeyboard=SetWindowsHookEx(WH_KEYBOARD,(HOOKPROC)KeyboardProc,hInstance,0)))

return FALSE;

return TRUE;

}

HOOK_API BOOL DisableKeyboardCapture()

{

return UnhookWindowsHookEx(hhkKeyboard);

}

注意:這是一個動態連結庫檔案。

在程式中要想呼叫“鉤子”的時候,有EnableKeyboardCapture()函式就可以啦,但你按鍵的時候就回發出聲音。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/79126/viewspace-984983/,如需轉載,請註明出處,否則將追究法律責任。

相關文章