什么是钩子(Hook)
钩子(Hook)是Windows提供的一种消息处理机制平台,是指在程序正常运行中接受信息之前预先启动的函数,用来检查和修改传给该程序的信息,(钩子)实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。注意:安装钩子函数将会影响系统的性能。监测“系统范围事件”的系统钩子特别明显。因为系统在处理所有的相关事件时都将调用您的钩子函数,这样您的系统将会明显的减慢。所以应谨慎使用,用完后立即卸载。还有,由于您可以预先截获其它进程的消息,所以一旦您的钩子函数出了问题的话必将影响其它的进程。
钩子的作用范围
一共有两种范围(类型)的钩子,局部的和远程的。局部钩子仅钩挂自己进程的事件。远程的钩子还可以将钩挂其它进程发生的事件。远程的钩子又有两种: 基于线程的钩子将捕获其它进程中某一特定线程的事件。简言之,就是可以用来观察其它进程中的某一特定线程将发生的事件。系统范围的钩子将捕捉系统中所有进程将发生的事件消息。
Hook 类型
Windows共有14种Hooks,每一种类型的Hook可以使应用程序能够监视不同类型的系统消息处理机制。下面描述所有可以利用的Hook类型的发生时机。详细内容可以查阅MSDN,这里只介绍我们将要用到的两种类型的钩子。
(1)WH_KEYBOARD_LL Hook
WH_KEYBOARD_LL Hook监视输入到线程消息队列中的键盘消息。
(2)WH_MOUSE_LL Hook
WH_MOUSE_LL Hook监视输入到线程消息队列中的鼠标消息。
下面的 class 把 API 调用封装起来以便调用。
- // NativeMethods.cs
- using System;
- using System.Runtime.InteropServices;
- using System.Drawing;
- namespace CnBlogs.Youzai.ScreenKeyboard
- {
- [StructLayout(LayoutKind.Sequential)]
- internal struct MOUSEINPUT
- {
- public int dx;
- public int dy;
- public int mouseData;
- public int dwFlags;
- public int time;
- public IntPtr dwExtraInfo;
- }
- [StructLayout(LayoutKind.Sequential)]
- internal struct KEYBDINPUT
- {
- public short wVk;
- public short wScan;
- public int dwFlags;
- public int time;
- public IntPtr dwExtraInfo;
- }
- [StructLayout(LayoutKind.Explicit)]
- internal struct Input
- {
- [FieldOffset(0)]
- public int type;
- [FieldOffset(4)]
- public MOUSEINPUT mi;
- [FieldOffset(4)]
- public KEYBDINPUT ki;
- [FieldOffset(4)]
- public HARDWAREINPUT hi;
- }
- [StructLayout(LayoutKind.Sequential)]
- internal struct HARDWAREINPUT
- {
- public int uMsg;
- public short wParamL;
- public short wParamH;
- }
- internal class INPUT
- {
- public const int MOUSE = 0;
- public const int KEYBOARD = 1;
- public const int HARDWARE = 2;
- }
- internal static class NativeMethods
- {
- [DllImport("User32.dll", CharSet = CharSet.Auto, SetLastError = false)]
- internal static extern IntPtr GetWindowLong(IntPtr hWnd, int nIndex);
- [DllImport("User32.dll", CharSet = CharSet.Auto, SetLastError = false)]
- internal static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
- [DllImport("User32.dll", EntryPoint = "SendInput", CharSet = CharSet.Auto)]
- internal static extern UInt32 SendInput(UInt32 nInputs, Input[] pInputs, Int32 cbSize);
- [DllImport("Kernel32.dll", EntryPoint = "GetTickCount", CharSet = CharSet.Auto)]
- internal static extern int GetTickCount();
- [DllImport("User32.dll", EntryPoint = "GetKeyState", CharSet = CharSet.Auto)]
- internal static extern short GetKeyState(int nVirtKey);
- [DllImport("User32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)]
- internal static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
- }
- }
安装钩子
使用SetWindowsHoo