鼠标钩子程序
终于把我这个鼠标钩子程序实现了,刚开始我把句柄赋值赋错了,也就是SetWindowsHookEx(int idHook, HookProc lpfn,IntPtr hInstance, int threadId)的第三个参数,现在找好了,程序运行一切正常。
我这里实现了一个简单的鼠标钩子程序,用于监视鼠标,把获取的鼠标坐标显示在wpf应用窗口。
第一步:声明API函数
[DllImport("kernel32.dll")] public static extern IntPtr GetModuleHandle(string name); //安装钩子 [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(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
使用钩子,需要使用WindowsAPI函数,所以要先声明这些API函数。声明一下API函数,以后就可以直接调用了。
第二步:声明、定义
public delegate int HookProc(int nCode, int wParam, IntPtr lParam); public HookProc MyProcedure; //获取模块句柄 IntPtr intp = GetModuleHandle(null); //定义钩子句柄 public static int hHook = 0; //定义钩子类型 public const int WH_MOUSE_LL = 14;
钩子必须使用标准的钩子子程,钩子子程就是一段方法,就是处理上面提到的把获取的鼠标坐标显示在wpf应用窗口操作。
钩子子程必须按照HookProc(int nCode, int wParam, IntPtr lParam)这种结构定义,三个参数会得到关于消息的数据。
GetModuleHandle获取一个应用程序或动态链接库的模块句柄,参数null将返回自身应用程序句柄。
当使用SetWindowsHookEx函数安装钩子成功后会返回钩子子程的句柄,hHook变量记录返回的句柄,如果hHook不为0则说明钩子安装成功。
WH_MOUSE_LL参数用于截获整个系统的鼠标事件。
第三步:安装钩子、卸载钩子、写钩子子程
private void button1_Click(object sender, RoutedEventArgs e) { if(hHook==0) { IntPtr intp = GetModuleHandle("user32.dll"); MyProcedure = new HookProc(this.MouseHookProc); //这里挂节钩子 hHook = SetWindowsHookEx(WH_MOUSE_LL, MyProcedure, intp, 0); if (hHook == 0) { MessageBox.Show("SetWindowsHookEx Failed"); return; } button1.Content = "卸载钩子"; } else { bool ret = UnhookWindowsHookEx(hHook); if(ret == false ) { MessageBox.Show("UnhookWindowsHookEx Failed"); return; } hHook = 0; button1.Content = "安装钩子"; } } public int MouseHookProc(int nCode, int wParam, IntPtr lParam) { POINT MyPOINT = (POINT)Marshal.PtrToStructure(lParam, typeof(POINT)); if (nCode < 0) { return CallNextHookEx((IntPtr)hHook, nCode, (IntPtr)wParam, lParam); } else { String strCaption = "x = " + MyPOINT.x.ToString("d") + " y = " + MyPOINT.y.ToString("d"); text1.Text = strCaption; return CallNextHookEx((IntPtr)hHook, nCode, (IntPtr)wParam, lParam); } } } [StructLayout(LayoutKind.Sequential)] public class POINT { public int x; public int y; }
SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId)函数将钩子加入到钩子链表中,说明一下四个参数:
idHook 钩子类型,即确定钩子监听何种消息。
lpfn 钩子子程的地址指针。如果threadId参数为0 或是一个由别的进程创建的线程的标识,lpfn必须指向dll中的钩子子程。 除此以外,lpfn可以指向当前进程的一段钩子子程代码。钩子函数的入口地址,当钩子钩到任何消息后便调用这个函数。
hInstance应用程序实例的句柄。
趣味验证:
这个程序可以显示鼠标在任何位置的坐标,拖动鼠标时,程序会实时刷新显示鼠标的坐标。鲁大师测试我的电脑分辨率是1280x800,现在我们来验证下,运行我上面的程序,鼠标指向电脑屏幕左上角和右下角,分别显示如图:
代码清单:
public partial class MainWindow : Window { [DllImport("kernel32.dll")] public static extern IntPtr GetModuleHandle(string name); //安装钩子 [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(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam); public delegate int HookProc(int nCode, int wParam, IntPtr lParam); public HookProc MyProcedure; //获取模块句柄 IntPtr intp = GetModuleHandle(null); //定义钩子句柄 public static int hHook = 0; //定义钩子类型 public const int WH_MOUSE_LL = 14; public MainWindow() { InitializeComponent(); } private void button1_Click(object sender, RoutedEventArgs e) { if(hHook==0) { MyProcedure = new HookProc(this.MouseHookProc); //这里挂节钩子 hHook = SetWindowsHookEx(WH_MOUSE_LL, MyProcedure, intp, 0); if (hHook == 0) { MessageBox.Show("SetWindowsHookEx Failed"); return; } button1.Content = "卸载钩子"; } else { bool ret = UnhookWindowsHookEx(hHook); if(ret == false ) { MessageBox.Show("UnhookWindowsHookEx Failed"); return; } hHook = 0; button1.Content = "安装钩子"; } } public int MouseHookProc(int nCode, int wParam, IntPtr lParam) { POINT MyPOINT = (POINT)Marshal.PtrToStructure(lParam, typeof(POINT)); if (nCode < 0) { return CallNextHookEx((IntPtr)hHook, nCode, (IntPtr)wParam, lParam); } else { String strCaption = "x = " + MyPOINT.x.ToString("d") + " y = " + MyPOINT.y.ToString("d"); text1.Text = strCaption; return CallNextHookEx((IntPtr)hHook, nCode, (IntPtr)wParam, lParam); } } } [StructLayout(LayoutKind.Sequential)] public class POINT { public int x; public int y; }
2013-06-02