• 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消息处理
    }
    ----------------------------------------------------------------------------------------------------------------------
    三、结束语
       至此使用全局钩子实现鼠标坐标值实时捕获实现过程说明完毕。
       简单吧!就那么几步。当然,这个小程序太简单了,没有实际用处,只是今天正好在问问遇到了此问题,所以把我的解决方法贴出来了,希望对初学钩子使用的网友有点用处。
  • 相关阅读:
    [Leetcode] Set Matrix Zeroes
    [Leetcode] Longest Valid Parentheses
    [Leetcode] Interleaving String
    [Leetcode] Surrounded Regions
    [Leetcode] Candy
    用Delphi获取当前系统时间
    Delphi窗体中禁用最大化按钮
    DELPHI关于文件的操作
    Delphi 2010初体验,是时候抛弃Delphi 7了
    双通道内存有什么优点和缺点?
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3105119.html
Copyright © 2020-2023  润新知