用VC++编写勾子程序

                                     用VC++编写勾子程序

一.什么是勾子:

Windows系统中,勾子(hook)是一种特殊的消息处理机制。勾子可以监视系统或进程中的各种事件消息,截获发往目标窗口的消息并进行处理。这样,我们就可以在系统中安装自定义的勾子,监视系统中特定事件的发生,完成特定的功能,比如截获键盘、鼠标的输入,屏幕取词,日志监视等等。可见,利用勾子可以实现许多特殊而有用的功能。因此,对于高级编程人员来说,掌握勾子的编程方法是很有必要的。
 二.勾子的类型
 

1按事件分类,有如下的几种常用类型

  (1) 键盘勾子和低级键盘勾子可以监视各种键盘消息。

  (2) 鼠标勾子和低级鼠标勾子可以监视各种鼠标消息。

  (3) 外壳勾子可以监视各种Shell事件消息。比如启动和关闭应用程序。

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

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

  此外,还有一些特定事件的勾子提供给我们使用,不一一列举。
 

  2. 按使用范围分类,主要有线程勾子和系统勾子

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

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

   几点需要说明的地方:

  (1) 如果对于同一事件(如鼠标消息)既安装了线程勾子又安装了系统勾子,那么系统会自动先调用线程勾子,然后调用系统勾子。

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

  (3) 勾子特别是系统勾子会消耗消息处理时间,降低系统性能。只有在必要的时候才安装勾子,在使用完毕后要及时卸载。
三.  编写勾子程序

编写勾子程序的步骤分为三步:定义勾子函数、安装勾子和卸载勾子。
 

 1.定义勾子函数

  勾子函数是一种特殊的回调函数。勾子监视的特定事件发生后,系统会调用勾子函数进行处理。不同事件的勾子函数的形式是各不相同的。下面以鼠标勾子函数举例说明勾子函数的原型:

LRESULT CALLBACK MouseProc
( int nCode, WPARAM wParam, LPARAM lParam)

  参数wParam和 lParam包含鼠标消息的信息,比如鼠标位置、状态等。nCode包含有关消息本身的信息,比如是否从消息队列中移出。

   我们先在勾子函数中实现自定义的功能,然后调用函数 CallNextHookEx.把勾子信息传递给勾子链的下一个勾子函数。CallNextHookEx.的原型如下:

LRESULT CallNextHookEx
( HHOOK hhk, int nCode, 
WPARAM wParam, LPARAM lParam )

  参数 hhk是勾子句柄。nCode、wParam和lParam 是勾子函数。下面的例子是一个简单的监视鼠标消息的勾子函数:

LRESULT CALLBACK MouseProc
(int nCode, WPARAM wParam, LPARAM lParam)
{        
//跟踪鼠标移动时的位置变化信息
if(wParam==WM_MOUSEMOVE || wParam==
           WM_NCMOUSEMOVE) 
{        //是鼠标移动消息
point=((MOUSEHOOKSTRUCT *)
lParam)->pt;//取鼠标信息
TRACE2(“Position is :%d,Y:%d"n",point.x,point.y);
}
//传递勾子信息
return CallNextHookEx(hHook,nCode,wParam,lParam);
}

  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)即可。

   值得注意的是线程勾子和系统勾子的勾子函数的位置有很大的差别。线程勾子一般在当前线程或者当前线程派生的线程内,而系统勾子必须放在独立的动态链接库中,实现起来要麻烦一些。


 

posted on 2008-06-02 14:08  路吾  阅读(501)  评论(0编辑  收藏  举报

导航