鼠标钩子程序

  终于把我这个鼠标钩子程序实现了,刚开始我把句柄赋值赋错了,也就是SetWindowsHookEx(int idHook, HookProc lpfn,IntPtr hInstance, int threadId)的第三个参数,现在找好了,程序运行一切正常。

  钩子(Hook),是windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的。当消息到达后,在目标窗口处理函数之前处理它。钩子机制允许应用程序截获处理windows消息或特定事件。
  钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。

  我这里实现了一个简单的鼠标钩子程序,用于监视鼠标,把获取的鼠标坐标显示在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;
    }
View Code

 

2013-06-02

posted @ 2013-06-02 19:38  woshiliyuan  阅读(...)  评论(...编辑  收藏