钩子原理 深入探讨.NET中的钩子技术[3]
深入探讨.NET中的钩子技术[3]
首先 我们使用DllImport属性导入SetUserHookCallback函数 作为我们的抽象基钩子类SystemHook的一个静态的外部的方法 为此 我们必须映射一些外部数据类型 首先 我们必须创建一个代理作为我们的函数指针 这是通过定义上面的HookProcessHandler来实现的 我们需要一个函数 它的C++签名为(int WPARAM LPARAM) 在Visual Studio NET C++编译器中 int与C#中是一样的 也就是说 在C++与C#中int就是Int 事情并不总是这样 一些编译器把C++ int作为Int 对待 我们坚持使用Visual Studio NET C++编译器来实现这个工程 因此 我们不必担心编译器差别所带来的另外的定义接下来 我们需要用C#传递WPARAM和LPARAM值 这些确实是指针 它们分别指向C++的UINT和LONG值 用C#来说 它们是指向uint和int的指针 如果你还不确定什么是WPARAM 你可以通过在C++代码中单击右键来查询它 并且选择 Go to definition 这将会引导你到在windef h中的定义
![钩子原理 深入探讨.NET中的钩子技术[3]](http://img.zhputi.com/uploads/4f29/4f29d89621460e61b4a3a78178a9125724262.jpg)
//从windef h:typedef UINT_PTR WPARAM;typedef LONG_PTR LPARAM;
因此 我们选择System UIntPtr和System IntPtr作为我们的变量类型 它们分别相应于WPARAM和LPARAM类型 当它们使用在C#中时
现在 让我们看一下钩子基类是怎样使用这些导入的方法来传递一个回叫函数(代理)到C++中 它允许C++库直接调用你的系统钩子类的实例 首先 在构造器中 SystemHook类创建一个到私有方法InternalHookCallback的代理 它匹配HookProcessedHandler代理签名 然后 它把这个代理和它的HookType传递到C++库以使用SetUserHookCallback方法来注册该回叫函数 如上面所讨论的 下面是其代码实现
public SystemHook(HookTypes type){ _type = type; _processHandler = new HookProcessedHandler(InternalHookCallback); SetUserHookCallback(_processHandler _type);}
InternalHookCallback的实现相当简单 InternalHookCallback在用一个catch all try/catch块包装它的同时仅传递到抽象方法HookCallback的调用 这将简化在派生类中的实现并且保护C++代码 记住 一旦一切都准备妥当 这个C++钩子就会直接调用这个方法
[MethodImpl(MethodImplOptions NoInlining)]private void InternalHookCallback(int code UIntPtr wparam IntPtr lparam){try { HookCallback(code wparam lparam); }catch {}}
我们已增加了一个方法实现属性 它告诉编译器不要内联这个方法 这不是可选的 至少 在我添加try/catch之前是需要的 看起来 由于某些原因 编译器在试图内联这个方法 这将给包装它的代理带来各种麻烦 然后 C++层将回叫 而该应用程序将会崩溃
现在 让我们看一下一个派生类是怎样用一个特定的HookType来接收和处理钩子事件 下面是虚拟的MouseHook类的HookCallback方法实现
protected override void HookCallback(int code UIntPtr wparam IntPtr lparam){ if (MouseEvent == null) { return; }int x = y = ;MouseEvents mEvent = (MouseEvents)wparam ToUInt ();switch(mEvent) { case MouseEvents LeftButtonDown:GetMousePosition(wparam lparam ref x ref y);break; // } MouseEvent(mEvent new Point(x y));}
首先 注意这个类定义一个事件MouseEvent 该类在收到一个钩子事件时激发这个事件 这个类在激发它的事件之前 把数据从WPARAM和LPARAM类型转换成 NET中有意义的鼠标事件数据 这样可以使得类的消费者免于担心解释这些数据结构 这个类使用导入的GetMousePosition函数 我们在C++ DLL中定义的用来转换这些值 为此 请看下面几段的讨论
lishixinzhi/Article/program/net/201311/15483