`

.net 的hook 设计

    博客分类:
  • .net
阅读更多

今天,有个同事问我,怎样在C#中使用全局钩子?以前写的全局钩子都是用unmanaged C或C++写个DLL来实现,可大家都知道,C#是基于.Net Framework的,是managed,怎么实现全局钩子呢?于是开始到网上搜索,好不容易找到一篇,318804 - HOW TO: Set a Windows Hook in Visual C# .NET,里面详细的说明了如何使用鼠标钩子捕获鼠标的移动等,可是,它只能在Application里起作用,出了Application就没用了,就是说它还是没有实现全局钩子,而且文章结尾处说:“Global Hooks are not supported in the .NET Framework...”,这可怎么办呢?

  别担心,办法总是有的,经过一番摸索以后,发现WH_KEYBORAD_LL和WH_MOUSE_LL这两个low-level的hook可以被安装成全局的,这就好办了,我们不妨用这两个low-level的hook替换掉WH_KEYBORAD和WH_MOUSE,于是开始测试。结果成功了,在C#里实现了全局钩子。

  我们来看一下主要代码段。

  首先倒入所需要的windows函数,主要有三个,SetWindowsHookEX用来安装钩子,UnhookWindowsHookEX用来卸载钩子以及CallNextHookEX用来将hook信息传递到链表中下一个hook处理过程。

[DllImport("user32.dll", CharSet = CharSet.Auto,
           CallingConvention 
= CallingConvention.StdCall, SetLastError = true)]
        
private static extern int SetWindowsHookEx(
            
int idHook,
            HookProc lpfn,
            IntPtr hMod,
            
int dwThreadId);

[DllImport(
"user32.dll", CharSet = CharSet.Auto,
            CallingConvention 
= CallingConvention.StdCall, SetLastError = true)]
        
private static extern int UnhookWindowsHookEx(int idHook);

[DllImport(
"user32.dll", CharSet = CharSet.Auto,
             CallingConvention 
= CallingConvention.StdCall)]
        
private static extern int CallNextHookEx(
            
int idHook,
            
int nCode,
            
int wParam,
            IntPtr lParam);

  下面是有关这两个low-level hook在Winuser.h中的定义:

/// <summary>
        
/// Windows NT/2000/XP: Installs a hook procedure that monitors low-level mouse input events.
        
/// </summary>

        private const int WH_MOUSE_LL       = 14;
        
/// <summary>
        
/// Windows NT/2000/XP: Installs a hook procedure that monitors low-level keyboard  input events.
        
/// </summary>

        private const int WH_KEYBOARD_LL    = 13;

  在安装全局钩子的时候,我们就要做替换了,将WH_MOUSE和WH_KEYBORAD分别换成WH_MOUSE_LL和WH_KEYBORAD_LL:

//install hook
                hMouseHook = SetWindowsHookEx(
                    WH_MOUSE_LL, 
//原来是WH_MOUSE
                    MouseHookProcedure,
                    Marshal.GetHINSTANCE(
                        Assembly.GetExecutingAssembly().GetModules()[
0]),
                    
0);

//install hook
                hKeyboardHook = SetWindowsHookEx(
                    WH_KEYBOARD_LL, 
//原来是WH_KEYBORAD
                    KeyboardHookProcedure,
                    Marshal.GetHINSTANCE(
                    Assembly.GetExecutingAssembly().GetModules()[
0]),
                    
0);
 
  这样替换了之后,我们就可以实现全局钩子了,而且,不需要写DLL。看一下程序运行情况:



  下面是关于鼠标和键盘的两个Callback函数:

private int MouseHookProc(int nCode, int wParam, IntPtr lParam)

        {

            // if ok and someone listens to our events

            if ((nCode >= 0) && (OnMouseActivity != null))

            {

                //Marshall the data from callback.

                MouseLLHookStruct mouseHookStruct = (MouseLLHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseLLHookStruct));

 

                //detect button clicked

                MouseButtons button = MouseButtons.None;

                short mouseDelta = 0;

                switch (wParam)

                {

                    case WM_LBUTTONDOWN:

                        //case WM_LBUTTONUP:

                        //case WM_LBUTTONDBLCLK:

                        button = MouseButtons.Left;

                        break;

                    case WM_RBUTTONDOWN:

                        //case WM_RBUTTONUP:

                        //case WM_RBUTTONDBLCLK:

                        button = MouseButtons.Right;

                        break;

                    case WM_MOUSEWHEEL:

                        //If the message is WM_MOUSEWHEEL, the high-order word of mouseData member is the wheel delta.

                        //One wheel click is defined as WHEEL_DELTA, which is 120.

                        //(value >> 16) & 0xffff; retrieves the high-order word from the given 32-bit value

                        mouseDelta = (short)((mouseHookStruct.mouseData >> 16) & 0xffff);

                        //TODO: X BUTTONS (I havent them so was unable to test)

                        //If the message is WM_XBUTTONDOWN, WM_XBUTTONUP, WM_XBUTTONDBLCLK, WM_NCXBUTTONDOWN, WM_NCXBUTTONUP,

                        //or WM_NCXBUTTONDBLCLK, the high-order word specifies which X button was pressed or released,

                        //and the low-order word is reserved. This value can be one or more of the following values.

                        //Otherwise, mouseData is not used.

                        break;

                }

 

                //double clicks

                int clickCount = 0;

                if (button != MouseButtons.None)

                    if (wParam == WM_LBUTTONDBLCLK || wParam == WM_RBUTTONDBLCLK) clickCount = 2;

                    else clickCount = 1;

 

                //generate event

                 MouseEventArgs e = new MouseEventArgs(

                                                    button,

                                                    clickCount,

                                                    mouseHookStruct.pt.x,

                                                    mouseHookStruct.pt.y,

                                                    mouseDelta);

                //raise it

                OnMouseActivity(this, e);

            }

            //call next hook

            return CallNextHookEx(hMouseHook, nCode, wParam, lParam);

        }


private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
 
{
            
//indicates if any of underlaing events set e.Handled flag
            bool handled = false;
            
//it was ok and someone listens to events
            if ((nCode >= 0&& (KeyDown != null || KeyUp != null || KeyPress != null))
            
{
                
//read structure KeyboardHookStruct at lParam
                KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
                
//raise KeyDown
                if (KeyDown != null && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN))
                
{
                    Keys keyData 
= (Keys)MyKeyboardHookStruct.vkCode;
                    KeyEventArgs e 
= new KeyEventArgs(keyData);
                    KeyDown(
this, e);
                    handled 
= handled || e.Handled;
                }


                
// raise KeyPress
                if (KeyPress != null && wParam == WM_KEYDOWN)
                
{
                    
bool isDownShift = ((GetKeyState(VK_SHIFT) & 0x80== 0x80 ? true : false);
                    
bool isDownCapslock = (GetKeyState(VK_CAPITAL) != 0 ? true : false);

                    
byte[] keyState = new byte[256];
                    GetKeyboardState(keyState);
                    
byte[] inBuffer = new byte[2];
                    
if (ToAscii(MyKeyboardHookStruct.vkCode,
                              MyKeyboardHookStruct.scanCode,
                              keyState,
                              inBuffer,
                              MyKeyboardHookStruct.flags) 
== 1)
                    
{
                        
char key = (char)inBuffer[0];
                        
if ((isDownCapslock ^ isDownShift) && Char.IsLetter(key)) key = Char.ToUpper(key);
                        KeyPressEventArgs e 
= new KeyPressEventArgs(key);
                        KeyPress(
this, e);
                        handled 
= handled || e.Handled;
                    }

                }


                
// raise KeyUp
                if (KeyUp != null && (wParam == WM_KEYUP || wParam == WM_SYSKEYUP))
                
{
                    Keys keyData 
= (Keys)MyKeyboardHookStruct.vkCode;
                    KeyEventArgs e 
= new KeyEventArgs(keyData);
                    KeyUp(
this, e);
                    handled 
= handled || e.Handled;
                }


            }


            
//if event handled in application do not handoff to other listeners
            if (handled)
                
return 1;
            
else
                
return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
        }

 

 

分享到:
评论

相关推荐

    .NET Easy Hook Library and Sample

    .NET Easy Hook Library and Sample 是一个专为.NET开发者设计的库,它简化了在Windows系统中实现钩子(Hook)技术的过程。Hook技术是Windows编程中的一种常见手法,用于拦截和处理系统或应用程序级别的消息和调用,...

    hook+WSASend源码

    【描述】中提到,这个源码包是以.e格式存储的,这意味着它可能是专为一种特定的编程环境或语言设计的,即'e'语言。使用.e语言编辑器来查看和编辑这些源代码是非常必要的,因为标准的文本编辑器可能无法正确解析或...

    EasyHook-2.7.6270.0.zip_c# easy hook_easyhook_easyhook 2.7_eas

    4. **稳定性与安全性**:EasyHook设计了多种机制来确保钩子的稳定性和安全性,如异常处理、线程安全以及防止钩子被意外移除。 5. **API接口**:EasyHook提供了简单易用的.NET API,使得开发者无需深入底层系统编程...

    hook微信2.3版本 .net源码

    【标题】"hook微信2.3版本 .net源码"涉及的是一个针对微信2.3版本的.NET框架下的源代码项目,主要使用了C#编程语言。"Hook"技术在此处指的是程序钩子,它是一种在系统或应用程序级别监控特定事件的技术。开发者通过...

    easyhook二进制dll

    标签中提到的"C# hook",表明EasyHook是专为C#开发者设计的钩子库。C#是一种面向对象的编程语言,与.NET Framework紧密集成,因此EasyHook能够方便地与C#项目整合,为C#应用程序添加钩子功能。 在压缩包的文件名称...

    easyhook库的使用例子

    EasyHook库是一个强大的.NET钩子库,它允许开发者在运行时拦截和修改其他应用程序的调用,无需重新编译或修改目标代码。这个库在Windows平台上特别有用,因为Windows API提供了大量的函数调用来实现各种系统操作,而...

    23个.NET开源项目

    - **xUnit.net**:作为测试驱动开发(TDD)的核心之一,xUnit.net为.NET平台提供了强大的单元测试支持,其设计简洁而高效,适用于各种.NET应用程序的测试需求。 - **RhinoMocks**:这是一个强大的模拟框架,通过模拟...

    微信pc hook

    Hook在计算机程序设计中,是一种机制,允许开发者在特定的系统事件或函数调用前或后插入自定义代码。在微信PC Hook的例子中,开发者通过Hook微信的API调用,监控并控制其行为。 **C# Hook技术基础** C#作为.NET框架...

    EasyHook 2.7 c#非常简单的HOOK处理类库

    EasyHook 2.7 是一个专门为C#开发者设计的钩子处理类库,它允许程序员在托管和非托管环境中轻松实现钩子技术。EasyHook 提供了一种简单且强大的方式来监控、拦截和修改其他应用程序的行为,这对于调试、性能分析、...

    EasyHook-2.7.6684.0.zip_c# easyhook_easyhook_hook_hook c# 触摸屏

    EasyHook,一个强大而灵活的远程函数挂钩库,它为.NET开发者提供了一种在C#中实现钩子(hook)机制的方法。在本文中,我们将探讨如何利用EasyHook库,通过C#封装C语言的hook接口,来实现在Windows操作系统下的钩子...

    基于.net开发的桌面日历(软件)

    本文将深入探讨一款基于.NET框架开发的桌面日历软件,该软件巧妙地利用了第三方控件、Hook技术和图像处理技术,为用户提供了一个功能强大且美观的桌面时钟解决方案。 首先,我们来理解.NET框架的核心概念。.NET是...

    EasyHook教程系列源代码

    4. **异步编程**:EasyHook的设计允许异步操作,这意味着开发者可以在不阻塞主程序执行的情况下设置和管理钩子。 5. **跨进程通信 (IPC)**:EasyHook实现了跨进程通信,这意味着可以在一个进程中创建钩子,并在另一...

    EasyHook Documentation

    - 高性能:EasyHook设计时考虑了性能优化,能在不显著降低系统性能的情况下工作。 - 易用性:EasyHook提供了直观的API,使得开发者能够快速地实现钩子功能。 - 安全性:考虑到patchguardf,EasyHook在设计时避免...

    dotnet-csharpInlineHook是一个可以将托管dll注入到非托管进程hook

    同时,由于Hook可能影响程序性能,因此在设计时需谨慎考虑其影响范围。 总结起来,C# Inline Hook是.NET开发者与非托管代码交互的一种强大工具,但使用时需谨慎,因为它涉及到对进程内存的直接操作。通过理解并掌握...

    EasyHook-2.7.6789.0_easyhook2.7_h6789.2com_www.67890_

    4. **跨平台兼容性**:虽然EasyHook最初是为Windows平台设计的,但随着.NET Framework的发展,它可能也支持.NET Core,从而具备了跨平台的可能性。 5. **代码示例与文档**:一个完整的源码包通常会包括示例代码和...

    EasyHook库源码

    EasyHook库源码是C#开发的一个系统HOOK库,用于在.NET环境中实现高效且可靠的钩子技术。这个库主要用于监控和拦截系统级别的函数调用,为开发者提供了在应用程序内部或跨进程进行动态功能注入的能力。Easy_Hook2.7....

    vb.net.rar_VB.NET ppt_vb 鼠标位置_vb.net 等待鼠标_vb.net 鼠标_vb2010

    这通常通过全局钩子(Global Hook)来实现,例如使用`SetWindowsHookEx`函数,它可以捕获系统级别的鼠标和键盘事件。在VB.NET中,可以借助第三方库如"MouseKeyBoardHook"来简化这一过程,该库提供了易于使用的API来...

    界面开发(c++ 、.net)

    比如,目前市场上很多界面库在绘制窗口标题栏的时候,去掉了窗口的WS_CAPTION属性, 导致GetClientRect、GetWindowRect方法失效,从而加大了界面开发和设计的难度,当然也导致不能完美支持SDI/MDI等界面框架。...

    RTMPExploreX fo VB.NET

    RTMPExploreX是一款专为VB.NET开发者设计的工具,用于理解和分析RTMP协议的工作原理。本文将深入探讨RTMPExploreX的核心功能以及如何在VB.NET环境下进行应用。 首先,我们需要了解RTMP协议的基础知识。RTMP是一种...

Global site tag (gtag.js) - Google Analytics