EVC编程点滴四 - 钩子
wince下支持三种钩子:
1.#define WH_JOURNALRECORD 0使应用程序可以监视输入事件。典型地,应用程序使用该HOOK记录鼠标、键盘输入事件以供以后回放。该HOOK是全局HOOK,并且不能在指定线程中使用。
2.#define WH_JOURNALPLAYBACK 1使应用程序可以向系统消息队列中插入消息。该HOOK可以回放以前由WH_JOURNALRECORD HOOK录制的鼠标、键盘输入事件。在WH_JOURNALPLAYBACK Hook安装到系统时,鼠标、键盘输入事件将被屏蔽。该HOOK同样是一个全局HOOK,不能在指定线程中使用。
WH_JOURNALPLAYBACK Hook返回一个时间暂停值,它告诉系统,在处理当前回放的消息时,系统等待百分之几秒。这使得此HOOK可以控制在回放时的时间事件
3.#define WH_KEYBOARD_LL 20
其中最常用的是键盘钩子,其它两个偶没有用过。
1. 设置钩子 通过SetWindowsHookEx ()函数。
2. 释放钩子 UnhookWindowsHookEx()函数。
3. 钩子进程 函数HookProc。
4. 调用下一个钩子函数 CallNexHookEx()函数。
钩子的建立
1. 建立一个动态连接库的.cpp文件。
1 // KeyBoardHook.cpp : Defines the entry point for the DLL application. 2 // 3 4 #include "stdafx.h" 5 #include "KeyBoardHook.h" 6 #include <Pwinuser.h> 7 #include "BasalMessage.h" 8 //#include "FileManage.h" 9 10 //告诉编译器将变量放入它自己的数据共享节中 11 #pragma data_seg("KeyHookData") 12 HINSTANCE hInst = NULL; 13 #pragma data_seg() 14 15 //告诉编译器设置共享节的访问方式为:读,写,共享 16 #pragma comment(linker, "/SECTION:KeyHookData,RWS") 17 18 BOOL APIENTRY DllMain( HANDLE hModule, 19 DWORD ul_reason_for_call, 20 LPVOID lpReserved 21 ) 22 { 23 switch (ul_reason_for_call) 24 { 25 case DLL_PROCESS_ATTACH: 26 hInst = (HINSTANCE)hModule; 27 break; 28 case DLL_THREAD_ATTACH: 29 case DLL_THREAD_DETACH: 30 case DLL_PROCESS_DETACH: 31 break; 32 } 33 return TRUE; 34 } 35 36 37 // This is an example of an exported variable 38 KEYBOARDHOOK_API int nKeyBoardHook=0; 39 40 // This is an example of an exported function. 41 KEYBOARDHOOK_API int fnKeyBoardHook(void) 42 { 43 return 42; 44 } 45 46 // This is the constructor of a class that has been exported. 47 // see KeyBoardHook.h for the class definition 48 CKeyBoardHook::CKeyBoardHook() 49 { 50 return; 51 } 52 53 extern "C" KEYBOARDHOOK_API void InstallHook(void) 54 { 55 if (hInst) 56 { 57 hKeyHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyBoardProc, hInst, 0); 58 } 59 } 60 61 extern "C" KEYBOARDHOOK_API void UnHook(void) 62 { 63 if (hKeyHook) 64 { 65 UnhookWindowsHookEx(hKeyHook); 66 hKeyHook = NULL; 67 } 68 69 hInst = NULL; 70 } 71 72 extern "C" KEYBOARDHOOK_API LRESULT CALLBACK KeyBoardProc(int nCode, WPARAM wParam, LPARAM lParam) 73 { 74 TCHAR t_WndClassName[50] = { 0 }; 75 HWND hCurActiveWnd = NULL; 76 HWND hCurForegroundWnd = NULL; 77 BOOL bIsTaskBarMsg = FALSE; 78 BOOL bIsOEMmsg = FALSE; 79 80 PKBDLLHOOKSTRUCT pkbhs = (PKBDLLHOOKSTRUCT)lParam; 81 82 if (WM_KEYDOWN == wParam) 83 { 84 uCount++; 85 RETAILMSG(1, (TEXT("WM_KEYDOWN vk %d /r/n"),pkbhs->vkCode)); 86 //响应按键声,并限制需要向上Post的vkCode 87 switch (pkbhs->vkCode) 88 { 89 case VK_UP: 90 break; 91 case VK_DOWN: 92 break; 93 case VK_LEFT: 94 break; 95 case VK_RIGHT: 96 break; 97 case VK_OEM_SELECT: 98 bIsOEMmsg = TRUE; 99 break; 100 case VK_OEM_OK: 101 bIsOEMmsg = TRUE; 102 break; 103 case VK_OEM_BACK: 104 bIsOEMmsg = TRUE; 105 break; 106 case VK_OEM_DIAL: 107 bIsOEMmsg = TRUE; 108 break; 109 case VK_NUMPAD1: 110 case 0x31: 111 break; 112 case VK_NUMPAD2: 113 case 0x32: 114 break; 115 case VK_NUMPAD3: 116 case 0x33: 117 break; 118 case VK_NUMPAD4: 119 case 0x34: 120 break; 121 case VK_NUMPAD5: 122 case 0x35: 123 break; 124 case VK_NUMPAD6: 125 case 0x36: 126 break; 127 case VK_NUMPAD7: 128 case 0x37: 129 break; 130 case VK_NUMPAD8: 131 case 0x38: 132 break; 133 case VK_NUMPAD9: 134 case 0x39: 135 break; 136 case VK_NUMPAD0: 137 case 0x30: 138 break; 139 case VK_OEM_ASTERISK: 140 bIsOEMmsg = TRUE; 141 break; 142 case VK_OEM_POUND: 143 bIsOEMmsg = TRUE; 144 break; 145 case VK_OEM_SIDEUP: 146 bIsOEMmsg = TRUE; 147 break; 148 case VK_OEM_SIDEDOWN: 149 bIsOEMmsg = TRUE; 150 break; 151 case VK_OEM_CAMERA: 152 bIsOEMmsg = TRUE; 153 break; 154 default: 155 uCount = 0; 156 return CallNextHookEx(hKeyHook, nCode, wParam, lParam); //继续传递消息 157 } 158 159 if (bNeedPassOnceMsg) 160 { 161 return TRUE; 162 } 163 164 //只发送OEM消息,其它消息并不拦截。 165 //拦截原消息,发送自定义消息。 166 //限制需要向上Post的vkCode 167 switch (pkbhs->vkCode) 168 { 169 return CallNextHookEx(hKeyHook, nCode, wParam, (LPARAM)pkbhs); //转换为回车消息传递(未测试) 170 } 171 case VK_OEM_OK: 172 case VK_OEM_BACK: 173 case VK_OEM_DIAL: 174 case VK_OEM_DISCONNECT: 175 bIsOEMmsg = TRUE; 176 break; 177 case VK_NUMPAD1: 178 case VK_NUMPAD2: 179 case VK_NUMPAD3: 180 case VK_NUMPAD4: 181 case VK_NUMPAD5: 182 case VK_NUMPAD6: 183 case VK_NUMPAD7: 184 case VK_NUMPAD8: 185 case VK_NUMPAD9: 186 case VK_NUMPAD0: 187 case 0x30: 188 case 0x31: 189 case 0x32: 190 case 0x33: 191 case 0x34: 192 case 0x35: 193 case 0x36: 194 case 0x37: 195 case 0x38: 196 case 0x39: 197 break; 198 case VK_OEM_ASTERISK: 199 case VK_OEM_POUND: 200 case VK_OEM_SIDEUP: 201 case VK_OEM_SIDEDOWN: 202 case VK_OEM_CAMERA: 203 bIsOEMmsg = TRUE; 204 break; 205 default: 206 return CallNextHookEx(hKeyHook, nCode, wParam, lParam); //继续传递消息 207 } 208 209 //只发送OEM消息,其它消息并不拦截。 210 if (bOnlySendOEMMsg) 211 { 212 if (bIsOEMmsg) 213 { 214 PostMessage(hTopWnd, WM_USER_KEYUP, (WPARAM)(pkbhs->vkCode), (LPARAM)uCount); 215 return TRUE; //拦截OEM消息,不再向上传递此消息。 216 } 217 else 218 { 219 return CallNextHookEx(hKeyHook, nCode, wParam, lParam); //继续传递其它消息 220 } 221 } 222 223 //拦截原消息,发送自定义消息。 224 if (bHoldUpMsg) 225 {//菜单未弹出的情况 226 PostMessage(hTopWnd, WM_USER_KEYUP, (WPARAM)(pkbhs->vkCode), 0L); 227 return TRUE; //拦截消息,不再向上传递此消息。 228 } 229 } 230 else 231 { 232 uCount = 0; 233 } 234 235 return CallNextHookEx(hKeyHook, nCode, wParam, lParam); //继续传递消息 236 } 237 238 extern "C" KEYBOARDHOOK_API void SetAppHWND(HWND hCurAppWnd) 239 { 240 hAppWnd = hCurAppWnd; 241 } 242 243 extern "C" KEYBOARDHOOK_API void SetTopHWND(HWND hCurTopWnd) 244 { 245 hTopWnd = hCurTopWnd; 246 } 247 248 extern "C" KEYBOARDHOOK_API void SetHoldUpMsg(BOOL bHoldUp) 249 { 250 bHoldUpMsg = bHoldUp; 251 } 252 253 extern "C" KEYBOARDHOOK_API void SetOnlySendOEMMsg(BOOL bOnlySendOEM) 254 { 255 bOnlySendOEMMsg = bOnlySendOEM; 256 } 257 258 extern "C" KEYBOARDHOOK_API void SetNeedPassOnceMsg(BOOL bWhetherNeed) 259 { 260 bNeedPassOnceMsg = bWhetherNeed; 261 }
2. 建立头文件
// The following ifdef block is the standard way of creating macros which make exporting // from a DLL simpler. All files within this DLL are compiled with the KEYBOARDHOOK_EXPORTS // symbol defined on the command line. this symbol should not be defined on any project // that uses this DLL. This way any other project whose source files include this file see // KEYBOARDHOOK_API functions as being imported from a DLL, wheras this DLL sees symbols // defined with this macro as being exported. #ifdef KEYBOARDHOOK_EXPORTS #define KEYBOARDHOOK_API __declspec(dllexport) #else #define KEYBOARDHOOK_API __declspec(dllimport) #endif // This class is exported from the KeyBoardHook.dll class KEYBOARDHOOK_API CKeyBoardHook { public: CKeyBoardHook(void); // TODO: add your methods here. }; extern KEYBOARDHOOK_API int nKeyBoardHook; KEYBOARDHOOK_API int fnKeyBoardHook(void); extern "C" KEYBOARDHOOK_API void InstallHook(void); extern "C" KEYBOARDHOOK_API void UnHook(void); extern "C" KEYBOARDHOOK_API LRESULT CALLBACK KeyBoardProc(int nCode, WPARAM wParam, LPARAM lParam); extern "C" KEYBOARDHOOK_API void SetAppHWND(HWND hCurAppWnd); extern "C" KEYBOARDHOOK_API void SetTopHWND(HWND hCurTopWnd); extern "C" KEYBOARDHOOK_API void SetHoldUpMsg(BOOL bHoldUp); extern "C" KEYBOARDHOOK_API void SetOnlySendOEMMsg(BOOL bOnlySendOEM); extern "C" KEYBOARDHOOK_API void SetNeedPassOnceMsg(BOOL bWhetherNeed);
3. 建立程序主文件
1 if (hModule) 2 { 3 InHook = (pInstallHook)GetProcAddress(hModule, L"InstallHook"); 4 UnHook = (pUnHook)GetProcAddress(hModule, L"UnHook"); 5 SetAppHWND = (pSetAppHWND)GetProcAddress(hModule, L"SetAppHWND"); 6 SetTopHWND = (pSetTopHWND)GetProcAddress(hModule, L"SetTopHWND"); 7 SetHoldUpMsg = (pSetHoldUpMsg)GetProcAddress(hModule, L"SetHoldUpMsg"); 8 SetOnlySendOEMMsg = (pSetOnlySendOEMMsg)GetProcAddress(hModule, L"SetOnlySendOEMMsg"); 9 SetNeedPassOnceMsg = (pSetNeedPassOnceMsg)GetProcAddress(hModule, L"SetNeedPassOnceMsg"); 10 11 if (!InHook || !UnHook || !SetAppHWND || !SetTopHWND || !SetHoldUpMsg || !SetOnlySendOEMMsg || !SetNeedPassOnceMsg) 12 { 13 MessageBoxEx(hWnd, L"KeyboardHook.dll加载失败,程序被终止。", L"Info", MB_OK); 14 PostQuitMessage(0); 15 } 16 } 17 else 18 { 19 MessageBoxEx(hWnd, L"KeyboardHook.dll加载失败,程序被终止。", L"Info", MB_OK); 20 PostQuitMessage(0); 21 } 22 23 InHook(); 24
DLL的编写,也可以参考以下网址中的内容:
http://www.bc-cn.net/Article/kfyy/cyy/jszl/200709/6328_2.html