多语言展示
当前在线:832今日阅读:167今日分享:16

详细讲解在C#中如何使用鼠标钩子

本文举例介绍如何使用Win32Api创建鼠标钩子。
工具/原料

Visual Studio(本文使用VS2013,其他版本亦可)。

基础知识
1

使用钩子之前,必须创建钩子,使用函数SetWindowsHookEx,函数原型如下:HHOOK WINAPI SetWindowsHookEx(__in int idHook,  \\钩子类型__in HOOKPROC lpfn,  \\回调函数地址__in HINSTANCE hMod,  \\实例句柄,钩子所在的实例的句柄__in DWORD dwThreadId);  \\线程ID,钩子所监视的线程的线程ID)函数说明:1、钩子的类型:分两种,全局钩子和局部钩子。全局钩子可以抓取其他进程的消息,分为抓取其他进程中某一特定线程的消息和抓取所有进程的消息两种。而局部钩子只抓取当前进程的消息。2、 回调函数。当抓取到消息时,操作系统将自动调用该函数处理消息。在C#中要使用委托。3、实例句柄,对于线程序钩子,参数传NULL;对于系统钩子:参数为钩子DLL的句柄。4、线程ID:对于全局钩子,该参数为NULL。

3

使用完钩子后一定要卸载钩子,否则可能会导致BUG,甚至导致死机。使用函数UnhookWin_dowsHookEx()卸载钩子即可。函数原形如下:BOOL UnhookWindowsHookEx(HHOOK  hhk    // 要卸载的钩子句柄。 )

鼠标钩子实例
1

启动VS,创建C# WinForm项目,如下:

2

主窗口Form1布局,如下:

3

添加新建类Win32Api,该类封装Api函数,代码如下:     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);    }

4

添加新建类MouseHook,该类封装对鼠标钩子的操作,代码如下:    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;    }

5

然后,在Form1中添加代码,如下: 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();        }    }

6

完成后,调试运行,结果如下:

注意事项
1

钩子使用后必须卸载。

2

钩子回调函数要足够简单。

3

通过事件可以把对消息的处理方法放在类的使用时。

推荐信息