看看C# Hook 如何实现
2018-02-13 10:58
309 查看
目前的程序中想要添加Hook,截获键盘按键消息,所以上网找了一下关于C# Hook的东西。发现很多人都在说在添加C# Hook不成功和不稳定,而建议使用C++封一个Dll给C#使用。可喜的是最后我还是成功的在程序中使用C#添加了Hook,经过测试还是没有什么问题的。进行Hook需要使用三个API函数SetWindowsHookEx 进行Hook的注册UnhookWindowsHookEx 取消已经注册的HookCallNextHookEx 将消息传递给下一个Hook函数看一下定义[DllImport("user32.dll")]
private static extern IntPtr SetWindowsHookEx(
HookType code, HookProc func, IntPtr instance, int threadID);
[DllImport("user32.dll")]
private static extern int UnhookWindowsHookEx(IntPtr hook);
[DllImport("user32.dll")]
private static extern int CallNextHookEx(
IntPtr hook, int code, IntPtr wParam, ref KBDLLHOOKSTRUCT lParam);
我们需要定义一个delegate来接收消息private delegate int HookProc(int code, IntPtr wParam, ref KBDLLHOOKSTRUCT lParam);
定义两个event提供给外界使用public delegate void HookEventHandler(object sender, HookEventArgs e);
public event HookEventHandler KeyDown;
public event HookEventHandler KeyUp;
因为要接收的是键盘的消息所以要定义一些消息,和我们要接收的结构。public class HookEventArgs : EventArgs
{
// using Windows.Forms.Keys instead of Input.Key since the Forms.Keys maps
// to the Win32 KBDLLHOOKSTRUCT virtual key member, where Input.Key does not
public Keys Key;
public bool Alt;
public bool Control;
public bool Shift;
public HookEventArgs(UInt32 keyCode)
{
// detect what modifier keys are pressed, using
// Windows.Forms.Control.ModifierKeys instead of Keyboard.Modifiers
// since Keyboard.Modifiers does not correctly get the state of the
// modifier keys when the application does not have focus
this.Key = (Keys)keyCode;
this.Alt = (System.Windows.Forms.Control.ModifierKeys & Keys.Alt) != 0;
this.Control = (System.Windows.Forms.Control.ModifierKeys & Keys.Control) != 0;
this.Shift = (System.Windows.Forms.Control.ModifierKeys & Keys.Shift) != 0;
}
}
private enum HookType : int
{
WH_JOURNALRECORD = 0,
WH_JOURNALPLAYBACK = 1,
WH_KEYBOARD = 2,
WH_GETMESSAGE = 3,
WH_CALLWNDPROC = 4,
WH_CBT = 5,
WH_SYSMSGFILTER = 6,
WH_MOUSE = 7,
WH_HARDWARE = 8,
WH_DEBUG = 9,
WH_SHELL = 10,
WH_FOREGROUNDIDLE = 11,
WH_CALLWNDPROCRET = 12,
WH_KEYBOARD_LL = 13,
WH_MOUSE_LL = 14
}
public struct KBDLLHOOKSTRUCT
{
public UInt32 vkCode;
public UInt32 scanCode;
public UInt32 flags;
public UInt32 time;
public IntPtr extraInfo;
}
关键的在这里注册C# Hookprivate void Install()
{
if (_hookHandle != IntPtr.Zero)
return;
Module[] list = System.Reflection.Assembly.GetExecutingAssembly().GetModules();
System.Diagnostics.Debug.Assert(list != null && list.Length > 0);
_hookHandle = SetWindowsHookEx(_hookType,
_hookFunction, Marshal.GetHINSTANCE(list[0]), 0);
}
哦,还有HookType _hookType = HookType.WH_KEYBOARD_LL; 因为要截获键盘消息还有_hookFunction = new HookProc(HookCallback);其实最关键的是Marshal.GetHINSTANCE(list[0])得到当前程序的instance,这样这个C# Hook就是全局的C# Hook,这个位置也可以是null,这样就不是全局C# Hook。有个很奇怪的现象就是这个函数,在调试状态执行不能成功,而做成Release以后运行成功,所以你在做程序时,不要因为调试失败而对这个函数有怀疑,编一个Release版本的程序,独立运行再试一下。我使用的环境是VS2005 + Vista。接收消息的函数private int HookCallback(int code, IntPtr wParam, ref KBDLLHOOKSTRUCT lParam)
{
if (code < 0)
return CallNextHookEx(_hookHandle, code, wParam, ref lParam);
if ((lParam.flags & 0x80) != 0 && this.KeyUp != null)
this.KeyUp(this, new HookEventArgs(lParam.vkCode));
if ((lParam.flags & 0x80) == 0 && this.KeyDown != null)
{
this.KeyDown(this, new HookEventArgs(lParam.vkCode));
if (lParam.vkCode == 44)
{
return 1;
}
}
return CallNextHookEx(_hookHandle, code, wParam, ref lParam);
}
这里会区分KeyUp和KeyDown,注意一定要调用CallNextHookEx,这样会将这个消息在系统中继续传递,这很重要。除非你想阻止这个消息,也不希望其他程序再处理这个消息。下面最后的操作,释放注册。private void Uninstall()
{
if (_hookHandle != IntPtr.Zero)
{
UnhookWindowsHookEx(_hookHandle);
_hookHandle = IntPtr.Zero;
}
}
Ok,完成了。
private static extern IntPtr SetWindowsHookEx(
HookType code, HookProc func, IntPtr instance, int threadID);
[DllImport("user32.dll")]
private static extern int UnhookWindowsHookEx(IntPtr hook);
[DllImport("user32.dll")]
private static extern int CallNextHookEx(
IntPtr hook, int code, IntPtr wParam, ref KBDLLHOOKSTRUCT lParam);
我们需要定义一个delegate来接收消息private delegate int HookProc(int code, IntPtr wParam, ref KBDLLHOOKSTRUCT lParam);
定义两个event提供给外界使用public delegate void HookEventHandler(object sender, HookEventArgs e);
public event HookEventHandler KeyDown;
public event HookEventHandler KeyUp;
因为要接收的是键盘的消息所以要定义一些消息,和我们要接收的结构。public class HookEventArgs : EventArgs
{
// using Windows.Forms.Keys instead of Input.Key since the Forms.Keys maps
// to the Win32 KBDLLHOOKSTRUCT virtual key member, where Input.Key does not
public Keys Key;
public bool Alt;
public bool Control;
public bool Shift;
public HookEventArgs(UInt32 keyCode)
{
// detect what modifier keys are pressed, using
// Windows.Forms.Control.ModifierKeys instead of Keyboard.Modifiers
// since Keyboard.Modifiers does not correctly get the state of the
// modifier keys when the application does not have focus
this.Key = (Keys)keyCode;
this.Alt = (System.Windows.Forms.Control.ModifierKeys & Keys.Alt) != 0;
this.Control = (System.Windows.Forms.Control.ModifierKeys & Keys.Control) != 0;
this.Shift = (System.Windows.Forms.Control.ModifierKeys & Keys.Shift) != 0;
}
}
private enum HookType : int
{
WH_JOURNALRECORD = 0,
WH_JOURNALPLAYBACK = 1,
WH_KEYBOARD = 2,
WH_GETMESSAGE = 3,
WH_CALLWNDPROC = 4,
WH_CBT = 5,
WH_SYSMSGFILTER = 6,
WH_MOUSE = 7,
WH_HARDWARE = 8,
WH_DEBUG = 9,
WH_SHELL = 10,
WH_FOREGROUNDIDLE = 11,
WH_CALLWNDPROCRET = 12,
WH_KEYBOARD_LL = 13,
WH_MOUSE_LL = 14
}
public struct KBDLLHOOKSTRUCT
{
public UInt32 vkCode;
public UInt32 scanCode;
public UInt32 flags;
public UInt32 time;
public IntPtr extraInfo;
}
关键的在这里注册C# Hookprivate void Install()
{
if (_hookHandle != IntPtr.Zero)
return;
Module[] list = System.Reflection.Assembly.GetExecutingAssembly().GetModules();
System.Diagnostics.Debug.Assert(list != null && list.Length > 0);
_hookHandle = SetWindowsHookEx(_hookType,
_hookFunction, Marshal.GetHINSTANCE(list[0]), 0);
}
哦,还有HookType _hookType = HookType.WH_KEYBOARD_LL; 因为要截获键盘消息还有_hookFunction = new HookProc(HookCallback);其实最关键的是Marshal.GetHINSTANCE(list[0])得到当前程序的instance,这样这个C# Hook就是全局的C# Hook,这个位置也可以是null,这样就不是全局C# Hook。有个很奇怪的现象就是这个函数,在调试状态执行不能成功,而做成Release以后运行成功,所以你在做程序时,不要因为调试失败而对这个函数有怀疑,编一个Release版本的程序,独立运行再试一下。我使用的环境是VS2005 + Vista。接收消息的函数private int HookCallback(int code, IntPtr wParam, ref KBDLLHOOKSTRUCT lParam)
{
if (code < 0)
return CallNextHookEx(_hookHandle, code, wParam, ref lParam);
if ((lParam.flags & 0x80) != 0 && this.KeyUp != null)
this.KeyUp(this, new HookEventArgs(lParam.vkCode));
if ((lParam.flags & 0x80) == 0 && this.KeyDown != null)
{
this.KeyDown(this, new HookEventArgs(lParam.vkCode));
if (lParam.vkCode == 44)
{
return 1;
}
}
return CallNextHookEx(_hookHandle, code, wParam, ref lParam);
}
这里会区分KeyUp和KeyDown,注意一定要调用CallNextHookEx,这样会将这个消息在系统中继续传递,这很重要。除非你想阻止这个消息,也不希望其他程序再处理这个消息。下面最后的操作,释放注册。private void Uninstall()
{
if (_hookHandle != IntPtr.Zero)
{
UnhookWindowsHookEx(_hookHandle);
_hookHandle = IntPtr.Zero;
}
}
Ok,完成了。
相关文章推荐
- .net是如何实现Page.IsPostBack属性的?看看C#中关于IsPostBack的解释
- .net是如何实现Page.IsPostBack属性的?看看C#中关于IsPostBack的解释
- 如何在C# 中使用WMI 实现远程查询和共享
- 如何在C#中实现图片缩放
- 如何在C#中实现图片缩放
- 请问在.net framework精简版,使用C#语言如何实现MD5和SHA1算法
- 如何通过C#实现单据号码的自动增加。
- 如何在C#代码中实现在Sqlserver2000中添加用户?以及附加数据库?
- 如何在C#用WM_COPYDATA消息来实现两个进程之间传递数据
- 在ASP.NET中如何用C#.NET实现基于表单的验证
- 请问在C#中如何实现声音报警?
- [转]在ASP.NET中如何用C#.NET实现基于表单的验证(一)
- 如何使用 C# .NET 在 ASP.NET 应用程序中实现基于窗体的身份验证
- 如何通过C#实现单据号码的自动增加
- 如何在c#2005express的MenuStrip中实现item分隔(Done)
- 如何扮演另一个帐号(C#实现)
- 如何在VS.NET/C# Builder开发的网页中也能实现DOS下录入数据回车换行的功能
- 如何在C# 中使用WMI 实现远程查询和共享
- 如何在C#中实现全屏模式
- 在ASP.NET中如何用C#.NET实现基于表单的验证