MFC線程鉤子和全局鉤子[HOOK DLL]
第一部分:API函數簡介
1. SetWindowsHookEx函數
函數原型
HHOOK SetWindowsHookEx(
int idHook, // hook type
HOOKPROC lpfn, // hook procedure
HINSTANCE hMod, // handle to application instance
DWORD dwThreadId // thread identifier
);
函數功能:該函數將一個應用程序定義的掛鉤處理過程安裝到掛鉤鏈中去,您可以通過安裝掛鉤處理過程來對系統的某些類型事件進行監控,這些事件與某個特定的線程或系統中的所有事件相關.具體參數詳見MSDN;
舉例:
線程鉤子:
HHOOK g_hMouse;//全局變量,保存鉤子的句柄
LRESULT CALLBACK MouseProc(
int nCode, // hook code
WPARAM wParam, // message identifier
LPARAM lParam // mouse coordinates
)
{
//……
}
g_hMouse=SetWindowsHookEx(WH_MOUSE,MouseProc,NULL,GetCurrentThreadId());
2. CallNextHookEx函數
函數原型:
LRESULT CallNextHookEx(
HHOOK hhk, // handle to current hook
int nCode, // hook code passed to hook procedure
WPARAM wParam, // value passed to hook procedure
LPARAM lParam // value passed to hook procedure
);
3. UnhookWindowsHookEx
函數原型:
BOOL UnhookWindowsHookEx(
HHOOK hhk // handle to hook procedure
);
第二部分:HOOK與DLL
1.線程鉤子的創建過程:
1. 聲明一個全局的HHOOK類型的變量,用于保存創建鉤子的句柄,如:
HHOOK g_hMouse;//全局變量,保存鉤子的句柄
2. 在應用程序的初始化函數中,安裝鉤子;注意SetWindowsHookEx的參數!
g_hMouse=SetWindowsHookEx(WH_MOUSE,MouseProc,NULL,GetCurrentThreadId());
3. 編寫處理鉤子消息的回調函數:
LRESULT CALLBACK MouseProc(
int nCode, // hook code
WPARAM wParam, // message identifier
LPARAM lParam // mouse coordinates
)
{
//編寫需要處理的部分
return 1;
//不需要處理的部分,調用
return CallNextHookEx(g_hMouse, nCode, wParam, lParam);
}
4. 卸載鉤子函數
UnhookWindowsHookEx(g_hMouse);
2.系統鉤子的創建過程:
運行機制:DLL函數中的代碼所創建的任何對象(包括變量)都歸調用它的線程或進程所有。當進程在載入DLL時,操作系統自動把DLL地址映射到該進程的私有空間,也就是進程的虛擬地址空間,而且也復制該DLL的全局數據的一份拷貝到該進程空間。也就是說每個進程所擁有的相同的DLL的全局數據,它們的名稱相同,但其值卻并不一定是相同的,而且是互不干涉的。因此,在Win32環境下要想在多個進程中共享數據,就必須進行必要的設置。在訪問同一個Dll的各進程之間共享存儲器是通過存儲器映射文件技術實現的。也可以把這些需要共享的數據分離出來,放置在一個獨立的數據段里,并把該段的屬性設置為共享。必須給這些變量賦初值,否則編譯器會把沒有賦初始值的變量放在一個叫未被初始化的數據段中。#pragma data_seg預處理指令用于設置共享數據段。例如:
#pragma data_seg("SharedDataName")
HHOOK hHook=NULL;
#pragma data_seg()
在#pragma data_seg("SharedDataName")和#pragma data_seg()之間的所有變量將被訪問該Dll的所有進程看到和共享。再加上一條指令
#pragma comment(linker,"/section:.SharedDataName,rws")
那么這個數據節中的數據可以在所有DLL的實例之間共享。所有對這些數據的操作都針對同一個實例的,而不是在每個進程的地址空間中都有一份。
系統鉤子的創建需要將鉤子的放在DLL中,因此其重建構成需要兩部分:1.編寫程序,生成Dll;2.編寫應用程序調用Dll中的函數
2.1 DLL中的代碼的編寫
方案 1:源代碼:http://download.csdn.net/detail/nuptboyzhb/4202102
1. 新建一個擴展MFC類型DLL工程;
2. 將DLL的句柄參數和要安裝鉤子的句柄聲明為共享數據:
#pragma data_seg("Titlename") //名稱任意起
HHOOK glhHook=NULL; //安裝的鼠標鉤子句柄
HINSTANCE glhInstance=NULL;//DLL實例句柄
#pragma data_seg()
注意:共享數據必須初始化,否則微軟編譯器會把沒有初始化的數據放到.BSS段中,從而導致多個進程之間的共享行為失敗。
3. 新建一個CMouseHook的導出類,用于實現鉤子的安裝和卸載
class AFX_EXT_CLASS CMouseHook:public CObject //AFX_EXT_CLASS宏聲明類為導出類
{
public:
CMouseHook();//鉤子類的構造函數
~CMouseHook();//鉤子類的析構函數
BOOL StartHook(HWND hWnd);//安裝鉤子函數
BOOL StopHook();//卸載鉤子函數
};
注意:AFX_EXT_CLASS用于聲明該類為導出類;
4. 編寫安裝鉤子,卸載鉤子,鉤子過程的函數
安裝鉤子:glhHook=SetWindowsHookEx(WH_MOUSE,MouseProc,glhInstance,0);
卸載鉤子:UnhookWindowsHookEx(glhHook);
鉤子過程:
//鼠標鉤子函數的實現
LRESULT CALLBACK MouseProc(int nCode,WPARAM wparam,LPARAM lparam)
{
LPMOUSEHOOKSTRUCT pMouseHook=(MOUSEHOOKSTRUCT FAR *) lparam;
if (nCode>=0)
{
//處理過程的代碼…..
}
return CallNextHookEx(glhHook,nCode,wparam,lparam); //繼續傳遞消息
}
2.2 主程序的調用
新建一個應用程序,將上述生成的.dll文件和.lib文件及類聲明的文件.h拷貝到當前目錄中,并在頭文件中包含生成的類聲明.h文件;靜態方式加載動態鏈接庫
#pragma comment(lib,"MousehookDll.lib") //隱式鏈接DLL
然后就可以聲明一個由DLL文件導出的類CMouseHook的一個變量;然后在應用程序的初始化函數中調用該變量的StartHook函數安裝鉤子;在需要取消鉤子的地方,調用StopHook()函數;
附錄:鉤子過程函數參數詳解
從上面的步驟中可以看到,鉤子的安裝和卸載是一個較為固定格式和步驟;真正關鍵的是:不同的鉤子類型,回調函數的參數意義不同,那我們就一一介紹各個參數的意義吧!
a. MouseProc(int nCode,WPARAM wparam,LPARAM lparam)WH_MOUSE
1.nCode 跟所有其他鉤子處理函數一樣,只要記得當 nCode小于0時:調用CallNextHookEx()就可以了。
HC_ACTION 當nCode等于HC_ACTION時,wParam和lParam 包含鼠標信息 HC_NOREMOVE 當nCode等于HC_NOREMOVE時,wParam和lParam 包含鼠標信息,并且鼠標消息沒有從消息隊列里移除
2. wParam 指定鼠標消息ID
3. lParam 一個MOUSEHOOKSTRUCT 結構的指針
typedef struct tagMOUSEHOOKSTRUCT {
POINT pt; //保存鼠標在屏幕上的x,y坐標
HWND hwnd; //接收到鼠標消息的窗口的句柄
UINT wHitTestCode; //詳細描述參見WM_NCHITTEST消息
ULONG_PTR dwExtraInfo; //指定與本消息聯系的額外消息
} MOUSEHOOKSTRUCT, *PMOUSEHOOKSTRUCT;
b. KeyboardProc(int nCode,WPARAM wparam,LPARAM lparam) WH_KEYBOARD
2.wParam:按鍵的虛擬鍵值消息,例如:VK_F1 VK_F2 等;
3. lParam:32位內存,內容描述包括:指定擴展鍵值,掃描碼,上下文,重復次數。
0-15位:描述:按下鍵盤次數。
16-23位:指定掃描碼. 依賴于OEM
24位:當24位為1時候:表示按鍵是擴展鍵;當24位為0時候:表示按鍵是數字鍵盤按鍵
25-28位:保留位
29位:上下文鍵:為1時: ALT按下,其他情況為0
30位:如果是按鍵按下后發送的消息,30位為0,如果是按鍵抬起后30位為1;
31位:指定轉變狀態;31位為0時候,按鍵正在被按下,為1時候,按鍵正在被釋放
c. GetMsgProc(int nCode,WPARAM wparam,LPARAM lparam) WH_GETMESSAGE
2.wParam:標明消息是否從消息對列中取出,它有如下兩個值:
PM_NOREMOVE:未從消息隊列中取出
PM_REMOVE:已經從消息隊列中取出
3. lParam: 它是指向MSG結構體的一個指針
typedef struct tagMSG {
HWND hwnd; //接收消息的窗口句柄
UINT message; //消息的標識,如WM_CLOSE等
WPARAM wParam;// 指定消息的附加信息
LPARAM lParam; // 不同的消息不一樣;
DWORD time; //消息投遞到消息隊列中的時間
POINT pt; //消息投遞到消息隊列中時的鼠標位置(屏幕坐標)
} MSG, *PMSG;
d. 未完待續…
RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成