钩子编程

科技工作者之家 2020-11-17

钩子是Windows消息处理机制的要点,Windows消息从硬件的输入到应用程序之间的传递。

概述当在应用程序中设置多个钩子函数以后,应用程序中的钩子函数组成一个与钩子相关联的指向钩子函数的指针列表。当钩子函数监视的消息到达以后,Windows系统首先将消息送到指针列表所指向的第一个钩子函数中,这个钩子函数对消息进行监视、修改、控制后,再将消息传递到下一个钩子函数中,再次进行处理,这样直到到达钩子链表的最后。在钩子链表对消息处理完成以后,消息仍然被送到应用程序的窗口中进行处理。

钩子函数拦截了消息,并且进行了一些处理,这显然影响了程序的效率,但是这种付出的回报是程序员可以对某些感兴趣的消息进行控制。钩子函数的本质就是一个处理系统消息的函数,通过应用程序将函数挂入到系统中,对系统消息进行拦截和处理。1

钩子范围根据钩子函数监视的消息范围不同,钩子分为全局钩子和线程局部钩子。线程局部钩子仅仅是对本进程中的某个线程的消息进行拦截和处理。全局钩子则是对系统的全部消息进行拦截。全局钩子的实现要比局部钩子困难一些,它要监视所有的系统消息并进行处理。

全局钩子函数的实现必须封装在独立的动态链接库中,才可以被各种各样的相关联的应用程序所使用。局部钩子不一定在动态链接库中实现,但经常的做法是仍然在动态链接库中实现,这样可以被多个应用程序所使用,这正是动态链接库的优势所在。1

钩子类型按事件分类,有如下常用的钩子类型。

(1)键盘钩子和低级键盘钩子:监视各种键盘消息。

(2)鼠标钩子和低级鼠标钩子:监视各种鼠标消息。

(3)外壳钩子:监视各种Shell事件消息,如启动和关闭应用程序。

(4)日志钩子:记录从系统消息队列中取出的各种事件消息。

(5)窗口过程钩子:监视所有从系统消息队列发往日标窗口的消息。

按使用范同分类,主要有线程钩子和系统钩子。

(1)线程钩子:监视指定线程的事件消息。

(2)系统钩子:监视系统中的所有线程的事件消息,因为它影响系统中的所有应用程序,所以钩子函数必须放在独立的动态链接库(DLL)中,这是系和线程钩子的主要不同。

13种钩子的说明如下。

(1) WH_CALLWNDPROC和WH_CALLWNDPROCRET:监视发送到窗口过程的消息。系统在消息发送到接收窗口过程之前调用WH_CALLWNDPROC钩子子程,处理消息之后调用WH_CALLWNDPROCRET钩子子程后传递指针到CWPRETSTRUCT结构。该结构包含来自处理消息窗口过程的返回值,以及与这个消息关联的消息参数。

(2) WH_CBT:在以下事件之前,系统调用WH_CBT钩子子程。

激活、建立、销毁、最小化、最火化、移动及改变尺寸等窗口事件。

完成系统指令事件。

来自系统消息队列中的移动鼠标和键盘事件。

设置输入焦点事件。

同步系统消息队列事件。

钩子子程的返回值确定系统是否允许或者禁止这些操作中的一个。

(3)WH__DEBUG:可以使用此钩子决定是否允许系统调用与其他钩子关联的钩子子程。

(4) WH_FOREGROUNDIDLE:应用程序的前台线程处于空闲状态时,可使用WH_该钩子执行低优先级的任务。

(5) WH_GETMESSAGE:应川程序使用该钩子监视从GetMessage或PeekMessage函数返同的消息。

(6) WH_JOURNALPLAYBACK:使应用程序可以插入消息到系统消息队列,该钩子返回超时值通知系统处理来自回放钩子当前消息前的等待时间(毫秒)。

(7) WH_JOURNALRECORD:监视和记录输入事件。

(8) WH_KEYBOARD:在应用程序中使该钩子监视WM_KEYDOWN利WM_KEYUP消息。

(9) WH_KEYBOARD_LL:监视输入到线程消息队列中的键盘消息。

(10) WH_MOUSE:监视从GetMessage或PeekMessage函数返同的鼠标消息。

(11) WH_MOUSE_LL:监视输入到线程消息队列中的鼠标消息。

(12) WH_MSGFILTER和WH_SYSMSGFILTER:前者仅监视传递到菜单、滚动条、消息框及传递到安装钩子子程的应用稗序建立的对话框消息。后者可监视所有应用程序消息。

(13) WH_SHELL:系统在以下情况调用该钩子子程。

·产生、激活或销毁一个top-level或unowned窗口

·任务栏需要重画某个按钮。

·系统需要任务栏显示一个程序的最小化形式。

·改变目前键盘布局。

·执行任务管理器或相同级别的程序。

按照惯例,外壳应刚程序不接收WH_SHELL消息,所以应用程序能够接收该消息之前序必须调用SystemParametersInfo函数注册自身。

需要说明的问题如下。

(1)对于同一事件(如鼠标消息)安装了线程钩子利系统钩子,则系统首先调用前者。

(2)对同一事件消息可安装多个钩子处理过程,这些钩子处理过程形成了钩子链,处理当前钩子后应把钩子信息传递给下一个钩子函数。

(3)钩子,特别是系统钩子会消耗消息处理时间,降低系统性能。只有在必要时才安装钩子,在使用后要及时卸载。2

本词条内容贡献者为:

李航 - 副教授 - 西南大学

科技工作者之家

科技工作者之家APP是专注科技人才,知识分享与人才交流的服务平台。