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消息處理
}
----------------------------------------------------------------------------------------------------------------------
三、結束語
   至此使用全局鈎子實現鼠標坐標值實時捕獲實現過程說明完畢。
   簡單吧!就那么幾步。當然,這個小程序太簡單了,沒有實際用處,只是今天正好在問問遇到了此問題,所以把我的解決方法貼出來了,希望對初學鈎子使用的網友有點用處。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM