zoukankan      html  css  js  c++  java
  • 鼠标钩子程序

      终于把我这个鼠标钩子程序实现了,刚开始我把句柄赋值赋错了,也就是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

  • 相关阅读:
    DHCP DHCPv6
    DHCPv6协议
    IPv6邻居发现协议
    CentOS下禁止防火墙
    centOS下更新yum源
    centOS下yum报错
    Flink+Kafka整合的实例
    Flink基本概念
    Ubuntu16.04下配置ssh免密登录
    Zookeeper+Kafka的单节点配置
  • 原文地址:https://www.cnblogs.com/yuanli/p/3114214.html
Copyright © 2011-2022 走看看