参考文献:http://www.jb51.net/article/37365.htm
谈一下我对mouse Hook的理解。主要是
SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
这个是设置钩子的。IntPtr hInstance这个是回调函数,当钩子勾到消息后会进入到这个函数中。完成setWindowsHookEx各个参数就差不多了。
网上解释很多,但是感觉不好理解。还是这样做比较好理解一些。最后再调用CallNextHookEx。到最后不用的时候要释放钩子UnhookWindowsHookEx。
回调函数格式固定:public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);完成这个参数的填写就差不多完成了。下面的两个类是例子可以参考一下,已经实现了对鼠标的捕捉。using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; namespace TestHook { class Win32Api { #region Normal Data Struct public const int WM_KEYDOWN = 0x100; public const int WM_KEYUP = 0x101; public const int WM_SYSKEYDOWN = 0x104; public const int WM_SYSKEYUP = 0x105; public const int WH_KEYBOARD_LL = 13; public const int WH_MOUSE_LL = 14; public const int WM_MOUSEMOVE = 0x200; public const int WM_LBUTTONDOWN = 0x201; public const int WM_RBUTTONDOWN = 0x204; public const int WM_MBUTTONDOWN = 0x207; public const int WM_LBUTTONUP = 0x202; public const int WM_RBUTTONUP = 0x205; public const int WM_MBUTTONUP = 0x208; public const int WM_LBUTTONDBLCLK = 0x203; public const int WM_RBUTTONDBLCLK = 0x206; public const int WM_MBUTTONDBLCLK = 0x209; //define keyboard meesage struct [StructLayout(LayoutKind.Sequential)] public class KeyboardHookStruct { //Represents a virtual keyboard codes between 1 and 254 public int vkCode; //Indicate a hardware scan code public int scanCode; public int flags; public int time; public int dwExtraInfo; } //Declares a Point type is marshaled [StructLayout(LayoutKind.Sequential)] public class POINT { public int x; public int y; } //Declaring a mouse hook marshaled structure types [StructLayout(LayoutKind.Sequential)] public class MouseHookStruct { public POINT pt; public int hWnd; public int wHitTestCode; public int dwExtraInfo; } #endregion #region Api public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam); //install hook [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId); //uninstall hook [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, Int32 wParam, IntPtr lParam); [DllImport("user32")] public static extern int ToAscii(int uVirtKey, int uScanCode, byte[] lpbKeyState, byte[] lpwTransKey, int fuState); [DllImport("user32")] public static extern int GetKeyboardState(byte[] pbKeyState); [DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] public static extern IntPtr GetModuleHandle(string lpModuleName); [DllImport("User32.dll", CharSet = CharSet.Auto)] public static extern int GetWindowThreadProcessId(IntPtr hwnd, out int ID); #endregion #region Copied from Prism Management Studio Common [DllImport("user32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)] public static extern IntPtr GetForegroundWindow(); #endregion #region GetMessageExtraInfo [DllImport("user32.dll", EntryPoint = "GetMessageExtraInfo", SetLastError = true)] public static extern IntPtr GetMessageExtraInfo(); #endregion #region MapVirtualKey [DllImport("user32.dll")] public static extern UInt32 MapVirtualKey(UInt32 uCode, UInt32 uMapType); #endregion } }类:MouseHOOkusing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace TestHook { class MouseHook { //use to judge doubleClick private int doubleClickcount = 0; private DateTime lastClickTime; private int pointx = -1; private int pointy = -1; int hHook; public bool IsHooking = false; Win32Api.HookProc MouseHookDelegate; /// <summary> /// mouse down event /// </summary> public event MouseEventHandler OnMouseDownEvents; /// <summary> /// mouse doubleclick event /// </summary> public event MouseEventHandler OnDoubleClickEvents; /// <summary> /// mouse up event /// </summary> public event MouseEventHandler OnMouseUpEvents; /// <summary> /// mouse move event /// </summary> public event MouseEventHandler OnMouseMove; [DllImport("user32.dll")] public static extern int GetDoubleClickTime(); public MouseHook() { } ~MouseHook() { if (IsHooking) { Win32Api.UnhookWindowsHookEx(hHook); } } public bool SetHook() { MouseHookDelegate = new Win32Api.HookProc(MouseHookProc); Process cProcess = Process.GetCurrentProcess(); ProcessModule cModule = cProcess.MainModule; var mh = Win32Api.GetModuleHandle(cModule.ModuleName); hHook = Win32Api.SetWindowsHookEx(Win32Api.WH_MOUSE_LL, MouseHookDelegate, mh, 0); if (hHook == 0) return false; IsHooking = true; return true; } public void UnHook() { if (IsHooking) { if (Win32Api.UnhookWindowsHookEx(hHook)) { IsHooking = false; } } } private int MouseHookProc(int nCode, Int32 wParam, IntPtr lParam) { //if (nCode != 0) //{ //} MouseButtons button = MouseButtons.None; int delta = 0; int clickCount = 0; switch (wParam) { case Win32Api.WM_LBUTTONDOWN: button = MouseButtons.Left; clickCount = 1; delta = 1; break; case Win32Api.WM_LBUTTONUP: button = MouseButtons.Left; clickCount = 1; delta = 2; break; case Win32Api.WM_LBUTTONDBLCLK: button = MouseButtons.Left; clickCount = 2; delta = 1; break; case Win32Api.WM_RBUTTONDOWN: button = MouseButtons.Right; clickCount = 1; delta = 1; break; case Win32Api.WM_RBUTTONUP: button = MouseButtons.Right; clickCount = 1; delta = 2; break; case Win32Api.WM_RBUTTONDBLCLK: button = MouseButtons.Right; clickCount = 2; delta = 1; break; case Win32Api.WM_MBUTTONDOWN: button = MouseButtons.Middle; clickCount = 1; delta = 1; break; case Win32Api.WM_MBUTTONUP: clickCount = 1; delta = 2; break; case Win32Api.WM_MBUTTONDBLCLK: button = MouseButtons.Middle; clickCount = 2; delta = 1; break; } //delta = 1 when mouse down ,delta = 2 when mouse up //Do MouseDown Events if (wParam == Win32Api.WM_LBUTTONDOWN || wParam == Win32Api.WM_RBUTTONDOWN || wParam == Win32Api.WM_MBUTTONDOWN) { //get mouse callback info Win32Api.MouseHookStruct MyMouseHookStruct = (Win32Api.MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(Win32Api.MouseHookStruct)); MouseEventArgs e; System.TimeSpan clickTimeSpan = DateTime.Now - lastClickTime; lastClickTime = DateTime.Now; if (clickTimeSpan.TotalMilliseconds <= GetDoubleClickTime() && wParam == Win32Api.WM_LBUTTONDOWN && MyMouseHookStruct.pt.x == pointx && MyMouseHookStruct.pt.y == pointy) { doubleClickcount++; } else { doubleClickcount = 1; } pointx = MyMouseHookStruct.pt.x; pointy = MyMouseHookStruct.pt.y; if (doubleClickcount == 1) { if (OnMouseDownEvents != null) { e = new MouseEventArgs(button, clickCount, MyMouseHookStruct.pt.x, MyMouseHookStruct.pt.y, delta); OnMouseDownEvents(this, e); } } if (doubleClickcount == 2) { if (OnDoubleClickEvents != null) { e = new MouseEventArgs(button, doubleClickcount, MyMouseHookStruct.pt.x, MyMouseHookStruct.pt.y, delta); doubleClickcount = 0; OnDoubleClickEvents(this, e); } } } //Do MouseUp Events if (wParam == Win32Api.WM_LBUTTONUP || wParam == Win32Api.WM_MBUTTONUP || wParam == Win32Api.WM_RBUTTONUP) { //get mouse callback info Win32Api.MouseHookStruct MyMouseHookStruct = (Win32Api.MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(Win32Api.MouseHookStruct)); MouseEventArgs e = new MouseEventArgs(button, clickCount, MyMouseHookStruct.pt.x, MyMouseHookStruct.pt.y, delta); //check is registed events if (OnMouseUpEvents != null) { OnMouseUpEvents(this, e); } } if (wParam == Win32Api.WM_MOUSEMOVE) { //get mouse callback info Win32Api.MouseHookStruct MyMouseHookStruct = (Win32Api.MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(Win32Api.MouseHookStruct)); MouseEventArgs e = new MouseEventArgs(button, clickCount, MyMouseHookStruct.pt.x, MyMouseHookStruct.pt.y, delta); if (OnMouseMove != null) { OnMouseMove(this, e); } } return Win32Api.CallNextHookEx(hHook, nCode, wParam, lParam); } } }接下来对鼠标事件进行注册就行了。using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace TestHook { public partial class Form1 : Form { MouseHook mouseHook = new MouseHook(); TestDelegate s; public Form1() { InitializeComponent(); } private void btnName_Click(object sender, EventArgs e) { //mouseHook.OnMouseDownEvents += new MouseEventHandler(mouseDown); mouseHook.OnMouseDownEvents += mouseDown; mouseHook.SetHook(); } private void mouseDown(Object sender, MouseEventArgs e) { //this.Text = "X: " + e.X + " Y: " + e.Y; //s = (int x,int y) => { MessageBox.Show("X: " + x + " Y: " + y); }; s = new TestDelegate(showXY); s.BeginInvoke(e.X, e.Y, null, null);//开辟一个新线程,否则可能造成MainForm的卡顿。 } private void showXY(int x, int y) { Thread.Sleep(5000); UIDelegate UIDelegate = delegate () { this.Text = ("X: " + x + " Y: " + y); }; this.Invoke(UIDelegate);//使用Invoke调用可以解决跨线程访问控件的问题。 } private void btnCancel_Click(object sender, EventArgs e) { mouseHook.OnMouseDownEvents -= mouseDown; mouseHook.UnHook();} } public delegate void TestDelegate(int x, int y); public delegate void UIDelegate();}//string status = e.Delta == 1 ? "Down" : "Up"; //string leftOrMiddleOrRight = e.Button.ToString(); //string ClickStatus=e.Clicks==1? "Click" : "DoubleClick"; //MessageBox.Show("status: "+status+" leftorMiddleorRight: "+leftOrMiddleOrRight+" ClickStatus: "+ClickStatus);