WPF毫秒级桌面时钟的实现-C#中Hook(钩子)的应用

最近由于项目中需要精确记录某些操作的发生时间,但又没有办法打日志,因此写了个小工具,用来记录当前的毫秒级本机时间。
(程序内部实现了全局钩子,监听所有的键盘事件,即KeyDown,KeyUp事件。)

工具功能如下:
1.通过任意键盘按键来记录当前时间
2.可以在列表处单击记录当前时间


C#中对于Hook API的包装如下:
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Reflection;
using  System.Runtime.InteropServices;
using  System.Text;

namespace  HookLib
{
     public  static  class  HookHelper
    {
         public  delegate  int  HookProc (
             int  nCode,
             IntPtr  wParam,
             IntPtr  lParam
            );

         public  static  int  HookCallback(  int  nCode,  IntPtr  wParam,  IntPtr  lParam)
        {
             if  ( IntPtr  .Zero == HookPtr ||  null  == HookId)
            {
                 return  0;
            }

             if  (nCode >= 0)
            {
                 if  ( null  != HookCallbackEvent)
                {
                     return  HookCallbackEvent(nCode, wParam, lParam);
                }
            }

             return  CallNextHookEx(HookPtr, HookId.Value, wParam, lParam);
        }

         public  static  IntPtr  SetWindowsHookEx()
        {
             if  ( null  == HookId)
            {
                 throw  new  Exception (  "You must set HookId first!"  );
            }

            HookPtr = SetWindowsHookEx(
                HookId.Value,
                KeyboardCallback,
                Instance,
                0);

             return  HookPtr;
        }

         public  static  bool  UnhookWindowsHookEx()
        {
             if  ( null  == HookPtr ||  IntPtr .Zero == HookPtr)
            {
                 throw  new  Exception (  "HookPtr is null" );
            }

             return  UnhookWindowsHookEx(HookPtr);
        }

         public  static  int  WH_KEYBOARD_LL = 13;

         public  static  IntPtr  HookPtr;
         public  static  int ? HookId = WH_KEYBOARD_LL;
         public  static  event  HookProc  HookCallbackEvent;
         public  static  HookProc  KeyboardCallback =  new  HookProc  ( HookHelper .HookCallback);
         public  static  IntPtr  Instance =  Marshal .GetHINSTANCE( Assembly  .GetAssembly( typeof (  HookHelper )).GetModules()[0]);

        #region  Win32API

        [  DllImport ( "User32.dll"  , CharSet =  CharSet .Unicode, CallingConvention =  CallingConvention .StdCall,
            SetLastError =  true )]
         public  static  extern  IntPtr  SetWindowsHookEx(
             int  idHook,
             HookProc  lpfn,  //如果是全局钩子,回调函数应该就写在dll内
             IntPtr  hMod,    //如果是全局钩子,应该是包含lpfn方法的dll句柄,注意此句柄要保持生命周期
             int  dwThreadId  //如果是全局钩子,置为0;否则应该是保护lpfn方法的进程id
            );

        [  DllImport ( "User32.dll"  , CharSet =  CharSet .Unicode, CallingConvention =  CallingConvention .StdCall,
            SetLastError =  true )]
         public  static  extern  int  CallNextHookEx(
             IntPtr  hhk,
             int  nCode,
             IntPtr  wParam,
             IntPtr  lParam
            );

        [  DllImport ( "User32.dll"  , CharSet =  CharSet .Unicode, CallingConvention =  CallingConvention .StdCall,
            SetLastError =  true )]
         public  static  extern  bool  UnhookWindowsHookEx(
             IntPtr  hhk
            );

        [  DllImport ( "Kernel32.dll"  , CharSet =  CharSet .Unicode, CallingConvention =  CallingConvention .StdCall)]
         public  static  extern  int  GetLastError();

        #endregion
    }
}
  
  
HookHelper的用法:
1.可以使用原始的win32 api,如
  public   static  extern   IntPtr  SetWindowsHookEx(
             int  idHook,
             HookProc  lpfn,
             IntPtr  hMod,
             int  dwThreadId
            );

2.可以使用包装好的2个方法,只要外部指定要处理的HookId(安装何种类型的钩子),以及处理钩子的回调函数HookCallbackEvent, 如
  private  void  MainView_Loaded  ( object  sender ,  System  . Windows .  RoutedEventArgs  e  )
        {
             //Add hook
             HookHelper . HookCallbackEvent  +=  F5Proc ;
             HookHelper . HookId  =  HookHelper .  WH_KEYBOARD_LL ;

             HookHelper . SetWindowsHookEx  ();
        }

注意事项:
1.如果是全局钩子,请把钩子的回调处理函数放在dll中
2.C#好像不支持wm_keyboard这样的钩子,需要替换为wm_keyboard_ll则可以
3.如果是全局钩子,请务必把进程实例设为回调函数所在dll的实例。
4.请保证回调处理函数的生命周期,要不然被垃圾回收器回收后找不到调用函数。


Demo 下载地址: http://download.csdn.net/detail/muzizongheng/8390369

你可能感兴趣的:(WPF,hook,wm_keyboard_ll)