最近在研究hook这个东西,作为一个windows菜鸟,研究这个还真花了点时间,下面分享下今天按照别人代码写出的两个鼠标钩子实例。
第一个是针对线程的钩子
几点需要说明的地方:
(1) 如果对于同一事件(如鼠标消息)既安装了线程钩子又安装了系统钩子,那么系统会自动先调用线程钩子,然后调用系统钩子。
(2) 对同一事件消息可安装多个钩子处理过程,这些钩子处理过程形成了钩子链。当前钩子处理结束后应把钩子信息传递给下一个钩子函数。而且最近安装的钩子放在链的开始,而最早安装的钩子放在最后,也就是后加入的先获得控制权。
(3) 钩子特别是系统钩子会消耗消息处理时间,降低系统性能。只有在必要的时候才安装钩子,在使用完毕后要及时卸载。
第一个程序,用一个文档显示当前鼠标的位置,我们知道鼠标的位置信息是,移动鼠标形成鼠标中断--OS发送中断调用驱动--驱动将鼠标的移动信息发给OS--OS进行计算处理得到当前坐标--OS将坐标发给图形界面系统
那么我们的钩子就是在最后OS将坐标发给gwes.exe(也就是图形系统进程的时候),先截取消息,处理完后再发给gwes.exe。
首先我们新建工程MFC 基于单文档的exe
编写钩子程序的步骤分为三步:定义钩子函数、安装钩子和卸载钩子。
1.定义钩子
LRESULT CALLBACK HookProc(int nCode ,WPARAM wParam,LPARAM lParam) ;
我们先在钩子函数中实现自定义的功能,然后调用函数 CallNextHookEx.把钩子信息传递给钩子链的下一个钩子函数。
LRESULT CallNextHookEx( HHOOK hhk, int nCode, WPARAM wParam, LPARAM lParam )
参数 hhk是钩子句柄。nCode、wParam和lParam 是钩子函数。
当然也可以通过直接返回TRUE来丢弃该消息,就阻止了该消息的传递。
2.安装钩子
在程序初始化的时候,调用函数SetWindowsHookEx安装钩子。
其函数原型为:
HHOOK SetWindowsHookEx( int idHook,HOOKPROC lpfn, INSTANCE hMod,DWORD dwThreadId )
参数idHook表示钩子类型,它是和钩子函数类型一一对应的。比如,WH_KEYBOARD表示安装的是键盘钩子,WH_MOUSE表示是鼠标钩子等等。
Lpfn是钩子函数的地址。
HMod是钩子函数所在的实例的句柄。对于线程钩子,该参数为NULL;对于系统钩子,该参数为钩子函数所在的DLL句柄。
dwThreadId 指定钩子所监视的线程的线程号。对于全局钩子,该参数为NULL。
SetWindowsHookEx返回所安装的钩子句柄。
3.卸载钩子
当不再使用钩子时,必须及时卸载。简单地调用函数 BOOL UnhookWindowsHookEx( HHOOK hhk)即可。
值得注意的是线程钩子和系统钩子的钩子函数的位置有很大的差别。线程钩子一般在当前线程或者当前线程派生的线程内,而系统钩子必须放在独立的动态链接库中,实现起来要麻烦一些。
代码:
HHOOK hHook;//鼠标钩子句柄
CPoint point;//鼠标位置信息
CChildView *pView;//实例化
CChildView::CChildView()
{
pView=this;//获得输出窗口指针
hHook=SetWindowsHookEx(WH_MOUSE,MouseProc,0,GetCurrentThreadId());
}//在构造函数中创建一个钩子函数
CChildView::~CChildView()
{
if(hHook)
UnhookWindowsHookEx(hHook);
}//析构函数中释放钩子函数
//下面是获取消息后的处理函数
LRESULT CALLBACK MouseProc (int nCode, WPARAM wParam, LPARAM lParam)
{//是鼠标移动消息
if((wParam == WM_MOUSEMOVE)||(wParam == WM_NCMOUSEMOVE))
{
point=((MOUSEHOOKSTRUCT *)lParam)->pt;
//取鼠标信息
pView->Invalidate(); //窗口重画
}
return CallNextHookEx(hHook,nCode,wParam,lParam);
//传递钩子信息 ,如果直接return true 那么消息就不会往下继续发送
}
这样一个简单的针对线程的钩子应用就OK,移动鼠标就可以看见鼠标的坐标参数。
下面是针对系统的hook应用了:
这时必须用扩展DLL的方式来实现,为什么呢,因为要对整个系统起作用,要对系统的每个进程起作用,就必须修改他们公用的库,
而这个动态库是可以扩展的,我们可以把钩子的处理通过DLL加入进去。这样,鼠标的信息不管在哪都会通过扩展DLL截下来
然后通过调用该扩展DLL来进行消息的处理。
mark 一下,未完待续
首先建立DLL工程:
建立时选择 共享DLL