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

    好久没写了,经历了考试周,现在又解放了。这2天有事,还是没有写,今晚简单整理下,写了个钩子程序玩玩~

    记得最早是人人某主页君写的一个钩子程序,作为愚人节礼物发到主页上的。当时觉得好神奇啊~最近在看1200例的书,第二卷一开始就说到了钩子程序,所以迫不及待的敲一遍,改一下,完成了基本功能~屏蔽所有的鼠标左键~哈哈~捉弄人的这是。。。。。。

    ******************************************分割线***************************************

    在钩子程序中,需要用到几个windows api函数。

    复制代码
        //声明钩子函数
            [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
            public static extern int SetWindowsHookEx(Int32 HookType, HOOKPROCEDURE methodAddress, IntPtr handler, Int32 dwThreadId);
            //释放钩子函数
            [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
            public static extern bool UnhookWindowsHookEx(IntPtr idHook);
    复制代码

    对于第一个函数,四个参数,分别指,钩子类型,消息处理函数地址,句柄(这个不太理解),线程ID

    对于第二个函数,只需要指出钩子的句柄就可以了。

    ******************************************分割线***************************************

    首先,建立一个基本的MouseHook类

    复制代码
    class MouseHook
        {
            public bool StartHook()
            {
                IntPtr InstallHook = IntPtr.Zero;
                if (this.mouseHandler == IntPtr.Zero)
                {
                    this.m_MouseHookProcedure = new HOOKPROCEDURE(MouseHookProcedure);
                    //安装钩子函数
                    this.mouseHandler = (IntPtr)SetWindowsHookEx(WH_MOUSE_LL, this.m_MouseHookProcedure, InstallHook, 0);
                    if (this.mouseHandler == IntPtr.Zero)
                    {
                        this.UnInstallHook();
                        return false;
                    }
                }
                return true;
            }
            public bool UnInstallHook()
            {
                bool Result = true;
                if (this.mouseHandler != IntPtr.Zero)
                {
                    Result = (UnhookWindowsHookEx(this.mouseHandler) && Result);
                    this.mouseHandler = IntPtr.Zero;
                }
    
                return Result;
            }
            
            public IntPtr mouseHandler = IntPtr.Zero;
            public event MouseEventHandler MouseDown;
            public static int flag = 0;
            //声明钩子函数
            [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
            public static extern int SetWindowsHookEx(Int32 HookType, HOOKPROCEDURE methodAddress, IntPtr handler, Int32 dwThreadId);
            //释放钩子函数
            [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
            public static extern bool UnhookWindowsHookEx(IntPtr idHook);
            //声明钩子函数地址
            public delegate int HOOKPROCEDURE(int nCode, Int32 wParam, IntPtr IParam);
            private HOOKPROCEDURE m_MouseHookProcedure;
            //定义使用户可以控制类或结构的数据字段的物理布局
            [StructLayout(LayoutKind.Sequential)]
            protected class MouseHookStruct
            {
                public POINT pt;
                public int mouseData;
                public int flags;
                public int time;
                public int dwExtraInfo;
            }
            [StructLayout(LayoutKind.Sequential)]
            protected class POINT
            {
                public int x;
                public int y;
            }
            //自定义的消息处理函数
            private int MouseHookProcedure(int nCode, Int32 wParam, IntPtr IParam)
            {
                if (nCode >= 0 && MouseDown != null)//判断是否处理该消息以及是否有鼠标按键被按下
                {
                    //定义一个结构体实例
                    MouseHookStruct mouseHookStruct = (MouseHookStruct)Marshal.PtrToStructure(IParam, typeof(MouseHookStruct));
                    MouseButtons button = GetButton(wParam);//获鼠标的按键类型
                    short mouseDelta = 0;//定义一个表示滑轮转动次数的变量
                    switch (wParam)
                    {
                        case WM_LBUTTONDOWN:
                        case WM_LBUTTONDBLCLK:
                        case WM_LBUTTONUP:
                            button = MouseButtons.Left;
                            flag = 1;
                            break;
                        case WM_RBUTTONDOWN:
                        case WM_RBUTTONDBLCLK:
                        case WM_RBUTTONUP:
                            button = MouseButtons.Right;flag=0;
                            break;
                        case WM_MOUSEWHEEL: flag = 0;
                            mouseDelta = (short)((mouseHookStruct.mouseData >> 16) & 0xffff);
                            break;
                        case WM_MOUSEMOVE: flag = 0; break;
                    }
                    int clickCount = 0;
                    //判断传递消息 表示的鼠标单击次数
                    if (wParam == WM_LBUTTONDBLCLK || wParam == WM_RBUTTONDBLCLK)
                        clickCount = 2;
                    else
                        clickCount = 1;
                    if (flag != 1)
                    {
                        //定义一个为鼠标事件提供数据的实例
                        System.Windows.Forms.MouseEventArgs e = new System.Windows.Forms.MouseEventArgs(button, clickCount, mouseHookStruct.pt.x, mouseHookStruct.pt.y, mouseDelta);
    
                        MouseDown(this, e);
                    }
                }
                return flag;
            }
            private MouseButtons GetButton(Int32 wParam)
            {
                switch (wParam)
                {
                    case WM_LBUTTONDOWN:
                    case WM_LBUTTONDBLCLK:
                    case WM_LBUTTONUP:
                        return MouseButtons.Left;
                    case WM_RBUTTONDOWN:
                    case WM_RBUTTONDBLCLK:
                    case WM_RBUTTONUP:
                        return MouseButtons.Right;
                    case WM_MBUTTONDBLCLK:
                    case WM_MBUTTONDOWN:
                    case WM_MBUTTONUP:
                        return MouseButtons.Middle;
                    default:
                        return MouseButtons.None;
                }
            }
            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;
            public const int WM_MOUSEWHEEL = 0x020A;
        }
    复制代码

    在整个类中,主要通过StartHookUnInstallHook来控制钩子的开启和关闭。

    在挂载钩子的时候,函数调用四个参数分别为: (IntPtr)SetWindowsHookEx(WH_MOUSE_LL, this.m_MouseHookProcedure, InstallHook, 0);

    WH_MOUSE_LL是一个const常量,指示钩子的类型,这里表示,此挂钩只能在Windows NT中被安装,用来对底层的鼠标输入事件进行监视。

    当然还有其余的值,不同的值代表不同的效果。

    第二个参数表示处理函数,第三个,这里给的值为0,同样,第四个线程ID也为0。线程ID填0表示,监测所有的消息,也就导致,就算我不是在当前winform下操作,也会被监测到~(其实这就是我想要的效果~尤记当年某主页君发的钩子程序)

    在这个地方,有一个疑问吧,第三个参数,不知道该如何写。按照书上的写法,总是无法安装钩子,但是将其值改为Zero后就可以了。。。。

    *****************************分割线*************************

    写完了hook类,接下来添加winform的代码:

    复制代码
    MouseHook mouseHook = new MouseHook();
            [DllImport("user32.dll", SetLastError = true)]
            public static extern bool RegisterHotKey(IntPtr Hwnd, int Id, KeyModifiers keyModifiers, Keys key);
            [DllImport("user32.dll", SetLastError = true)]
            public static extern bool UnregisterHotKey(IntPtr Hwnd, int Id);
            [Flags()]
            public enum KeyModifiers
            {
                None = 0,
                Alt = 1,
                Control = 2,
            }
            void Mouse_Down(object sender, MouseEventArgs e)
            { AddMouseValueEvent(e.Button.ToString()); }
            public void AddMouseValueEvent(string MouseValue)
            { }
            private void button1_Click(object sender, EventArgs e)
            {
                label1.Text = "F10解除钩子~";
                mouseHook.StartHook();
                mouseHook.MouseDown += new MouseEventHandler(Mouse_Down);
            }
    
            private void Form1_Load(object sender, EventArgs e)
            {
                Clipboard.Clear();
                RegisterHotKey(Handle, 100, 0, Keys.F10);
            }
    
            private void Form1_FormClosing(object sender, FormClosingEventArgs e)
            {
                UnregisterHotKey(Handle, 100);
            }
    
            protected override void WndProc(ref Message m)
            {
                const int WM_Key = 0x312;
                switch (m.Msg)
                {
                    case WM_Key:
                        mouseHook.UnInstallHook();
                        label1.Text = "好玩不~?";
                        break;
                }
                base.WndProc(ref m);
            }
    复制代码

    这里的Mouse_Down和AddMouseValueEvent仅仅做消息传递的功能。

    而,由于点击开始后,鼠标左键被我屏蔽了(mouseHook类中的消息处理,如果是鼠标左边,不进行MouseDown的消息传递)。所以,再添加一个系统热键F10进行解除屏蔽。这里使用了WndProc的重载,来过滤消息。

    *******************************分割线************************

    这样的钩子程序,不好给图演示效果。说一下这些代码的效果吧。当单机button之后,鼠标左键就再也没用了。就如同坏掉了一样。。。。右键和滑轮还是好的,可以使用。就算右键激活了其余的窗体,而不在HookLTest窗体下,鼠标左键一样没有效果~最后,只能按F10解除。

    但是,发觉这个代码还是可能存在问题。我经常性的运行后,资源管理器都有问题,最后都得重启资源管理器。不知道这个是由什么导致的。望知道的可以指点下。。。。

    然后,对于那个WH_MOUSE_LL。其实,还有别的值,不同的值对应不同的效果,看个人的需要吧。

    嘿嘿,Hook是捉弄人的好神器啊~

  • 相关阅读:
    Spring:dispatchservlet
    信息系统设计
    数据流图的绘制方法
    信息系统管理工程师学习笔记
    JS语法学习笔记
    jQuery
    用Excel生成Sql
    JAVA-Reflect
    Java创建对象的过程
    有关死锁那点事儿
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2878826.html
Copyright © 2011-2022 走看看