码迷,mamicode.com
首页 > Windows程序 > 详细

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

时间:2015-01-23 18:30:09      阅读:236      评论:0      收藏:0      [点我收藏+]

标签:wpf   hook   setwindowshookex   wm_keyboard_ll   

最近由于项目中需要精确记录某些操作的发生时间,但又没有办法打日志,因此写了个小工具,用来记录当前的毫秒级本机时间。
(程序内部实现了全局钩子,监听所有的键盘事件,即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.请保证回调处理函数的生命周期,要不然被垃圾回收器回收后找不到调用函数。



技术分享

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

标签:wpf   hook   setwindowshookex   wm_keyboard_ll   

原文地址:http://blog.csdn.net/muzizongheng/article/details/43057333

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!