首先
我们使用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这将会引导你到在windefh中的定义
//从windefh:
typedef UINT_PTR WPARAM;
typedef LONG_PTR LPARAM;
因此我们选择SystemUIntPtr和SystemIntPtr作为我们的变量类型它们分别相应于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在用一个catchall try/catch块包装它的同时仅传递到抽象方法HookCallback的调用这将简化在派生类中的实现并且保护C++代码记住一旦一切都准备妥当这个C++钩子就会直接调用这个方法
[MethodImpl(MethodImplOptionsNoInlining)]
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)wparamToUInt();
switch(mEvent) {
case MouseEventsLeftButtonDown:
GetMousePosition(wparam lparam ref x ref y);
break;
//
}
MouseEvent(mEvent new Point(x y));
}
首先注意这个类定义一个事件MouseEvent该类在收到一个钩子事件时激发这个事件这个类在激发它的事件之前把数据从WPARAM和LPARAM类型转换成NET中有意义的鼠标事件数据这样可以使得类的消费者免于担心解释这些数据结构这个类使用导入的GetMousePosition函数我们在C++ DLL中定义的用来转换这些值为此请看下面几段的讨论
[] [] [] [] []