鼠标钩子详解

来源:互联网 发布:淘宝咸鱼会不会被骗 编辑:程序博客网 时间:2024/05/22 10:22

钩的作用非常大,它能够预演和修改系统事件和消息,关能在系统范围内阻止事件和消息发生.Windows系统支持多种不同类型的钩,每种类型都只监控一种Windows消息流,下面是几种常见钩类型.

WH_MOUSE 监控鼠标输入事件

WH_KEYBOARD 监控键盘输入事件

WH_CALLWNDPROC 监控发送到窗口过程的消息,钩过程在消息发送到窗口过程前调用

WH_CALLWNDPROCRET监控发送到窗口过程的消息,钩过程在消息发送到窗口过程后调用

WH_CBT 监控CBT(如窗口创建,最大最小化等计算机使用培训相关的)消息

WH_SHEEL 监控Windows外壳通知消息,例如创建释放顶级窗口

      等等….

      为了使某种类型的钩发生作用,钩过程必须满足一定的语法条件,使用Win32 API 函数SetWindowsHookEx 来安装到钩链中.SetWindowsHookEx 函数具体定义为:

function SetWindowsHookEx(idHook: Integer; lpfn: TFNHookProc; hmod: HINST; dwThreadId: DWORD): HHOOK; stdcall;

      上述声明中,参数idHook 为钩过程类型, lpfn 参数为指向钩过程的指针, hmod 参数表示包含钩过程的DLL 的实例句柄, dwThreadId 参数表示钩过程要监控的线程,如果其值为0则表示将监控系统中的所有线程,如果SetWindowsHookEx 函数调用成功,则返回钩过程的句柄,否则为0;例如:

      SetWindowsHookEx(WH_MOUSE,HookHander,Hinstance,0);  //HookHander为钩过程

按照Delphi 的定义,所有钩过程都必须采用下述声明规范:

type

      TFNHookProc = function (code: Integer; wparam: WPARAM; lparam: LPARAM): LRESULT stdall;

Code 参数表示钩码, 其值取决钩过程的类型,钩过程需要使用该参数确定调用什么样的系统功能,wparam参灵符与iparam参数与code参数有关,通常用于保存已发送或投递消息信息.

      SetWindowsHookEx 函数习惯将新钩子到钩链的开头,当某种系统事件或消息发生时,该类型钩链中钩过程将依次获得该事件或消息的处理权,其中每个钩过程独立确定是否将该消息传到下一个钩过程,如果需要,则必须调用Win32 API 函数 CallNextHookEx.

注意在应用程序终止前必须调用 UnhookWindowsHookEx函数释放钩占用的系统资源,就是常说的脱钩啦….呵呵.

好了,我们现在就开始写一个鼠标钩子.获取所有进程的鼠标消息,需要用到系统钩子,所以要用到 DLL 才能截取,因此挂钩函数封装在 DLL 动态链接库中.

      首先我们定义钩的数据结构

      TShareMInfo =  record

              DataFirst: array[1..2] of DWORD;

       DataMouseInfo: TmouseHookStruct;

      End;

      PshareMInfo = ^ TshareMInfo;

定义钩过程

      function HookHandler(iCode: Integer; wParam: WPARAM; lParam: LPARAM); stdcall;

      定义安装钩和脱钩函数

      function StartHook(Sender: HWND; MessageID: WORD): BOOL; stdcall;

      function StopHook: BOOL; stdcall;

      详细代码如下: 

unit HookDllUnit;


 


 


interface


 


 


uses Windows, Messages, Dialogs, SysUtils.


 


 


const

  MappingFileName='_SelfDllMouse';


 


 


TShareMInfo =  record

DataFirst: array[1..2] of DWORD; // DataFirst[1] 为窗口句柄,DataFirst[2] 为消息

DataMouseInfo: TmouseHookStruct; //鼠标消息结构

End;

Var

PShMem: PShareMem;

  hMappingFile: THandle;

  FirstProcess: Boolean;

  NextHook: HHook;


 


 


  function StartHook(Sender: HWND; MessageID: WORD): BOOL; stdcall;

  function StopHook: BOOL; stdcall;


 


 


implementation


 


 


function HookHandler(iCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; export;

begin

  Result := 0;

  if iCode < 0  then

    Result := CallNextHookEx(NextHook,ICode,wParam,lParam);


 


 


  case wParam of

    WM_NCMOUSEMOVE, WM_MOUSEMOVE:

    begin

      PShMem^.DataTwo := PMOUSEHOOKSTRUCT(lParam)^;

      SendMessage(PShMem^.DataFirst[1],PShMem^.DataFirst[2],wParam,

                    integer(@(PShMem^.DataTwo)));

    end;

  end;

end;


 


 


function StartHook(Sender: HWND; MessageID: WORD): BOOL; stdcall;

begin

  Result := False;

  if NextHook <> 0 then Exit;

  PShMem^.DataFirst[1] := Sender;

  PShMem^.DataFirst[2] := MessageID;

  NextHook := SetWindowsHookEx(WH_MOUSE,HookHandler,HInstance,0);

  Result := NextHook <> 0;

end;


 


 


function StopHook: BOOL; stdcall;

begin

  if NextHook <> 0 then

  begin

    UnHookWindowsHookEx(NextHook);

    NextHook := 0;

  end;

  Result := NextHook = 0;

end;


 


 


initialization  //下列为内存映像文件来共享数据(也就是鼠标信息),这里不详细讲了

  hMappingFile := OpenFileMapping(FILE_MAP_WRITE,False,MappingFileName);

  if hMappingFile = 0 then

  begin

    hMappingFile := CreateFileMapping($FFFFFFFF,nil,PAGE_READWRITE,0,

                        SizeOf(TShareMem),MappingFileName);

    FirstProcess := True;

  end

  else FirstProcess := False;

  if hMappingFile = 0 then Exception.Create('Don''t Build Share Memory!');

  PShMem := MapViewOfFile(hMappingFile,FILE_MAP_WRITE or FILE_MAP_READ,0,0,0);

  if PShMem = nil then

  begin

    CloseHandle(hMappingFile);

    Exception.Create('Don''t Mapping Share Memory!');

  end;

  if FirstProcess then

  NextHook := 0;


 


 


finalization

  UnMapViewOfFile(PShMem);

  CloseHandle(hMappingFile);


 


 


end.

下面是DLL 代码;

library MouseDll;


 


 


uses

  SysUtils,

  Classes,

  HookDllUnit in 'Source/HookDllUnit.pas';


 


 


exports

  StartHook,StopHook;


 


 


begin

end.


 


 


下面是主窗口代码:

unit MainForm;


 


 


interface


 


 


uses

  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

  Dialogs, RzButton, StdCtrls , Mask, RzEdit, ExtCtrls, unit HookDllUnit;


 


 


type

  TForm1 = class(TForm)

    Capture: TRzBitBtn;

    XYLable: TRzLabel;

    procedure CaptureClick(Sender: TObject);

    procedure FormClose(Sender: TObject; var Action: TCloseAction);

    procedure FormCreate(Sender: TObject);

  private

    { Private declarations }

  public

    { Public declarations }

    procedure WndProc(var Messages: TMessage); override; //接受来自 MouseDLL 发送过来的消息

  end;


 


 


var

  Form1: TForm1;

  hMappingFile: THandle;

  PShmem: PShareMem;


 


 


const MessageID = WM_USER + 211; //自定义消息


 


 


implementation


 


 


function StartHook(sender : HWND;MessageID : WORD) : BOOL;stdcall; external 'MouseDll.DLL';

function StopHook: BOOL;stdcall; external 'MouseDll.DLL';


 


 


{$R *.dfm}


 


 


procedure TForm1.CaptureClick(Sender: TObject);

begin

    if capture.caption='Start' then

  begin

     if StartHook(Handle,MessageID) then

       capture.caption:='Stop';

  end

  else begin

    if StopHook then

       capture.caption:='Start';

  end;

end;


 


 


procedure TForm1.WndProc(var Messages: TMessage);

var

  X,Y: integer;

begin

  if PShMem = nil then

  begin

    hMappingFile := OpenFileMapping(FILE_MAP_WRITE,False,MappingFileName);

    if hMappingFile=0 then Exception.Create('Don''t Build Share Memory!');

    PShMem :=  MapViewOfFile(hMappingFile,FILE_MAP_WRITE or FILE_MAP_READ,0,0,0);

    if PShMem = nil then

    begin

       CloseHandle(hMappingFile);

       Exception.Create('Don''t Mapping Share Memory!');

    end;

// 上面取得DLL 共享数据

  end;

  if PShMem = nil  then Exit;

  if Messages.Msg = MessageID then

  begin

    X := PShMem^.DataTwo.pt.X;

    Y := PShMem^.DataTwo.pt.Y;

    XYLable.Caption := Format('X: º%d  Y : º%d',[X,Y]);

  end

  else inherited;

end;


 


 


procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);

begin

  if Capture.Caption = 'Stop' then

  else

    begin

      if StopHook  then

        Capture.Caption := 'Start';

    end;

end;


 


 


procedure TForm1.FormCreate(Sender: TObject);

begin

  PShMem := nil;

end;


 


 


end.


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/GARNETT2183/archive/2005/10/23/514038.aspx

原创粉丝点击