Chinaunix首页 | 论坛 | 博客
  • 博客访问: 8699823
  • 博文数量: 1413
  • 博客积分: 11128
  • 博客等级: 上将
  • 技术积分: 14685
  • 用 户 组: 普通用户
  • 注册时间: 2006-03-13 10:03
个人简介

follow my heart...

文章分类

全部博文(1413)

文章存档

2013年(1)

2012年(5)

2011年(45)

2010年(176)

2009年(148)

2008年(190)

2007年(293)

2006年(555)

分类:

2006-08-30 13:39:15

钩子函数并不是什么高深的技术,在 Microsoft的Win32  SDK手册上就有记述。不过很可惜秉承M$的一贯风格,要看懂可是不容易的事!而且它的例子是使用SDK写的,又不完整!这就让我们这些用只会 Delphi的程序员更看不懂了。不过用钩子函数是很有用的,例如鼠标钩子可以拦截下所有的鼠标消息的。  
前段时间我写我的第一个软件《聊天快贴》的时候,学习了一下鼠标钩子函数,现在我把我几周的学习成果写出来希望对大家有帮助。  
钩 子函数一共有12种(这里就不列举出来了,不过说实话我多数钩子也没有用过^_^),分为全局子和线程钩子两种。线程钩子就只监视某个线程,全局钩子可以 监视Windows的所有线程。具体的你可以看看Delphi  带的Win32  SDK,就是是全英文的,可惜了。全局钩子是必须用DLL加载,也就是说钩子函数这部分必须包装为一个DLL文件,然后再在主程序中调用钩子DLL中函 数才可以!而且有些钩子是必须以全局钩子的方式存在,也就是一定要用DLL包装它才可以。  
再解释一下设置钩子的Api函数:  
function  SetWindowsHookEx(idHook:  Integer;  lpfn:  TFNHookProc;  hmod:  HINST;  dwThreadId:  DWORD):  HHOOK;  stdcall;这是在Delphi下的说明,其中第一个参数是钩子的类型;第二个参数是钩子函数的地址;第个参数是包含钩子函数的模块句柄;第四个参 数指定监视的线程;返回钩子句柄。如果指定了某个确定的线程就只监视那个线程,即是线程钩子;如果为空,即是监视所有线程的全局钩子。其它几个相关函数就 没有什么讲的了,只要照着用就可以了。具体的看我的源程序吧!    
另外如果你只想使用进程钩子的话,有一个现成的控件可以用,就是Rx的 RxWindowHook控件。拖到你窗体上,设置Active为True就可以了。  然后他只有BeforeMessage(消息从消息队列取走前)和AfterMessage(消息从消息队列取走后)两个事件,响应他就可以了,怎么用 就看你的了。  
下面我说说比较实用的全局钩子的使用!我写了一个最简单的鼠标全局钩子的例子,我还假定你懂如何写DLL。好了,来看源程序:(BTW:我学习编程技巧的时候总是想看一些最简单的例子,可是有些作者习惯用复杂的应用作为例子。学起来真是痛苦!!!)  
 
一、DLL的工程文件。  
library  hookprj;  
 
uses  
SysUtils,  
Classes,  
hkprocunit  in  'hkprocunit.pas';  
 
{$R  *.RES}  
exports  
EnableMouseHook,  //只要把这两个函数输出就可以了,  
DisableMouseHook;//不会不懂函数的意思吧^_^。  
begin  
 
end.  
 
二、DLL输出函数的实现单元。  
 
unit  hkprocunit;  
 
interface  
 
uses  
Windows,Messages;  
 
var  
hHk:  HHOOK;//钩子的句柄值。  
function  MouseHookProc(nCode:  Integer;WParam:  WPARAM;LParam:  LPARAM):  LRESULT;stdcall;  
//鼠标钩子的回调函数,即是用它来处理得到消息后要干什么。这里我只是发送一个//WM_PASTE消息。  
//nCode参数是Hook的标志,一般只关心小于0时。看下面的详细说明  
//WParam参数表示鼠标消息的类型  
//LParam参数是一个指向  TMOUSEHOOKSTRUCT  结构的指针。结构包含了鼠标消息的状态,我只用了hwnd一个  
//即鼠标消息要传递给的窗口句柄。  
//返回值如果不是0的话windows就把这个消息丢掉,其它的程序就不会再收到这个消息了。  
 
function  EnableMouseHook:Boolean;  stdcall;  export;  
function  DisableMouseHook:Boolean;  stdcall;  export;//两个函数都是Boolean类型,成功都是返回True  
 
implementation  
 
