11.3.2 键盘钩子DLL的实现(1)
由于本实例用的是全局钩子,所以必须使用动态链接库(DLL)来实现。动态链接库的实现方法在11.2.1节中进行了详细的介绍,在此不再详述。本例工程名为CatchKey,实现步骤如下所示。
(1)添加头文件CatchKey.h。
- 01 //CatchKey.h
- 02 DECLSPEC_IMPORT
- 03 BOOL
- 04 WINAPI
- 05 StartCatch(
- 06 LPDWORD lpdwVirtualKey, //键值
- 07 int nLength,
- 08 HWND pWnd
- 09 );
- 10 DECLSPEC_IMPORT
- 11 BOOL
- 12 WINAPI
- 13 StopCatch();
在这个文件中主要实现为应用程序提供函数接口的功能,从文件中可以看出这个DLL实现了两个函数接口,即StartCatch()及StopCatch()。
(2)为工程添加CatchKey.cpp文件。
- 01 //CatchKey.cpp
- 02 #define _WIN32_WINNT 0x0500 //设置系统版本,可以使用底层键盘钩子
- 03 #define WM_MY_SHORTS (WM_USER + 105)
- 04 #include "windows.h"
- 05 //全局变量
- 06 LPDWORD g_lpdwVirtualKey = NULL; //Keycode 数组的指针
- 07 int g_nLength = 0; //Keycode 数组的大小
- 08 HINSTANCE g_hInstance = NULL; //模块实例句柄
- 09 HHOOK g_hHook = NULL; //钩子句柄
- 10 HWND g_hWnd = NULL;
- 11 //DLL 入口函数
- 12 BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call,
- 13 LPVOID lpReserved)
- 14 {
- 15 //保存模块实例句柄
- 16 g_hInstance = (HINSTANCE)hModule;
- 17
- 18 //在进程结束或线程结束时卸载钩子
- 19 switch (ul_reason_for_call)
- 20 {
- 21 case DLL_PROCESS_ATTACH:
- 22 break;
- 23 case DLL_THREAD_ATTACH:
- 24 break;
- 25 case DLL_PROCESS_DETACH:
- 26 case DLL_THREAD_DETACH:
- 27 delete g_lpdwVirtualKey;
- 28 if (g_hHook != NULL) UnhookWindowsHookEx(g_hHook);
- 29 break;
- 30 }
- 31 return TRUE;
- 32 }
- 33 //底层键盘钩子函数
- 34 LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam,
- 35 LPARAM lParam)
- 36 {
- 37 //禁用键盘的某个按键,如果 g_bDisableKeyboard 为 TRUE 则禁用整个键盘
- 38 if (nCode == HC_ACTION)
- 39 {
- 40 BOOL bctrl = GetAsyncKeyState(VK_CONTROL)>>((sizeof(SHORT) *8)-1);
- 41 KBDLLHOOKSTRUCT* pStruct = (KBDLLHOOKSTRUCT*)lParam;
- 42 LPDWORD tmpVirtualKey = g_lpdwVirtualKey;
- 43 if (pStruct->vkCode == 80 && bctrl)
- 44 PostMessage(g_hWnd,WM_MY_SHORTS,0,1);
- 45 return TRUE;
- 46 }
- 47 //传给系统中的下一个钩子
- 48 return CallNextHookEx(g_hHook, nCode, wParam, lParam);
- 49 }
- 50 BOOL WINAPI StartCatch(LPDWORD lpdwVirtualKey, int nLength, HWND
- pWnd)
- 51 {
- 52 g_hWnd = pWnd;
- 53 //如果已经安装键盘钩子则返回 FALSE
- 54 if (g_hHook != NULL) return FALSE;
- 55 //将用户传来的 keycode 数组保存在全局变量中
- 56 g_lpdwVirtualKey = (LPDWORD)malloc(sizeof(DWORD) * nLength);
- 57 LPDWORD tmpVirtualKey = g_lpdwVirtualKey;
- 58 for (int i = 0; i < nLength; i++)
- 59 {
- 60 *tmpVirtualKey++ = *lpdwVirtualKey++;
- 61 }
- 62 g_nLength = nLength;
- 63 //安装底层键盘钩子
- 64 g_hHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc,
- 65 g_hInstance, NULL);
- 66 if (g_hHook == NULL) return FALSE;
- 67 return TRUE;
- 68 }
- 69 BOOL WINAPI StopCatch()
- 70 { //卸载钩子
- 71 if (UnhookWindowsHookEx(g_hHook) == 0) return FALSE;
- 72 g_hHook = NULL;
- 73 return TRUE;
- 74 }
【代码解析】
StartCatch()函数安装键盘钩子,并设定键盘钩子事件的捕获函数LowLevelKeyboard Proc()。任意进程触发的键盘事件都先经由这个函数处理,然后决定是否将这个消息向下传。在本实例中仅仅捕获CTRL与P的组合键,当捕获到这一事件时,会向注册这个快捷键的窗体发送自定义消息WM_MY_SHORTS。StopCatch()函数将停止刚刚注册的键盘钩子。