C# 封装一个钩子类

利用C#设置钩子函数,并封装成类。如果想要实现全局钩子的话,必须将实现的代码封装到类库里。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Diagnostics;
using System.Windows.Forms;

namespace PublicHook
{
    /// <summary>
    ///存放回调函数的委托
    /// </summary>
    public delegate int HOOKPROC(int nCode, IntPtr wParam, IntPtr lParam);
    public enum HookType
    {
        WH_KEYBOARD = 2,        //私有键盘钩子
        WH_EKYBOARD_LL = 13,    //全局键盘钩子
        WH_MOUSE = 7,           //私有鼠标钩子
        WH_MOUSE_LL = 14        //全局鼠标钩子
    }

    public abstract class hook
    {
        //设置钩子
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern int SetWindowsHookEx(HookType idHook, HOOKPROC lpfn, IntPtr hInstance, int threadId);
        //取下钩子
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern bool UnhookWindowsHookEx(int idHook);
        //获取当前线程一个唯一的线程标识符
        [DllImport("kernel32")]
        public static extern int GetCurrentThreadId();
        //传递消息给下一个钩子
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern int CallNextHookEx(int idHook, int nCode, IntPtr wParam, IntPtr lParam);
        //获取一个应用程序或动态链接库的模块句柄
        [DllImport("kernel32.dll")]
        public static extern IntPtr GetModuleHandle(string name);

        /// <summary>
        /// 钩子处理委托
        /// </summary>
        public HOOKPROC proc;
        /// <summary>
        /// 钩子类型
        /// </summary>
        public HookType type;
        /// <summary>
        /// 钩子的句柄
        /// </summary>
        public int hHook = 0;

        public hook(HOOKPROC proc, HookType type)
        {
            this.proc = proc;
            this.type = type;
        }
        //设置回调函数
        public void SetProc(HOOKPROC proc)
        {
            this.proc = proc;
        }

        public abstract int SetWindowsHookEx();
        public virtual void UnhookWindowsHookEx()
        {
            bool retKeyboard = true;
            //当前钩子句柄不为空,卸载钩子
            if (hHook != 0)
            {
                retKeyboard = UnhookWindowsHookEx(hHook);
                hHook = 0;
            }
            if (!retKeyboard)
                throw new Exception("UnhookWindowsHookEx failed.");
        }
    }

    public class PublicKBHook : hook
    {
        public PublicKBHook(HOOKPROC proc)
            : base(proc, HookType.WH_EKYBOARD_LL)
        { }
       
        public override int SetWindowsHookEx()
        {
            if (hHook == 0)
                hHook = SetWindowsHookEx(this.type, this.proc,
                    GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName), 0);
            return hHook;
        }

        //Hook结构
        [StructLayout(LayoutKind.Sequential)]
        public class HookStruct
        {
            public int vkCode;
            public int scanCode;
            public int flags;
            public int time;
            public int dwExtraInfo;
        }
        /// <summary>
        ///回调函数,屏蔽除了回车和tab之外的所有键盘消息
        /// </summary>
        public int MyKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if ( nCode >= 0 )                  
            {
                HookStruct hookStruct = (HookStruct)Marshal.PtrToStructure((IntPtr)lParam, typeof(HookStruct));
                //如果按下了回车,则将消息传给下一个钩子
                if ((Keys)hookStruct.vkCode == Keys.Enter ||
                    (Keys)hookStruct.vkCode == Keys.Tab)
                    return CallNextHookEx(hHook, nCode, wParam, lParam);
                //后门
                if ((Keys)hookStruct.vkCode == Keys.F1)
                    UnhookWindowsHookEx( hHook );
            }

            return 1;
        }
    }

    public class PrivateKBHook : hook
    {
        public PrivateKBHook(HOOKPROC proc)
            : base(proc, HookType.WH_KEYBOARD)
        { }

        public override int SetWindowsHookEx()
        {
            if (hHook == 0)
                hHook = SetWindowsHookEx(this.type, this.proc, IntPtr.Zero, GetCurrentThreadId());
            return hHook;
        }
    }

    public class PublicMouseHook : hook
    {
        public PublicMouseHook(HOOKPROC proc)
            : base(proc, HookType.WH_MOUSE_LL)
        { }

        public override int SetWindowsHookEx()
        {
            if (hHook == 0)
                hHook = SetWindowsHookEx(this.type, this.proc,
                    GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName), 0);
            return hHook;
        }

        /// <summary>
        /// 屏蔽除了鼠标移动之外的鼠标消息
        /// </summary>
        public int MyMouseProc(int nCode, IntPtr wParam, IntPtr lParam)
        {
            //当wParam = 0x0200 时,进行鼠标移动操作
            //直接将消息传递给下一个钩子
            if (wParam == (IntPtr)0x0200)
                return CallNextHookEx(hHook, nCode, wParam, lParam);

            return 1;
        }
    }

    public class PrivateMouseHook : hook
    {
        public PrivateMouseHook(HOOKPROC proc)
            : base(proc, HookType.WH_MOUSE)
        { }

        public override int SetWindowsHookEx()
        {
            if (hHook == 0)
                hHook = SetWindowsHookEx(this.type, this.proc, IntPtr.Zero, GetCurrentThreadId());

            return hHook;
        }
    }
}

调用代码:

            //钩子句柄
            int hKBHook = 0, hMouseHook = 0;
            //设置全局键盘钩子
            PublicKBHook myKBHook = new PublicKBHook(null);
            myKBHook.SetProc(myKBHook.MyKeyboardProc);
            hKBHook = myKBHook.SetWindowsHookEx();      

卸载钩子:

//撤销钩子
                myKBHook.UnhookWindowsHookEx();