鼠标钩子详解
钩的作用非常大,它能够预演和修改系统事件和消息,关能在系统范围内阻止事件和消息发生.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.
鼠标钩子详解
最新推荐文章于 2017-07-28 22:17:07 发布