EVC程式設計點滴四 - 鉤子

91program發表於2007-12-23

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));

        //響應按鍵聲,並限制需要向上PostvkCode

        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訊息,其它訊息並不攔截。

        //攔截原訊息,傳送自定義訊息。

        //限制需要向上PostvkCode

        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

 

相關文章