楔子
网上关于Hook(钩子)的例子有很多,本文旨在简单且详细的介绍一下全局键盘的钩子,适合对钩子没有任何概念的人群,选用的IDE环境为VB.net和BCB6.0。
1.钩子的本质
什么是钩子(Hook)?
Windows的应用程序全部都是基于消息驱动的,而钩子,是一段用来处理系统消息的程序,是Windows消息的处理平台,从种类上可以分为多种,如键盘(WH_KEYBOARD),鼠标(WH_MOUSE)等,从监听的级别上又分为系统级和线程级,不过所谓的系统级其实也可以认为是线程级,稍后解释。
系统钩子,监听当前系统中所有指定的消息。但是系统钩子会影响到系统中的所有应用程序的运行,因此需要将钩子函数放入到独立的动态链接库当中,也就是要写一个独立的DLL文件来完成。系统会自动将包含钩子回调函数的DLL映射到受钩子函数影响的所有进程的地址空间当中。
2.用到的Windows的API
SetWindowsHookEx(int idHook, HooKPROC lpfn, HINSTANCE hMod, DWORD dwThreadId)
作用:
安装钩子
具体参数含义为:
idHook:
钩子的类型,如WH_KEYBOARD,就是想要监听什么消息
lpfn:
钩子过程的指针,就是回调函数,拦截到了消息之后处理函数的指针(函数在内存中的入口地址)
hMod:
应用程序实例的句柄。0表示自己
dwThreadId:
安装钩子的线程ID。0的话表示全局,即系统钩子,说到这里,提一下为什么说系统钩子实际上也是个线程够子,因为安装的钩子的线程ID是0,而Windows系统当中的线程ID为0的是谁?不错,就是桌面这个大窗口~,因为我们绝大部分的操作都是基于窗口消息的,而所有窗口的父窗口都是桌面这个大窗口,因此这个全局是相对与其他窗口程序的。
UnHookWindowsHookEx(HHOOK hkk)
作用:
注销钩子
具体参数含义为:
hKK:
钩子实例的名称
3.在VB.net中的实现
实现需要三个步骤:
(1) 了解什么是钩子
(2) 编写独立的钩子的dll
(3) 在VB.net中调用
我们已经完成了第一个,下面说第二个步骤
大家可以选用任何一种可以编写dll的工具,这里选用BCB6.0
(1)新建一个DLL
(2)代码如下:
DLL名称:
KeyHook.dll
- #include <vcl.h>
- #include <windows.h>
- #include "windef.h"
- #pragma hdrstop
- #pragma argsused
- typedef LRESULT ( CALLBACK *HookProc)(int code, WPARAM w, LPARAM l);
- typedef void (__stdcall CALLBACK *Bakfun)(WPARAM w,KBDLLHOOKSTRUCT* k);
- //变量定义
- HookProc g_lpfnkeyboardProc;
- Bakfun g_bakProc;
- HINSTANCE hins=NULL;
- static HHOOK hkb=NULL;
- int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
- {
- hins=hinst;
- return 1;
- }
- //回调函数
- LRESULT CALLBACK KeyboardProc(int nCode,WPARAM wParam,LPARAM lParam)
- {
- KBDLLHOOKSTRUCT* pstruct=(KBDLLHOOKSTRUCT*)lParam;
- g_bakProc(wParam,pstruct); //回调函数,进入vb.net处理函数中
- return CallNextHookEx( hkb, nCode, wParam, lParam );
- }
- //钩子启动函数
- extern "C" __declspec(dllexport) bool __stdcall installhook(Bakfun lp)
- {
- g_bakProc=lp;
- hkb=SetWindowsHookEx(WH_KEYBOARD_LL,(HOOKPROC)KeyboardProc,hins,0);
- return TRUE;
- }
- //卸载钩子函数
- extern "C" __declspec(dllexport) BOOL __stdcall UnHook()
- {
- BOOL unhooked = UnhookWindowsHookEx(hkb);
- return unhooked;
- }
在VB.net中的代码
- Public Declare Function installhook Lib "KeyHook.dll" (ByVal lp As HookProc) As Boolean
- Public Declare Sub UnHook Lib "KeyHook.dll" ()
- Public Delegate Sub HookProc(ByVal a As System.UIntPtr, ByVal ks As System.IntPtr)
- Public Structure KBDLLHOOKSTRUCT
- Dim vkCode As Integer
- Dim scanCode As Integer
- Dim flags As Integer
- Dim time As Integer
- Dim dwExtraInfo As Integer
- End Structure
- Public Enum KEYACTION
- ACTION_KEYDOWN = WM_KEYDOWN
- ACTION_KEYUP = WM_KEYUP
- ACTION_SYSKEYDOWN = WM_SYSKEYDOWN
- ACTION_SYSKEYUP = WM_SYSKEYUP
- End Enum
- Public Const WM_KEYDOWN =
- Public Const WM_KEYUP =
- Public Const WM_SYSKEYDOWN =
- Public Const WM_SYSKEYUP =
- Public Const DT_LEFT =
- Private Keys As Integer = 0
- Public Sub HookProc1(ByVal a As System.UIntPtr, ByVal ks As System.IntPtr)
- Dim kk As KBDLLHOOKSTRUCT
- Dim KeyboardEvent As KEYACTION = CType(a.ToUInt32, KEYACTION)
- If KeyboardEvent = KEYACTION.ACTION_KEYUP Then
- kk = System.Runtime.InteropServices.Marshal.PtrToStructure(ks, kk.GetType())
- Select Case kk.vkCode
- Case 88 'a的ASCII编码
- MessageBox.Show("a")
- End Select
- End If
- End Sub
在主窗口当中
- Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
- Static hkproc As HookProc
- hkproc = AddressOf HookProc1
- installhook(hkproc)
- End Sub
运行程序即可,在任何窗口下按下键盘上的"A"键,都可以看到弹出一个对话框
PS:
程序代码摘自http://www.ihome99.com/xiaowu/html/88/165788-32337.html