最近应用开发的进程中出现了一个小问题,顺便记录一下原因和方法--鼠标函数
自从应用.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消息处理 }
----------------------------------------------------------------------------------------------------------------------
三、结束语
至此应用全局钩子实现鼠标坐标值实时捕获实现进程说明终了。
简单吧!就那么几步。当然,这个小程序太简单了,没有现实用途,只是明天正好在问问遇到了此问题,所以把我的解决方法贴出来了,希望对初学钩子应用的网友有点用途。
文章结束给大家分享下程序员的一些笑话语录: 一条狗在街上闲逛,看见橱窗里一张告示:「招聘程序员。会编程,有团队精神,至少精通两种语言。均等机会。」
那条狗就进去申请,但是被拒绝了。
「我不能雇一条狗在公司里做事。」经理说。
狗不服气,指着告示上「均等机会」几字抗议。
经理没法,叹了口气,不屑地问道:「你会编程吗?」
那条狗默默地走到电脑前,编了个程序,运作准确。
「你有团队精神吗?」经理问。
那条狗掉头看了看门外,一大群野狗在外面虎视耽耽。
「我真的不能雇狗做这份工作。」经理气急败坏地说。
「就算会编程、有团队精神,但是我需要的雇员至少要能精通两种语言。」
那条狗抬头看着经理说:「喵-噢。」
--------------------------------- 原创文章 By
鼠标和函数
---------------------------------