定义数据结构
代码语言:javascript复制 /// <summary>
/// 声明键盘钩子的封送结构类型
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public class KeyboardHookStruct
{
public int vkCode;//表示一个1到254间的虚拟键盘码
public int scanCode;//表示硬件扫描码
public int flags;
public int time;
public int dwExtraInfo;
}
声明Hook相关方法
代码语言:javascript复制 //使用WINDOWS API函数代替获取当前实例的函数,防止钩子失效
[DllImport("kernel32.dll")]
public static extern IntPtr GetModuleHandle(string lpModuleName);
//安装钩子
[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 int CallNextHookEx(int idHook, int nCode, Int32 wParam, IntPtr lParam);
//卸载钩子
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern bool UnhookWindowsHookEx(int idHook);
// 取得当前线程编号(线程钩子需要用到)
[DllImport("kernel32.dll")]
static extern int GetCurrentThreadId();
Hook拦截方法
全局Hook
代码语言:javascript复制 private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
{
if ((nCode >= 0) && (OnKeyDownEvent != null || OnKeyUpEvent != null || OnKeyPressEvent != null))
{
KeyboardHookStruct MyKBHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
//引发OnKeyDownEvent
if (OnKeyDownEvent != null && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN))
{
Keys keyData = (Keys)MyKBHookStruct.vkCode;
KeyEventArgs e = new KeyEventArgs(keyData);
OnKeyDownEvent(this, e);
}
}
return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
}
线程Hook
代码语言:javascript复制 private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
{
if ((nCode >= 0) && (OnKeyDownEvent != null || OnKeyUpEvent != null || OnKeyPressEvent != null))
{
//引发OnKeyDownEvent
if (OnKeyDownEvent != null && nCode==0)
{
Keys keyData = (Keys)wParam;
KeyEventArgs e = new KeyEventArgs(keyData);
OnKeyDownEvent(this, e);
}
}
return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
}
全局/线程Hook参数结构区别
代码语言:javascript复制线程Hook KeyboardHookProc函数的各个参数意义如下:
nCode 消息的类型,分HC_ACTION和HC_NOREMOVE
wParam 按键的虚拟键码
lParam 按键的相关参数信息,包括重复时间、按键的状态(按下或弹起)等
全局Hook KeyboardHookProc函数的各个参数意义如下:
nCode 消息的类型,有HC_ACTION
wParam 按键的状态(按下或弹起)WM_KEYDOWN、WM_KEYUP、WM_SYSKEYDOWN、WM_SYSKEYUP
lParam 指向KeyboardHookStruct结构的指针,该结构包含了按键的详细信息。
添加Hook
全局Hook
代码语言:javascript复制 public void Start()
{
if (hKeyboardHook == 0)
{
KeyboardHookProcedure = new HookProc(KeyboardHookProc);
using (System.Diagnostics.Process curProcess = System.Diagnostics.Process.GetCurrentProcess())
using (System.Diagnostics.ProcessModule curModule = curProcess.MainModule)
hKeyboardHook = SetWindowsHookEx(13, KeyboardHookProcedure, GetModuleHandle(curModule.ModuleName), 0);
if (hKeyboardHook == 0)
{
Stop();
throw new Exception("Set GlobalKeyboardHook failed!");
}
}
}
线程Hook
代码语言:javascript复制 public void Start()
{
if (hKeyboardHook == 0)
{
KeyboardHookProcedure = new HookProc(KeyboardHookProc);
hKeyboardHook = SetWindowsHookEx(2, KeyboardHookProcedure, IntPtr.Zero, GetCurrentThreadId());
if (hKeyboardHook == 0)
{
Stop();
throw new Exception("Set GlobalKeyboardHook failed!");
}
}
}
注:idHook 钩子类型,即确定钩子监听何种消息 线程钩子监听键盘消息应设为2,全局钩子监听键盘消息应设为13 线程钩子监听鼠标消息应设为7,全局钩子监听鼠标消息应设为14