好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

Hook钩子程序

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  ;
    } 

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

在挂载钩子的时候,函数调用四个参数分别为: ( 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是捉弄人的好神器啊~

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于Hook钩子程序的详细内容...

  阅读:41次