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檔案。
// KeyBoardHook.cpp : Defines the entry point for the DLL application.
//
#include "stdafx.h"
#include "KeyBoardHook.h"
#include <Pwinuser.h>
#include "BasalMessage.h"
//#include "FileManage.h"
//告訴編譯器將變數放入它自己的資料共享節中
#pragma data_seg("KeyHookData")
HINSTANCE hInst = NULL;
#pragma data_seg()
//告訴編譯器設定共享節的訪問方式為:讀,寫,共享
#pragma comment(linker, "/SECTION:KeyHookData,RWS")
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
hInst = (HINSTANCE)hModule;
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
// This is an example of an exported variable
KEYBOARDHOOK_API int nKeyBoardHook=0;
// This is an example of an exported function.
KEYBOARDHOOK_API int fnKeyBoardHook(void)
{
return 42;
}
// This is the constructor of a class that has been exported.
// see KeyBoardHook.h for the class definition
CKeyBoardHook::CKeyBoardHook()
{
return;
}
extern "C" KEYBOARDHOOK_API void InstallHook(void)
{
if (hInst)
{
hKeyHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyBoardProc, hInst, 0);
}
}
extern "C" KEYBOARDHOOK_API void UnHook(void)
{
if (hKeyHook)
{
UnhookWindowsHookEx(hKeyHook);
hKeyHook = NULL;
}
hInst = NULL;
}
extern "C" KEYBOARDHOOK_API LRESULT CALLBACK KeyBoardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
TCHAR t_WndClassName[50] = { 0 };
HWND hCurActiveWnd = NULL;
HWND hCurForegroundWnd = NULL;
BOOL bIsTaskBarMsg = FALSE;
BOOL bIsOEMmsg = FALSE;
PKBDLLHOOKSTRUCT pkbhs = (PKBDLLHOOKSTRUCT)lParam;
if (WM_KEYDOWN == wParam)
{
uCount++;
RETAILMSG(1, (TEXT("WM_KEYDOWN vk %d /r/n"),pkbhs->vkCode));
//響應按鍵聲,並限制需要向上Post的vkCode
switch (pkbhs->vkCode)
{
case VK_UP:
break;
case VK_DOWN:
break;
case VK_LEFT:
break;
case VK_RIGHT:
break;
case VK_OEM_SELECT:
bIsOEMmsg = TRUE;
break;
case VK_OEM_OK:
bIsOEMmsg = TRUE;
break;
case VK_OEM_BACK:
bIsOEMmsg = TRUE;
break;
case VK_OEM_DIAL:
bIsOEMmsg = TRUE;
break;
case VK_NUMPAD1:
case 0x31:
break;
case VK_NUMPAD2:
case 0x32:
break;
case VK_NUMPAD3:
case 0x33:
break;
case VK_NUMPAD4:
case 0x34:
break;
case VK_NUMPAD5:
case 0x35:
break;
case VK_NUMPAD6:
case 0x36:
break;
case VK_NUMPAD7:
case 0x37:
break;
case VK_NUMPAD8:
case 0x38:
break;
case VK_NUMPAD9:
case 0x39:
break;
case VK_NUMPAD0:
case 0x30:
break;
case VK_OEM_ASTERISK:
bIsOEMmsg = TRUE;
break;
case VK_OEM_POUND:
bIsOEMmsg = TRUE;
break;
case VK_OEM_SIDEUP:
bIsOEMmsg = TRUE;
break;
case VK_OEM_SIDEDOWN:
bIsOEMmsg = TRUE;
break;
case VK_OEM_CAMERA:
bIsOEMmsg = TRUE;
break;
default:
uCount = 0;
return CallNextHookEx(hKeyHook, nCode, wParam, lParam); //繼續傳遞訊息
}
if (bNeedPassOnceMsg)
{
return TRUE;
}
//只傳送OEM訊息,其它訊息並不攔截。
//攔截原訊息,傳送自定義訊息。
//限制需要向上Post的vkCode
switch (pkbhs->vkCode)
{
return CallNextHookEx(hKeyHook, nCode, wParam, (LPARAM)pkbhs); //轉換為回車訊息傳遞(未測試)
}
case VK_OEM_OK:
case VK_OEM_BACK:
case VK_OEM_DIAL:
case VK_OEM_DISCONNECT:
bIsOEMmsg = TRUE;
break;
case VK_NUMPAD1:
case VK_NUMPAD2:
case VK_NUMPAD3:
case VK_NUMPAD4:
case VK_NUMPAD5:
case VK_NUMPAD6:
case VK_NUMPAD7:
case VK_NUMPAD8:
case VK_NUMPAD9:
case VK_NUMPAD0:
case 0x30:
case 0x31:
case 0x32:
case 0x33:
case 0x34:
case 0x35:
case 0x36:
case 0x37:
case 0x38:
case 0x39:
break;
case VK_OEM_ASTERISK:
case VK_OEM_POUND:
case VK_OEM_SIDEUP:
case VK_OEM_SIDEDOWN:
case VK_OEM_CAMERA:
bIsOEMmsg = TRUE;
break;
default:
return CallNextHookEx(hKeyHook, nCode, wParam, lParam); //繼續傳遞訊息
}
//只傳送OEM訊息,其它訊息並不攔截。
if (bOnlySendOEMMsg)
{
if (bIsOEMmsg)
{
PostMessage(hTopWnd, WM_USER_KEYUP, (WPARAM)(pkbhs->vkCode), (LPARAM)uCount);
return TRUE; //攔截OEM訊息,不再向上傳遞此訊息。
}
else
{
return CallNextHookEx(hKeyHook, nCode, wParam, lParam); //繼續傳遞其它訊息
}
}
//攔截原訊息,傳送自定義訊息。
if (bHoldUpMsg)
{//選單未彈出的情況
PostMessage(hTopWnd, WM_USER_KEYUP, (WPARAM)(pkbhs->vkCode), 0L);
return TRUE; //攔截訊息,不再向上傳遞此訊息。
}
}
else
{
uCount = 0;
}
return CallNextHookEx(hKeyHook, nCode, wParam, lParam); //繼續傳遞訊息
}
extern "C" KEYBOARDHOOK_API void SetAppHWND(HWND hCurAppWnd)
{
hAppWnd = hCurAppWnd;
}
extern "C" KEYBOARDHOOK_API void SetTopHWND(HWND hCurTopWnd)
{
hTopWnd = hCurTopWnd;
}
extern "C" KEYBOARDHOOK_API void SetHoldUpMsg(BOOL bHoldUp)
{
bHoldUpMsg = bHoldUp;
}
extern "C" KEYBOARDHOOK_API void SetOnlySendOEMMsg(BOOL bOnlySendOEM)
{
bOnlySendOEMMsg = bOnlySendOEM;
}
extern "C" KEYBOARDHOOK_API void SetNeedPassOnceMsg(BOOL bWhetherNeed)
{
bNeedPassOnceMsg = bWhetherNeed;
}
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. 建立程式主檔案
if (hModule)
{
InHook = (pInstallHook)GetProcAddress(hModule, L"InstallHook");
UnHook = (pUnHook)GetProcAddress(hModule, L"UnHook");
SetAppHWND = (pSetAppHWND)GetProcAddress(hModule, L"SetAppHWND");
SetTopHWND = (pSetTopHWND)GetProcAddress(hModule, L"SetTopHWND");
SetHoldUpMsg = (pSetHoldUpMsg)GetProcAddress(hModule, L"SetHoldUpMsg");
SetOnlySendOEMMsg = (pSetOnlySendOEMMsg)GetProcAddress(hModule, L"SetOnlySendOEMMsg");
SetNeedPassOnceMsg = (pSetNeedPassOnceMsg)GetProcAddress(hModule, L"SetNeedPassOnceMsg");
if (!InHook || !UnHook || !SetAppHWND || !SetTopHWND || !SetHoldUpMsg || !SetOnlySendOEMMsg || !SetNeedPassOnceMsg)
{
MessageBoxEx(hWnd, L"KeyboardHook.dll載入失敗,程式被終止。", L"Info", MB_OK);
PostQuitMessage(0);
}
}
else
{
MessageBoxEx(hWnd, L"KeyboardHook.dll載入失敗,程式被終止。", L"Info", MB_OK);
PostQuitMessage(0);
}
InHook();
DLL的編寫,也可以參考以下網址中的內容:
http://www.bc-cn.net/Article/kfyy/cyy/jszl/200709/6328_2.html
相關文章
- VB程式設計經驗點滴程式設計
- 程式設計技術點滴一(Delphi)程式設計
- VB程式介面設計經驗點滴 (轉)
- 程式設計技術點滴三(C/C++)程式設計C++
- Oracle程式設計經驗及維護點滴(轉)Oracle程式設計
- wordpress的save_post鉤子注意點
- 程式設計二三事 - 如何從點滴做起開發高質量專案程式設計
- 原始碼中的設計模式--模板方法模式(鉤子方法)原始碼設計模式
- asm點滴ASM
- oracle點滴Oracle
- 小程式開發點滴積累
- 遮蔽系統熱鍵鉤子Hook程式Hook
- 理解 Vue 的 setup 應用程式鉤子Vue
- Nuxt3 的生命週期和鉤子函式(四)UX函式
- MFC程式設計(四)C程式程式設計
- mailx使用點滴AI
- PHP系列之鉤子PHP
- React Hooks 鉤子特性ReactHook
- 鉤子(hook)是啥Hook
- 新建鉤子檔案
- 程式設計師強子程式設計師
- 併發程式設計(四)程式設計
- 工作點滴積累
- lzma 知識點滴
- 前端點滴記錄前端
- 專題:點滴JavascriptJavaScript
- hp-ux點滴UX
- vue-router的鉤子Vue
- Vue 生命週期鉤子Vue
- PHP之鉤子行為PHP
- WINDOWS鉤子函式(轉)Windows函式
- VC:滑鼠鉤子函式函式
- C#系統鉤子C#
- 程式設計師的樣子程式設計師
- 我的2023年:程式設計師的自我迭代、技術覆盤與生活點滴程式設計師
- pre-commit鉤子,程式碼質量檢查MIT
- 利用鍵盤鉤子開發按鍵發音程式
- 談談程式設計師重複造輪子的幾點思考程式設計師