function  MouseHookProc(nCode:  Integer;WParam:  WPARAM;LParam:  LPARAM):  LRESULT;stdcall;  
var  
MouseHookStruct:  ^TMOUSEHOOKSTRUCT;//这个结构Delphi在Windows单元有定义,直接用就可以了。  
nState:  SHORT;//得到键盘状态的GetKeyState函数的返回值。这是一个16位的数。    
begin  
Result  :=  0;  //最好首先给他一个返回值,不然会有警告的!记住这可不是C语言。  
//当nCode小于0时表示还有其它的Hook,必须把参数传给他。  
//此时就要用Api函数CallNextHookEx让他调用下一个Hook!!!当然不用好像也可以。    
if  nCode  <  0  then    
Result  :=  CallNextHookEx(hHk,nCode,WParam,LParam)//参数是现成的,直接用就可以了,  
//详细的说明可以参考Win32  SDK  
else  if  wParam  =  WM_LBUTTONDBLCLK  then  //判断是不是鼠标左键双击事件  
begin  
nState  :=  GetKeyState(VK_CONTROL);//这个函数只有一个参数,就是要得到的键的  
//键值,这里用windows的虚拟键值表示ctrl键。  
if  (nState  and  $8000)  =  $8000  then//如果按下了,那么返回值的最高位为1  
begin  //即是16进制的8000,如果没有按下就返回0  
MouseHookStruct  :=  Pointer(LParam);//转换指针并付值给MouseHookStruct变量。  
SendMessage(MouseHookStruct.hwnd,WM_PASTE,0,0);//如果条件都满足了就发送WM_PASTE(粘贴)消息  
end;  
end;  
 
end;  
 
function  EnableMouseHook:Boolean;  stdcall;  export;  
begin  
if  hHk  =  0  then  //为了安全,必须判断一下再设置钩子。  
Begin    
//  第三个参数的Hinstance  在Delphi中有定义,用就可以了。第四个参数必须为0  
hHk  :=  SetWindowsHookEx(WH_MOUSE,@MouseHookProc,Hinstance,0);  
Result  :=  True;  
end  
else  
Result  :=  False;  
end;  
 
function  DisableMouseHook:Boolean;  stdcall;  export;  
begin  
if  hHk  <>  0  then  //如果有钩子就卸掉他。  
begin  
UnHookWindowsHookEx(hHk);  
hHk  :=  0;  
Result  :=  True;  
end  
else  
Result  :=  False;  
end;  
 
end.  
 
三、使用钩子的应用程序的工程文件。  
 
program  Project1;  
 
uses  
Forms,  
Unit1  in  'Unit1.pas'  {Form1};  
 
{$R  *.RES}  
 
begin  
Application.Initialize;  
Application.CreateForm(TForm1,  Form1);  
Application.Run;  
end.  
 
四、使用钩子的应用程序代码。  
 
unit  Unit1;  
 
interface  
 
uses  
Windows,  Messages,  SysUtils,  Classes,  Graphics,  Controls,  Forms,  Dialogs,  
StdCtrls,  RxHook;  
 
type  
TForm1  =  class(TForm)  
Button1:  TButton;//放上两个Button和一个Edit控键用来试用我们的钩子函数。  
Button2:  TButton;  
Edit1:  TEdit;  
procedure  Button1Click(Sender:  TObject);  
procedure  Button2Click(Sender:  TObject);  
procedure  FormClose(Sender:  TObject;  var  Action:  TCloseAction);  
private  
{  Private  declarations  }  
 
 
public  
{  Public  declarations  }  
end;  
 
var  
Form1:  TForm1;  
//下面是引用hookprj.dll中的函数。  
function  EnableMouseHook:Boolean;  stdcall;  external  'Hookprj.dll'  name  'EnableMouseHook';  
function  DisableMouseHook:Boolean;  stdcall;  external  'Hookprj.dll'  name  'DisableMouseHook';  
implementation  
 
{$R  *.DFM}  
 
procedure  TForm1.Button1Click(Sender:  TObject);  
begin  
if  EnableMouseHook  then  
ShowMessage('启动钩子成功');  
end;  
 
procedure  TForm1.Button2Click(Sender:  TObject);  
begin  
if  DisableMouseHook  then  
ShowMessage('停止钩子成功');  
end;  
 
procedure  TForm1.FormClose(Sender:  TObject;  var  Action:  TCloseAction);  
begin  
//这里调用是必须的,否则有可能没有卸载钩子就退出了,那就不好了。    
DisableMouseHook;  
end;  
end.  
 
Windows2000  +  Delphi5.0sp1  测试通过  
 
好 了讲完了,如果你还有什么问题的话可以email  to  me:chen777@cmmail.com不过我也是菜鸟一个,太深了我也回答不了:(  不过大家可以讨论一下,共同进步!  还有如果你不想自己敲代码的话,可以到我的主页上下源程序最后要感谢我学校的图书馆,如果不是它收藏了 《Vc++  4开发人员指南》和《Win32  SDK》这两套书的中文版的话我也不能如此快的学到如何使用钩子^_^
阅读(1747) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~