摘要: 本文主要对钩子这种特殊的Windows编程机制进行了讨论并给出了鼠标钩子和键盘钩子的具体实现方法。
关键词: 钩子;鼠标钩子;Visual C++
钩子概述 钩子(Hook)是Windows消息处理机制的一个要点(Point)。应用程序可以通过钩子机制截获处理Window消息或是其他一些特定事件。同DOS中断截获处理机制类似,应用
程序可以在钩子上设置多个钩子函数,由其组成一个与钩子相关联的指向钩子函数的指针列表(钩子链表)。当钩子所监视的消息出现时,Windows首先将其送到调用链表中所指向的第一个钩子函数中,钩子函数将根据其各自的功能对消息进行监视、修改和控制,并在处理完成后把消息传递给下一钩子函数直至到达钩子链表的末尾。在钩子函数交出控制权后,被拦截的消息最终仍将交还给窗口处理函数。虽然钩子函数对消息的过滤将会略加影响系统的运行效率,但在很多场合下通过钩子对消息的过滤处理可以完成一些其他方法所不能完成的特殊功能。
可以看出,钩子的本质是一段用以处理系统消息或特定事件的函数,通过系统调用将其挂入到系统。钩子的种类有很多,每一种钩子负责截获并处理相应的消息。钩子机制允许应用程序截获并处理发往指定窗口的消息或特定事件,其监视的窗口即可以是本进程内的也可以是由其他进程所创建的。在特定的消息发出后、达目的窗口前,钩子
程序拥有对其控制权,此时的钩子函数除了可以对截获的消息进行各种处理外,甚至还可以强行终止消息的继续传递。
对于多个钩子的安装,最近安装的钩子将被放置于钩子链的开始,最早安装的钩子则放在最后,在钩子监视的消息出现时,操作系统调用链表开始处的第一个钩子函数进行处理,也就是说最后加入的钩子优先获得控制权。这里提到的钩子函数必须是一个回调函数,而且不能定义为类成员函数,只能是普通的C函数,如:
LRESULT CALLBACK HookProc(int nCode ,WPARAM wParam,LPARAM lParam);
线程局部钩子与系统全局钩子 钩子根据其对消息监视范围的不同而分为系统全局钩子和线程局部钩子两大类,其中线程局部钩子只能监视本进程中某个指定的线程,而全局钩子则可对在当前系统下运行的所有线程进行监视。显然,线程钩子可以看作是全局钩子的一个子集,全局钩子虽然功能强大但同时实现起来也比较烦琐:其钩子函数的实现必须封装在独立的动态
链接库中才可以被各种相关联的应用
程序所使用。
虽然对于线程局部钩子并不要求其象系统全局钩子一样必须放置于动态链接库中,但是推荐的做法仍是将其放到动态链接库中去实现。这样的处理不仅能使钩子为系统内的多个进程所访问,同时也可以在系统中被直接调用。对于一个只供单进程访问的钩子,还可以将其钩子处理过程放在安装钩子的同一个线程内。
钩子的安装与卸载 系统是通过调用位于钩子链表最开始处的钩子函数而进行消息拦截处理的,因此在设置钩子时要把回调函数放置于钩子链表的链首,操作系统会使其首先被调用。由函数SetWindowsHookEx()负责将回调函数放置于钩子链表的开始位置。SetWindowsHookEx()函数原型声明为:
HHOOK SetWindowsHookEx(int idHook;HOOKPROC lpfn;HINSTANCE hMod;DWORD dwThreadId); |
其中,参数idHook 指定了钩子的类型,可以使用的类型有以下13种:
WH_CALLWNDPROC 系统将消息发送到指定窗口之前的“钩子” WH_CALLWNDPROCRET 消息已经在窗口中处理的“钩子” WH_CBT 基于计算机培训的“钩子” WH_DEBUG 差错“钩子” WH_FOREGROUNDIDLE 前台空闲窗口“钩子” WH_GETMESSAGE 接收消息投递的“钩子” WH_JOURNALPLAYBACK 回放以前通过WH_JOURNALRECORD“钩子”记录的输入消息 WH_JOURNALRECORD 输入消息记录“钩子” WH_KEYBOARD 键盘消息“钩子” WH_MOUSE 鼠标消息“钩子” WH_MSGFILTER 对话框、消息框、菜单或滚动条输入消息“钩子” WH_SHELL 外壳“钩子” WH_SYSMSGFILTER 系统消息“钩子” |