挂钩笔记一——挂钩的执行过程及一个例程

     系统钩子必须做成dll文件,否则不能映射到其他进程。

挂钩的执行过程:

1、声明一个全局变量(钩子句柄)

 var
  HookHandle: HHOOK;

2、定义一个钩子函数。不同的钩子类型对应着不同的钩子函数结构。stdcall不能少。

function TestHookProc(Code: Integer; WParam: Longint; Msg: Longint)
  : Longint; stdcall;
begin
  if (Code = HC_ACTION) then
    if PMsg(Msg)^.Message = WM_TestMessage then
    begin
      showMessage('已经截获该消息');
    end;
  Result := CallNextHookEx(HookHandle, Code, WParam, Longint(@Msg));
end;

3、挂钩

HookHandle := SetWindowsHookEx(WH_GETMESSAGE, TestHookProc, 0,GetCurrentThreadID);

4、卸钩

UnhookWindowsHookEx(HookHandle);


     挂钩函数SetWindowsHookEx介绍:

SetWindowsHookEx(
  idHook: Integer;   {钩子类型}
  lpfn: TFNHookProc; {函数指针}
  hmod: HINST;       {包含钩子函数的模块(EXE、DLL)句柄; 一般是 HInstance; 如果是当前线程这里可以是 0}
  dwThreadId: DWORD  {关联的线程; 可用 GetCurrentThreadId 获取当前线程; 0 表示是系统级钩子}
): HHOOK;            {返回钩子的句柄; 0 表示失败}

参数四 dwThreadId : 在设置全局钩子时这个参数一般是 0, 表示关联所有线程; 本例是线程级的钩子, 所以是
GetCurrentThreadId.

参数三 hmod: 是模块实例的句柄, 在 EXE 和 DLL 中都可以用 HInstance 得到当前实例的句柄; 直接用 API 也可以: 
GetModuleHandle(nil).

参数二 lpfn: 是钩子函数的指针, 用 @ 和 Addr 函数都可以得到函数指针; 这里的关键是那个钩子函数:
首先不同的钩子类型对应着不同的钩子函数结构, Win32 共有 14 种钩子类型;
本例用的是键盘钩子, 键盘钩子的回调函数的参数结构在 这里, 我们定义的函数名无所谓, 参数必须按照Windows的规定来.
还有, 这个回调函数的调用惯例必须是: stdcall; 我们在上例中是先在接口区声明, 如果不要声明直接实现, 也不能忘了这个 stdcall.

参数一
//钩子类型 idHook 选项:
WH_MSGFILTER       = -1; {线程级; 截获用户与控件交互的消息}
WH_JOURNALRECORD   = 0;  {系统级; 记录所有消息队列从消息队列送出的输入消息, 在消息从队列中清除时发生; 可用于宏记录}
WH_JOURNALPLAYBACK = 1;  {系统级; 回放由 WH_JOURNALRECORD 记录的消息, 也就是将这些消息重新送入消息队列}
WH_KEYBOARD        = 2;  {系统级或线程级; 截获键盘消息}
WH_GETMESSAGE      = 3;  {系统级或线程级; 截获从消息队列送出的消息}
WH_CALLWNDPROC     = 4;  {系统级或线程级; 截获发送到目标窗口的消息, 在 SendMessage 调用时发生}
WH_CBT             = 5;  {系统级或线程级; 截获系统基本消息, 譬如: 窗口的创建、激活、关闭、最大最小化、移动等等}
WH_SYSMSGFILTER    = 6;  {系统级; 截获系统范围内用户与控件交互的消息}
WH_MOUSE           = 7;  {系统级或线程级; 截获鼠标消息}
WH_HARDWARE        = 8;  {系统级或线程级; 截获非标准硬件(非鼠标、键盘)的消息}
WH_DEBUG           = 9;  {系统级或线程级; 在其他钩子调用前调用, 用于调试钩子}
WH_SHELL           = 10; {系统级或线程级; 截获发向外壳应用程序的消息}
WH_FOREGROUNDIDLE  = 11; {系统级或线程级; 在程序前台线程空闲时调用}
WH_CALLWNDPROCRET  = 12; {系统级或线程级; 截获目标窗口处理完毕的消息, 在 SendMessage 调用后发生}



 

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

const
  WM_TestMessage = WM_USER + 2000;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

var
  HookHandle: HHOOK;

function TestHookProc(Code: Integer; wParam: WPARAM; lParam: LPARAM)
  : LRESULT; stdcall;
begin
  if (Code = HC_ACTION) then
    if PMsg(lParam)^.Message = WM_TestMessage then
    begin
      //showMessage('已经截获该消息');
      OutputDebugString(PChar('WM_TestMessage:'+intToStr(WM_TestMessage)));
    end;
  Result := CallNextHookEx(HookHandle, Code, WParam, Longint(@lParam));
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  HookHandle := SetWindowsHookEx(WH_GETMESSAGE, @TestHookProc, 0,
    GetCurrentThreadID);
  OutputDebugString(PChar('钩子已经加载。'));
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  UnhookWindowsHookEx(HookHandle);
  OutputDebugString(PChar('钩子已经卸载。'));
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  PostMessage(self.Handle, WM_TestMessage, 0, 0);
end;

end.


 


 

posted @ 2011-11-04 11:14  cuibq  阅读(210)  评论(0编辑  收藏  举报