C# 钩子函数使用

1. 什么是钩子

hook(钩子)是windows提供的一种消息处理机制平台,是指在程序正常运行中接受信息之前预先启动的函数,用来检查和修改传给该程序的信息,(钩子)实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出, 在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递(return)。

2. 钩子函数的声明

C#是.NET Framework平台的相伴语言,用它本身的类库和编译器提供的方法是无法实现全局钩子的。但实际上对于非托管代码的调用在C#中是成立的,钩子函数存在于user32.dll中,使用DllImport属性可以引用非托管代码类库中的方法。

钩子函数的安装:

  //安装钩子
        [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, IntPtr wParam, IntPtr lParam);

3.钩子函数的使用

首先声明一个委托:

        //委托+事件(把钩到的消息封装为事件,由调用者处理)

        public delegate void MouseMoveHandler(object sender, MouseEventArgs e);

        public event MouseMoveHandler MouseMoveEvent;

定义一个鼠标钩子类:

    public class MouseHook
    {

        private Point point;

        private Point Point
        {

            get { return point; }

            set
            {
                if (point != value)
                {
                    point = value;
                    if (MouseMoveEvent != null)
                    {
                        var e = new MouseEventArgs(MouseButtons.None, 0, point.X, point.Y, 0);
                        MouseMoveEvent(this, e);
                    }
                }
            }
        }

        private int hHook;

        public const int WH_MOUSE_LL = 14;

        public Win32Api.HookProc hProc;

        public MouseHook() { this.Point = new Point(); }

        public int SetHook()
        {

            hProc = new Win32Api.HookProc(MouseHookProc);

            hHook = Win32Api.SetWindowsHookEx(WH_MOUSE_LL, hProc, IntPtr.Zero, 0);

            return hHook;

        }

        public void UnHook()
        {

            Win32Api.UnhookWindowsHookEx(hHook);

        }

        private int MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam)
        {

            Win32Api.MouseHookStruct MyMouseHookStruct = (Win32Api.MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(Win32Api.MouseHookStruct));

            if (nCode < 0)
            {

                return Win32Api.CallNextHookEx(hHook, nCode, wParam, lParam);

            }

            else
            {

                this.Point = new Point(MyMouseHookStruct.pt.x, MyMouseHookStruct.pt.y);

                return Win32Api.CallNextHookEx(hHook, nCode, wParam, lParam);

            }

        }

        //委托+事件(把钩到的消息封装为事件,由调用者处理)

        public delegate void MouseMoveHandler(object sender, MouseEventArgs e);

        public event MouseMoveHandler MouseMoveEvent;

    }

调用钩子:

   public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        MouseHook mh;

        private void Form1_Load(object sender, EventArgs e)
        {

            mh = new MouseHook();

            mh.SetHook();

            mh.MouseMoveEvent += mh_MouseMoveEvent;

        }

        void mh_MouseMoveEvent(object sender, MouseEventArgs e)
        {

            int x = e.Location.X;

            int y = e.Location.Y;

            label1.Text = string.Format("当前鼠标位置为:({0},{1})", x, y);

        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {

            mh.UnHook();
        }
    }

Win32Api 导入类:

需要引入 using System.Runtime.InteropServices; 命名空间

public class Win32Api
    {

        [StructLayout(LayoutKind.Sequential)]
        public class POINT
        {
            public int x;

            public int y;

        }

        [StructLayout(LayoutKind.Sequential)]
        public class MouseHookStruct
        {

            public POINT pt;

            public int hwnd;

            public int wHitTestCode;

            public int dwExtraInfo;

        }

        public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);

        //安装钩子
        [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, IntPtr wParam, IntPtr lParam);

    }

运行结果:

 

 鼠标在窗口移动的时候,显示鼠标当前的坐标位置(在整个显示屏幕中的坐标)。

 

posted on 2020-06-08 15:56  积跬步---行千里  阅读(2544)  评论(0编辑  收藏  举报