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); }
運行結果:
鼠標在窗口移動的時候,顯示鼠標當前的坐標位置(在整個顯示屏幕中的坐標)。