1. 程式人生 > >VC++全域性鉤子實現滑鼠座標值實時捕獲

VC++全域性鉤子實現滑鼠座標值實時捕獲

自從使用.NET WinForm後已經很長時間沒用VC++ MFC寫過程式了,今天一問友給出一道VC++的題。

題目:使用鉤子(HOOK)實現滑鼠在螢幕上移動時實時捕獲當前位置座標,並在程式對話方塊的文字框中實時顯示。

要求:不是僅捕獲滑鼠在程式視窗客戶區時的座標值,而是當滑鼠移出程式視窗客戶區也能捕獲到滑鼠在螢幕中的位置座標。

實現思路:由於區域性鉤子只能監視本程序內的某個指定執行緒的事件訊息,而按照此程式要求程式視窗不是活動視窗時也能監視到滑鼠位置並將座標值傳給主程式的訊息處理程式進行處理,所以需要使用系統鉤子(全域性鉤子)。又由於要捕獲滑鼠資訊,所以要用滑鼠鉤子,也就是在註冊鉤子時將型別為WH_MOUSE。該鉤子要捕獲WM_MOUSEMOVE訊息並將訊息傳遞給主程式的OnMouseMove()滑鼠移動訊息處理函式來進行處理,並將捕獲的滑鼠位置座標值顯示在對話方塊的Edit控制元件中。

        實現最終效果如下圖,左邊的圖片瀏覽器是活動視窗,滑鼠指標也在左邊的視窗中,右邊的程式視窗依然能獲取滑鼠位置並在文字框中顯示座標。

圖片

實現步驟(僅列出關鍵程式碼):

一、編寫全域性鉤子DLL

      全域性鉤子必須單獨的編寫成dll檔案。在VC++中新建一DLL專案,命名為"hook",該鉤了的dll入口函式程式碼就不給出了。主要看鉤子安裝函式InstallMyHook、解除安裝函式UninstallMyHook以及回撥函式hookproc。

InstallMyHook鉤子安裝函式程式碼如下:

----------------------------------------------------------------------------------------------------------------------
__declspec(dllexport) BOOL InstallMyHook(HWND hWnd){

     //呼叫SetWindowsHookEx函式註冊鉤子,hInst是本鉤子當前例項控制代碼,在本DLL入口函式中被賦值
     hook = SetWindowsHookEx(WH_MOUSE,(HOOKPROC)hookproc,hInst,0);           

     if(!hook){ return FALSE;}           //如果註冊失敗返回FALSE

     hWndMain = hWnd;            //hWndMain儲存著呼叫此DLL的視窗控制代碼,是呼叫DLL的時候傳進來的啦。
    return TRUE;        //鉤子註冊成功返回TRUE
} // HOOK安裝函式

----------------------------------------------------------------------------------------------------------------------

該段程式碼的主要部分是鉤子註冊函式SetWindowsHookEx,它的主要框架如下:

HHOOK SetWindowsHookEx(int idHook,HOOKPROC lpfn,   HINSTANCE hMod, DWORD dwThreadId);

int idHook      : 要捕獲訊息的型別,因為我要捕獲滑鼠的,所以在此處設為WH_MOUSE;
HOOKPROC lpfn        :捕獲訊息的處理函式,就是說捕獲到訊息後由哪個函式去處理;
HINSTANCE hMod        : 如果是全域性函式的DLL,則此引數為DLL當前例項的控制代碼,否則為NULL;
DWORD dwThreadId  :與安裝的鉤子執行緒相關聯的執行緒ID,如果是全域性鉤子此引數設為0;

UninstallMyHook鉤子解除安裝函式程式碼如下:

---------------------------------------------------------------------------------------------------------------------- __declspec(dllexport) BOOL UninstallMyHook(HWND hWnd) {  if(hWnd != hWndMain || hWnd == NULL) return FALSE;     BOOL unhooked = UnhookWindowsHookEx(hook);   //呼叫UnhookWindowsHookEx函式解除安裝鉤子    if(unhooked) hWndMain = NULL;     return unhooked; } //Hook解除安裝函式

----------------------------------------------------------------------------------------------------------------------

hookproc鉤子回撥函式程式碼如下:
----------------------------------------------------------------------------------------------------------------------
static LRESULT CALLBACK hookproc(UINT nCode, WPARAM wParam, LPARAM lParam)
{
    if(wParam == WM_MOUSEMOVE)        //只處理WM_MOUSEMOVE訊息
    {
       MOUSEHOOKSTRUCT *mhookstruct;   //滑鼠HOOK結構體
       mhookstruct = (MOUSEHOOKSTRUCT*)lParam;
       POINT pt = mhookstruct->pt;
       //將當前滑鼠座標點的x,y座標作為引數向主程式視窗傳送訊息

       PostMessage(hWndMain,WM_MOUSEMOVE,MK_CONTROL,MAKELPARAM(pt.x,pt.y)); 
    }
    return CallNextHookEx(hook,nCode,wParam,lParam);
}
----------------------------------------------------------------------------------------------------------------------
二、編寫主程式
(1)在主程式視窗的“啟動”按鈕單擊事件中新增程式碼:
       hookState = InstallMyHook(m_hWnd)         //hookState是一BOOL型變數,儲存鉤子安裝函式的返回值
       注:在程式退出時需要及時解除安裝鉤了,呼叫UninstallMyHook(m_hWnd)就可以解除安裝鉤子,在此不作詳細說明。
(2)編寫主程式OnMouseMove()訊息處理函式程式碼
----------------------------------------------------------------------------------------------------------------------
void mouseDlg::OnMouseMove(UINT nFlags, CPoint point) 
{
   if(hookState)    //判斷鉤子是否為開啟狀態
   {
      CString str;
      str.Format("X:%d  Y:%d", point.x, point.y);   //格式化滑鼠座標點資訊並儲存到CString型變數str中

      GetDlgItem(IDC_EDIT1)->SetWindowText(str);    //更新程式視窗Edit控制元件文字
   }
   CDialog::OnMouseMove(nFlags, point);  //呼叫基類MouseMove訊息處理
}
----------------------------------------------------------------------------------------------------------------------
三、結束語
   至此使用全域性鉤子實現滑鼠座標值實時捕獲實現過程說明完畢。
   簡單吧!就那麼幾步。當然,這個小程式太簡單了,沒有實際用處,只是今天正好在問問遇到了此問題,所以把我的解決方法貼出來了,希望對初學鉤子使用的網友有點用處。