您的位置:首页 > 编程语言 > C#

看看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,完成了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: