Hook钩子攻略

** 一。写在最前 ** ** **

本文的内容只想以最通俗的语言说明钩子的使用方法,具体到钩子的详细介绍可以参照下面的网址:

http://www.microsoft.com/china/community/program/originalarticles/techdoc/hook.mspx

** 二。了解一下钩子 **

从字面上理解,钩子就是想钩住些东西,在程序里可以利用钩子提前处理些 Windows 消息。

** 例子: ** 有一个 Form , Form 里有个 TextBox ,我们想让用户在 TextBox 里输入的时候,不管敲键盘的哪个键, TextBox 里显示的始终为“ A ”,这时我们就可以利用钩子监听键盘消息,先往 Windows 的钩子链表中加入一个自己写的钩子监听键盘消息,只要一按下键盘就会产生一个键盘消息,我们的钩子在这个消息传到 TextBox 之前先截获它,让 TextBox 显示一个“ A ”,之后结束这个消息,这样 TextBox 得到的总是“ A ”。

** 消息截获顺序: ** 既然是截获消息,总要有先有后,钩子是按加入到钩子链表的顺序决定消息截获顺序。就是说最后加入到链表的钩子最先得到消息。

** 截获范围: ** 钩子分为线程钩子和全局钩子,线程钩子只能截获本线程的消息,全局钩子可以截获整个系统消息。我认为应该尽量使用线程钩子,全局钩子如果使用不当可能会影响到其他程序。






** 三。开始通俗 ** ** **

这里就以上文提到的简单例子做个线程钩子。

** 第一步: ** 声明 API 函数

使用钩子,需要使用 WindowsAPI 函数,所以要先声明这些 API 函数。

// 安装钩子

[DllImport("user32.dll",CharSet=CharSet.Auto, CallingConvention=CallingConvention.StdCall)]

public static extern int SetWindowsHookEx( int idHook, HookProc lpfn, IntPtr hInstance, int threadId);

// 卸载钩子

[DllImport("user32.dll",CharSet=CharSet.Auto, CallingConvention=CallingConvention.StdCall)]

public static extern bool UnhookWindowsHookEx( int idHook);

// 继续下一个钩子

[DllImport("user32.dll",CharSet=CharSet.Auto, CallingConvention=CallingConvention.StdCall)]

public static extern int CallNextHookEx( int idHook, int nCode, Int32 wParam, IntPtr lParam);

// 取得当前线程编号

[DllImport("kernel32.dll")]

static extern int GetCurrentThreadId();

声明一下 API 函数,以后就可以直接调用了。


** 第二步: ** 声明、定义。

public delegate int HookProc( int nCode, Int32 wParam, IntPtr lParam);

static int hKeyboardHook = 0;

HookProc KeyboardHookProcedure;

先解释一下委托,钩子必须使用标准的钩子子程,钩子子程就是一段方法,就是处理上面例子中提到的让 TextBox 显示“ A ”的操作。

钩子子程必须按照 HookProc( int nCode, Int32 wParam, IntPtr lParam) 这种结构定义,三个参数会得到关于消息的数据。

当使用 SetWindowsHookEx 函数 安装钩子成功后会返回钩子子程的句柄, hKeyboardHook 变量记录返回的句柄,如果 hKeyboardHook 不为 0 则说明钩子安装成功。

** 第三步: ** 写钩子子程

钩子子程就是钩子所要做的事情。

private int KeyboardHookProc( int nCode, Int32 wParam, IntPtr lParam)

{

if (nCode >= 0)

{

textbox1.Text = “ A ” ;

return 1;

}

return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);

}

我们写一个方法,返回一个 int 值,包括三个参数。如上面给出的代码,符合钩子子程的标准。

nCode 参数是钩子代码,钩子子程使用这个参数来确定任务,这个参数的值依赖于 Hook 类型。

wParam 和 lParam 参数包含了消息信息,我们可以从中提取需要的信息。

方法的内容可以根据需要编写,我们需要 TextBox 显示“ A ”,那我们就写在这里。当钩子截获到消息后就会调用钩子子程,这段程序结束后才往下进行。截获的消息怎么处理就要看子程的返回值了,如果返回 1 ,则结束消息,这个消息到此为止,不再传递。如果返回 0 或调用 CallNextHookEx 函数 则消息出了这个钩子继续往下传递,也就是传给消息真正的接受者。

** 第四步: ** 安装钩子、卸载钩子

准备工作都完成了,剩下的就是把钩子装入钩子链表。

我们可以写两个方法在程序中合适位置调用。代码如下:

// 安装钩子

public void HookStart()

{

if (hMouseHook == 0)

{

// 创建 HookProc 实例

MouseHookProcedure = new HookProc(MouseHookProc);

// 设置线程钩子

hMouseHook = SetWindowsHookEx( 2, KeyboardHookProcedure, IntPtr.Zero,

GetCurrentThreadId());

// 如果设置钩子失败

if (hMouseHook == 0 )

{

HookStop();

throw new Exception("SetWindowsHookEx failed.");

}

}

}

// 卸载钩子

public void HookStop()

{

bool retKeyboard = true ;

if (hKeyboardHook != 0)

{

retKeyboard = UnhookWindowsHookEx(hKeyboardHook);

hKeyboardHook = 0;

}

if (!(retMouse && retKeyboard)) throw new Exception("UnhookWindowsHookEx

failed.");

}

安装钩子和卸载钩子关键就是 SetWindowsHookEx 和 UnhookWindowsHookEx 方法。

SetWindowsHookEx (int idHook, HookProc lpfn, IntPtr hInstance, int threadId) 函数将钩子加入到钩子链表中,说明一下四个参数:

** idHook ** 钩子类型,即确定钩子监听何种消息,上面的代码中设为 2 ,即监听键盘消息并且是线程钩子,如果是全局钩子监听键盘消息应设为 13 ,线程钩子监听鼠标消息设为 7 ,全局钩子监听鼠标消息设为 14 。

** lpfn ** 钩子子程的地址指针。如果 dwThreadId 参数为 0 或是一个由别的进程创建的线程的标识, lpfn 必须指向 DLL 中的钩子子程。 除此以外, lpfn 可以指向当前进程的一段钩子子程代码。钩子函数的入口地址,当钩子钩到任何消息后便调用这个函数。

** hInstance ** ** ** 应用程序实例的句柄。标识包含 lpfn 所指的子程的 DLL

Published At
Categories with Web编程
Tagged with
comments powered by Disqus