1 简介
- C# 使用钩子的方式和C++基本上是一样的,因为直接使用了静态链接库user32.dll
- 我把鼠标钩子和键盘钩子封装成了两个工具类,有兴趣的朋友可以参考一下。项目的链接
- 使用的时候需要给定委托,委托的返回参数你可以参考DLL包下的两个类中的常量。注意,给定的委托函数内部不要写复杂的程序,委托的函数内部修改某个变量,然后外部开辟一个循环任务进行读取。如果委托函数内部的逻辑过于复杂,则读取数据的时候可能会有问题。
2 全局鼠标钩子
2.1 工具类
- 调用win10内置的DLL"user32.dll"
- 设置全局鼠标回调事件
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Input;
namespace RecordKeyBoardAndMouse.Service
{
class MouseHook
{
#region 常量
public const int WM_MOUSEMOVE = 0x200;
public const int WM_LBUTTONDOWN = 0x201;
public const int WM_RBUTTONDOWN = 0x204;
public const int WM_MBUTTONDOWN = 0x207;
public const int WM_LBUTTONUP = 0x202;
public const int WM_RBUTTONUP = 0x205;
public const int WM_MBUTTONUP = 0x208;
public const int WM_LBUTTONDBLCLK = 0x203;
public const int WM_RBUTTONDBLCLK = 0x206;
public const int WM_MBUTTONDBLCLK = 0x209;
public const int WH_MOUSE_LL = 14;
#endregion
#region 成员变量、回调函数、事件
public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);
public delegate void MyMouseEventHandler(Int32 wParam, MouseHookStruct mouseMsg);
private event MyMouseEventHandler OnMouseActivity;
private HookProc _mouseHookProcedure;
private static int _hMouseHook = 0;
private readonly object lockObject = new object();
private bool isStart = false;
#endregion
#region Win32的API
[StructLayout(LayoutKind.Sequential)]
public class MouseHookStruct
{
public POINT pt;
public int hWnd;
public int wHitTestCode;
public int dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
public class POINT
{
public int x;
public int y;
}
[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);
#endregion
#region 构造(单例模式)与析构函数
private static volatile MouseHook MyMouseHook;
private readonly static object createLock = new object();
private MouseHook() { }
public static MouseHook GetMouseHook()
{
if (MyMouseHook == null)
{
lock (createLock)
{
if (MyMouseHook == null)
{
MyMouseHook = new MouseHook();
}
}
}
return MyMouseHook;
}
~MouseHook()
{
Stop();
}
#endregion
public void Start()
{
if (isStart)
{
return;
}
lock (lockObject)
{
if (isStart)
{
return;
}
if (OnMouseActivity == null)
{
throw new Exception("Please set handler first!Then run Start");
}
if (_hMouseHook == 0)
{
_mouseHookProcedure = new HookProc(MouseHookProc);
_hMouseHook = SetWindowsHookEx(WH_MOUSE_LL, _mouseHookProcedure, Marshal.GetHINSTANCE(System.Reflection.Assembly.GetExecutingAssembly().GetModules()[0]), 0);
if (_hMouseHook == 0)
{
Stop();
throw new Exception("SetWindowsHookEx failed.");
}
}
isStart = true;
}
}
public void Stop()
{
if (!isStart)
{
return;
}
lock (lockObject)
{
if (!isStart)
{
return;
}
bool retMouse = true;
if (_hMouseHook != 0)
{
retMouse = UnhookWindowsHookEx(_hMouseHook);
_hMouseHook = 0;
}
if (!(retMouse))
throw new Exception("UnhookWindowsHookEx failed.");
OnMouseActivity = null;
isStart = false;
}
}
private int MouseHookProc(int nCode, Int32 wParam, IntPtr lParam)
{
if ((nCode >= 0) && (OnMouseActivity != null))
{
MouseHookStruct MyMouseHookStruct = (MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseHookStruct));
OnMouseActivity(wParam, MyMouseHookStruct);
}
return CallNextHookEx(_hMouseHook, nCode, wParam, lParam);
}
public void AddMouseHandler(MyMouseEventHandler handler)
{
OnMouseActivity += handler;
}
public void RemoveMouseHandler(MyMouseEventHandler handler)
{
if (OnMouseActivity != null)
{
OnMouseActivity -= handler;
}
}
}
}
2.2 使用
- 钩子函数为
- public delegate void MyMouseEventHandler(Int32 wParam,MouseHookStruct mouseMsg);
- wParam 代表发生的鼠标的事件,详情参考钩子类中的常量
- mouseMsg存储鼠标信息,其中的pt记录着鼠标的位置。
public void Start(MyMouseEventHandler handler)
{
mouseHook.AddMouseHandler(handler);
mouseHook.Start();
}
public void Stop()
{
mouseHook.Stop();
}
private void Handler(Int32 wParam,MouseHookStruct mouseMsg)
{
switch (wParam)
{
case WM_MOUSEMOVE:
x = mouseMsg.pt.x;
y = mouseMsg.pt.y;
break;
case WM_LBUTTONDOWN:
break;
case WM_LBUTTONUP:
break;
case WM_LBUTTONDBLCLK:
break;
case WM_RBUTTONDOWN:
break;
case WM_RBUTTONUP:
break;
case WM_RBUTTONDBLCLK:
break;
}
}
3 全局键盘钩子
3.1 钩子类
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Input;
namespace RecordKeyBoardAndMouse.DLL
{
class KeyboardHook
{
#region 常数和结构
#region wParam对应的按钮事件
public const int WM_KEYDOWN = 0x100;
public const int WM_KEYUP = 0x101;
public const int WM_SYSKEYDOWN = 0x104;
public const int WM_SYSKEYUP = 0x105;
#endregion
public const int WH_KEYBOARD_LL = 13;
[StructLayout(LayoutKind.Sequential)]
public class KeyboardHookStruct
{
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int dwExtraInfo;
}
#endregion
#region 成员变量、委托、事件
private static int hHook;
private static HookProc KeyboardHookDelegate;
public delegate void KeyboardHandler(Int32 wParam, KeyboardHookStruct
keyboardHookStruct);
private static event KeyboardHandler Handlers;
private readonly object lockObject = new object();
private volatile bool isStart = false;
#endregion
#region Win32的Api
private delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention =
CallingConvention.StdCall)]
private static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr
hInstance, int threadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention =
CallingConvention.StdCall)]
private static extern bool UnhookWindowsHookEx(int idHook);
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention =
CallingConvention.StdCall)]
private static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam,
IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention =
CallingConvention.StdCall)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
#endregion
#region 单例模式
private static volatile KeyboardHook MyKeyboard;
private readonly static object createLock = new object();
private KeyboardHook() { }
public static KeyboardHook GetKeyboardHook()
{
if (MyKeyboard == null)
{
lock (createLock)
{
if (MyKeyboard == null)
{
MyKeyboard = new KeyboardHook();
}
}
}
return MyKeyboard;
}
#endregion
public void Start()
{
if (isStart)
{
return;
}
lock (lockObject)
{
if (isStart)
{
return;
}
if (Handlers == null)
{
throw new Exception("Please set handler first!Then run Start");
}
KeyboardHookDelegate = new HookProc(KeyboardHookProc);
Process cProcess = Process.GetCurrentProcess();
ProcessModule cModule = cProcess.MainModule;
var mh = GetModuleHandle(cModule.ModuleName);
hHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookDelegate, mh, 0);
isStart = true;
}
}
public void Stop()
{
if (!isStart)
{
return;
}
lock (lockObject)
{
if (!isStart)
{
return;
}
UnhookWindowsHookEx(hHook);
Handlers = null;
isStart = false;
}
}
private static int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
{
if ((nCode >= 0) && Handlers != null)
{
KeyboardHookStruct KeyDataFromHook =
(KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
Handlers(wParam,KeyDataFromHook);
}
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
public void AddKeyboardHandler(KeyboardHandler handler)
{
Handlers += handler;
}
public void RemoveKeyboardHandler(KeyboardHandler handler)
{
if (Handlers != null)
{
Handlers -= handler;
}
}
}
}
3.2 使用
public void StartKeyboardHook(KeyboardHandler handler)
{
MyKeyboardHook.AddKeyboardHandler(handler);
MyKeyboardHook.Start();
}
public void StopKeyboardHook()
{
MyKeyboardHook.Stop();
}
- 回调函数
- recordService为上面那两个函数的类
- 使用lambda表达式传入回调函数,不要在内部有复杂的处理
- wParam为按键的状态,详情参考钩子类的常数部分
- keyboardHookStruct 存储被按下的按键的相关信息。详情参考虚拟按键
recordService.StartKeyboardHook((wParam, keyboardHookStruct) =>
{
keyStatus = wParam;
keyValue = keyboardHookStruct.vkCode;
});