zoukankan      html  css  js  c++  java
  • C#系统钩子(转载)

    这几天用C#做了一个抓图软件,其中用到了系统钩子技术。

    在这里发表下自己用C#实现系统钩子的心得,希望对我的朋友们有所帮助。

    看了很多资料,都提到系统钩子(Hook)必须是一个dll,这样Windows才能在所有进程中共享钩子代码。

    与钩子相关的3个Windows API函数是:

    SetWindowsHookEx、UnhookWindowsHookEx、CallNextHookEx,它们的简要说明如下:

    HHOOK SetWindowsHookEx( 
    int  idHook, 
    HOOKPROC lpfn, 
    HINSTANCE hMod, 
    DWORD dwThreadId); 

    idHook -- 系统钩子类型,实际上是一个int值,具体的定义请看MSDN

    lpfn -- 钩子回调函数指针,当收到钩子消息时就执行这个回调函数,回调函数有3个参数,不同类型的钩子这3个参数有不同的含义,具体请看MSDN。

    hMod -- DLL实例句柄(我猜是这样,我不熟悉Win32API编程),当钩子为系统钩子时这个参数是必须的,如果是单个程序或者线程使用的钩子那么可以不用这个值。

    dwThreadId -- 线程ID,如果是单个程序或者线程使用的钩子这个参数是必须的。

    SetWindowsHookEx返回所设置的钩子的句柄。

    BOOL UnhookWindowsHookEx(HHOOK hhk);

    hhk -- 所要注销的钩子的句柄

    UnhookWindowsHookEx返回注销钩子是否成功。

    LRESULT CallNextHookEx( 
    HHOOK hhk, 
    int  nCode, 
    WPARAM wParam, 
    LPARAM lParam); 

    hhk -- 起始钩子句柄,如果是在钩子回调函数中调用CallNextHookEx时传的通常是本钩子句柄。

    nCode -- 钩子回调函数参数1,具体含义视钩子类型而定。

    wParam -- 钩子回调函数参数2,具体含义视钩子类型而定。

    lParam -- 钩子回调函数参数3,具体含义视钩子类型而定。

    从以上3个函数的简要说明可以看出所用到的参数几乎都是简单的参数,稍微复杂就是回调函数(在C#中用delegate类型来实现,后面会提到),但是最让人头疼的就是DLL的实例句柄,C#制作的DLL并不像C做的DLL有DllMain入口可以接受到DLL实例句柄。

    我目前唯一的办法就是使用C做一个系统钩子DLL再让C#调用。底下是DLL的代码。

    #define  _WIN32_WINNT 0x0500 

    #include 
    < Windows.h >  
    #include 
    < WinUser.h >  

    #define  Dll_Export __declspec(dllexport) 

    /* DLL实例句柄 */  

    HINSTANCE instance 
    =  NULL; 

    BOOL APIENTRY DllMain(HINSTANCE hInstance, DWORD  ul_reason_for_call, LPVOID lpReserved) 

     instance 
    =  hInstance; 
        
    return  TRUE; 
    }
     

    /*  
    *功能:设置系统钩子 
    *hookType -- 钩子类型 
    *hookproc -- 钩子回调函数 
    */
     

    Dll_Export HHOOK SetHook(
    int  hookType,HOOKPROC hookproc) 

     
    return  SetWindowsHookEx(hookType, hookproc, instance, NULL); 
    }
     

    /*  
    *功能:注销钩子 
    *hook -- 钩子句柄 
    */
     
    Dll_Export BOOL UnHook(HHOOK hook) 

     
    if (hook  !=  NULL) 
      
    return  UnhookWindowsHookEx(hook); 
     
    else  
      
    return   0
    }
     

    然后在C#项目中创建一个系统钩子类,提供创建钩子和注销钩子的接口,代码如下

    public   class  Hook 

         [DllImport(
    " LowLevelHook.dll " )] 
         
    public   extern   static  IntPtr SetHook( int  hookType, HookProc hookProc); 

         [DllImport(
    " LowLevelHook.dll " )] 
         
    public   extern  staticbool UnHook(IntPtr hook); 
     }


     上面用到的User32.HookProc类型不是.NET框架提供的,是自己定义的一个委托类型,声明如下

    public   delegate   int  HookProc( int  nCode, IntPtr wParam, IntPtr lParam); 

    现在你的C#程序就可以使用各种系统钩子了,我们目前已经使用的有低级别鼠标钩子和低级别键盘钩子。

    应用低级别鼠标钩子时会遇到这样一个问题:

    低级别鼠标钩子的回调函数lParam是一个MSLLHOOKSTRUCT结构体指针,C#中怎么获取这个结构体的实例呢?实现代码如下

    MSLLHOOKSTRUCT _mstr; 
    unsafe

       _mstr 
    =* (User32.MSLLHOOKSTRUCT * )lParam.ToPointer(); 
     }

    通过声明非安全代码来获取指针所指对象。

    MSLLHOOKSTRUCT结构体的C#定义如下:

    [StructLayout(LayoutKind.Sequential)] 
    public   struct  MSLLHOOKSTRUCT 

         
    public  Point Point; 
         
    public   int  MouseData; 
         
    public   int  Flags; 
         
    public   int  Time; 
         
    public   int  ExtraInfo; 
     }

          PS: 附件--系统钩子的源代码与DLL

    补充HookType枚举值,很抱歉一时疏忽忘记写出来,这些值可以在Win32 API 的相关头文件中找到,有LL字样的就是低级钩子:


            
    public   enum  HookTypes:  int
            
    {
                WH_JOURNALRECORD 
    =   0
    ,
                WH_JOURNALPLAYBACK 
    =   1
    ,
                WH_KEYBOARD 
    =   2
    ,
                WH_GETMESSAGE 
    =   3
    ,
                WH_CALLWNDPROC 
    =   4
    ,
                WH_CBT 
    =   5
    ,
                WH_SYSMSGFILTER 
    =   6
    ,
                WH_MOUSE 
    =   7
    ,
                WH_HARDWARE 
    =   8
    ,
                WH_DEBUG 
    =   9
    ,
                WH_SHELL 
    =   10
    ,
                WH_FOREGROUNDIDLE 
    =   11
    ,
                WH_CALLWNDPROCRET 
    =   12
    ,        
                WH_KEYBOARD_LL 
    =   13
    ,
                WH_MOUSE_LL 
    =   14
            
            }


    虽然上篇文章已经有但是还是要重点重复说明下CallNextHookEx函数,这个函数的功能是在执行完系统钩子的回调函数后接着调用下一个钩子函数,当设置的钩子是底层键盘或者鼠标钩子时如果不这么做将会时键盘和鼠标"失灵"。

            [DllImport("user32.dll")]
            
    public static extern int CallNextHookEx(IntPtr hookHandle, int nCode, IntPtr wParam, IntPtr lParam);

    这个函数第一个参数是钩子的句柄,在创建钩子时返回来的那个就是,后面3个参数和钩子回调函数的3个参数一一对应,照传就可以。

    因为公司现在装得是VS2005所以我只能先用VS2005做个试验程序了,这个程序功能是锁定鼠标一定时间,需要有.NET Framework 2.0 Runtime才能运行,我会尽快找台装VS2003的电脑做个.NET 1.1的范例的。

    可执行文件:https://files.cnblogs.com/BG5SBK/HookTest_NET2_Bin.rar
    项目文件:https://files.cnblogs.com/BG5SBK/HookTest_NET2_Source.rar
    系统钩子文件:https://files.cnblogs.com/BG5SBK/LowLevelHook.rar

    原文地址:http://www.cnblogs.com/bg5sbk/articles/299728.html

  • 相关阅读:
    iOS开发- UICollectionView详解+实例
    iOS 8出色的跨应用通信效果:解读Action扩展
    iOS开发宝典:String用法大全
    Masonry介绍与使用实践
    UILabel 行间距设置
    libc++abi.dylib: terminate_handler unexpectedly threw an exception错误小结
    适配iOS 8备忘录 开始启动(持续更新。。。1130)
    “System.AccessViolationException”类型的未经处理的异常在 System.Data.dll 中发生 其他信息: 尝试读取或写入受保护的内存。这通常指示其他内存已损坏
    HighCharts 详细使用及API文档说明
    跟我一起从零开始学WCF系列课程
  • 原文地址:https://www.cnblogs.com/bnuvincent/p/1525322.html
Copyright © 2011-2022 走看看