将WINAPI的WINDOWSHOOKEX封装成C#的类,某些钩子类型只能用C/C++写的DLL才能运行,如CBT钩子,有些使用C#写的方法就能实现如:WH_KEYBOARD_LL ,WH_MOUSE_LL
因为IntPtr相当于一个VOID指针,因此在C#能够指向任何一个钩子类型的结构。用 Marshal 类的StructureToPtr,就能将定义的结构包装给IntPtr类型
using System;
using System.Text;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace FengCreateCLRDll {
namespace Win32API {
namespace WindowsHookEx{
/// <summary>
/// 只读的静态成员,用来表示钩子的类型,这个类不存储某些钩子类型,
/// 可以在WinUser.h中查找
/// </summary>
public class HookType {
public static readonly int WH_CALLWNDPROC = 4;
public static readonly int WH_JOURNALRECORD = 0;
public static readonly int WH_KEYBOARD = 2;
public static readonly int WH_GETMESSAGE = 3;
public static readonly int WH_CBT = 5;
public static readonly int WH_SYSMSGFILTER = 6;
public static readonly int WH_MOUSE = 7;
public static readonly int WH_DEBUG = 9;
public static readonly int WH_SHELL = 10;
public static readonly int WH_FOREGROUNDIDLE = 11;
public static readonly int WH_CALLWNDPROCRET = 12;
/// <summary>
/// LOWLEVEL键盘钩子类型
/// </summary>
public static readonly int WH_KEYBOARD_LL = 13;
/// <summary>
/// LOWLEVEL鼠标钩子类型
/// </summary>
public static readonly int WH_MOUSE_LL = 14;
private HookType() { }
};
/// <summary>
/// 处理钩子回调的函数。用户提供相对应的函数,作为这个委托的处理程序
/// </summary>
/// <param name="nCode">当这个参数大于0时才处理回调函数</param>
/// <param name="wParam">钩子消息,在不同钩子有不同的处理</param>
/// <param name="lParam">指向一个结构,可由Marshal.PtrToStructure转换成特定类型的结构</param>
/// <returns>如果要拦截某种类型钩子的消息,返回IntPtr.Zero或者其他处理;
/// 否则应调用CallNextHookEx作为返回值</returns>
public delegate IntPtr CallbackWindowsHookEx(int nCode,IntPtr wParam,IntPtr lParam);
/// <summary>
/// LOWlEVEL键盘钩子,回调函数的lParam参数指向的结构
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct KBDLLHOOKSTRUCT {
public int vkCode;
public int scanCode;
public int flags;
public int time;
public IntPtr dwExtraInfo;
};
/// <summary>
/// LOWlEVEL鼠标钩子,回调函数的lParam参数指向的结构
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct MSLLHOOKSTRUCT {
public POINT pt;
public int mouseData;
public int flags;
public int time;
public IntPtr extraInfo;
};
/// <summary>
/// 表示鼠标指针所在的X-Y坐标上的点
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct POINT {
public int x;
public int y;
};
/// <summary>
/// .net实现WINDOWS钩子的定义类
/// </summary>
public class CLRSetWindowsHookEx_Define {
/*typedef struct _MYHOOKDATA
{
int nType;
HOOKPROC hkprc;
HHOOK hhook;
} MYHOOKDATA;
MYHOOKDATA myhookdata[NUMHOOKS]; */
//例子通过数组的索引查找MYHOOKDATA结构的数据
//通过值建类型检索MYHOOKDATA结构××××××××××××××××××××
/// <summary>
/// 安装钩子函数
/// </summary>
/// <param name="idHook">钩子类型,可由FengCreateCLRDll.Win32API.WindowsHookEx.HookType
/// 静态字段获取指定的钩子类型</param>
/// <param name="lpfn">回调函数,用户必须定义一个跟FengCreateCLRDll.Win32API.WindowsHookEx.CallbackWindowsHookEx
/// 相同签名档函数</param>
/// <param name="hMod">模块句柄,该模块包含有CallbackWindowsHookEx回调的处理函数,
/// 如果指定了ThreadId参数,可为空值</param>
/// <param name="ThreadId">线程的ID,该线程关联钩子回调函数,如果设为0,回调函数同
/// 相同桌面下的所有的存在的、正在运行的线程相关联</param>
/// <returns>成功返回钩子的句柄,否则为空值</returns>
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr SetWindowsHookEx(
int idHook,
CallbackWindowsHookEx lpfn,
IntPtr hMod,
int ThreadId
);
/// <summary>
/// 作为回调函数的返回值使用
/// </summary>
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr CallNextHookEx(
IntPtr hhk,
int nCode,
IntPtr wParam,
IntPtr lParam
);
/// <summary>
/// 移除钩子函数
/// </summary>
[DllImport("user32.dll", SetLastError = true)]
public static extern int UnhookWindowsHookEx(IntPtr hhk);
/// <summary>
/// 获取指定模块的句柄,在这里用做SetWindowsHookEx函数的hMod参数
/// </summary>
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr GetModuleHandle(string lpModulename);
};
/// <summary>
/// 该类将某一种钩子类型实例化,当不用时应调用Dispose函数移除钩子,该类不会自动清除钩子
/// </summary>
public sealed class CLRSetWindowsHookEx_Ins:IDisposable {
private IntPtr hhook = IntPtr.Zero;//返回钩子的句柄
/// <summary>
/// 获取当前实例的钩子的句柄,即SetWindowsHookEx的返回值
/// </summary>
public IntPtr HHook {
get { return this.hhook; }
}
/// <summary>
/// 用来存储CallbackWindowsHookEx回调的字段,这样用户不必在实现代码的地方,实例化
/// 一个CallbackWindowsHookEx类型的变量,使用这个字段可防止回调实例被过早的回收。
/// 当然,用户也可另行实例化一个CallbackWindowsHookEx变量,然后用GC.KeepAlive保护该变量被
/// 过早的回收。另:不可使用多路广播委托,只能持有一个相同签名档方法.
/// </summary>
public CallbackWindowsHookEx HookProc=null;
/// <summary>
/// 该构造函数,同SetWindowsHookEx函数,将其返回值包装在此类中
/// </summary>
/// <param name="hooktype">可由FengCreateCLRDll.Win32API.WindowsHookEx.HookType获取钩子的类型</param>
/// <param name="hookproc">CallbackWindowsHookEx回调函数,用户可在现实代码处使用HookProc字段</param>
public CLRSetWindowsHookEx_Ins(int hooktype, CallbackWindowsHookEx hookproc
, IntPtr hMod, int ThreadId) {
this.hhook = CLRSetWindowsHookEx_Define.SetWindowsHookEx(hooktype,
hookproc , hMod, ThreadId);
}
/// <summary>
/// 该构造函数用来表示钩子只能在当前进程中使用,忽略了hMod和ThreadId参数
/// </summary>
/// <param name="hooktype">可由FengCreateCLRDll.Win32API.WindowsHookEx.HookType获取钩子的类型</param>
/// <param name="hookproc">CallbackWindowsHookEx回调函数,用户可在现实代码处使用HookProc字段</param>
public CLRSetWindowsHookEx_Ins(int hooktype, CallbackWindowsHookEx hookproc) {
this.hhook = CLRSetWindowsHookEx_Define.SetWindowsHookEx(
hooktype, hookproc,
CLRSetWindowsHookEx_Define.GetModuleHandle(
Process.GetCurrentProcess().MainModule.FileName),
0);
}
/// <summary>
/// 该方法用来移除实例化该类的所安装的钩子,当不再使用该类时,必须调用
/// 这个方法移除钩子
/// </summary>
public void Dispose() {
GC.KeepAlive(this.hhook);
if(!((int)this.hhook == -1 || (int)this.hhook == 6)){//错误、无效句柄
if(this.hhook != IntPtr.Zero) {
CLRSetWindowsHookEx_Define.UnhookWindowsHookEx
(this.hhook);
this.hhook = IntPtr.Zero;
}
}
GC.KeepAlive(this.HookProc);
if(this.HookProc!=null){
this.HookProc = null;
}
}
~CLRSetWindowsHookEx_Ins() { }
};
}
}
}