在这个方法中我们检查是否有人在听这一个事件如果没有不必继续处理这一事件然后我们把WPARAM转换成一个MouseEvents枚举类型我们已小心地构造了MouseEvents枚举来准确匹配它们在C++中相应的常数这允许我们简单地把指针的值转换成枚举类型但是要注意这种转换即使在WPARAM的值不匹配一个枚举值的情况下也会成功mEvent的值将仅是未定义的(不是null只是不在枚举值范围之内)为此请详细分析SystemEnumIsDefined方法
接下来在确定我们收到的事件类型后该类激活这个事件并且通知消费者鼠标事件的类型及在该事件过程中鼠标的位置
最后注意有关转换WPARAM和LPARAM值对于每个类型的事件这些变量的值和意思是不同的因此在每一种钩子类型中我们必须区别地解释这些值我选择用C++实现这种转换而不是尽量用C#来模仿复杂的C++结构和指针例如前面的类就使用了一个叫作GetMousePosition的C++函数下面是C++ DLL中的这个方法
bool GetMousePosition(WPARAM wparam LPARAM lparam int & x int & y) {
MOUSEHOOKSTRUCT * pMouseStruct = (MOUSEHOOKSTRUCT *)lparam;
x = pMouseStruct>ptx;
y = pMouseStruct>pty;
return true;
}
不是尽量映射MOUSEHOOKSTRUCT结构指针到C#我们简单地暂时把它回传到C++层以提取我们需要的值注意因为我们需要从这个调用中返回一些值我们把我们的整数作为参考变量传递这直接映射到C#中的int*但是我们可以重载这个行为通过选择正确的签名来导入这个方法
private static extern bool InternalGetMousePosition(UIntPtr wparam
IntPtr lparam ref int x ref int y)
通过把integer参数定义为ref int我们得到通过C++参照传递给我们的值如果我们想要的话我们还可以使用out int
五限制
一些钩子类型并不适合实现全局钩子我当前正在考虑解决办法它将允许使用受限制的钩子类型到目前为止不要把这些类型添加回该库中因为它们将导致应用程序的失败(经常是系统范围的灾难性失败)下一节将集中讨论这些限制背后的原因和解决办法
HookTypesCallWindowProcedure
HookTypesCallWindowProret
HookTypesComputerBasedTraining
HookTypesDebug
HookTypesForegroundIdle
HookTypesJournalRecord
HookTypesJournalPlayback
HookTypesGetMessage
HookTypesSystemMessageFilter
六两种类型的钩子
在本节中我将尽量解释为什么一些钩子类型被限制在一定的范畴内而另外一些则不受限制如果我使用有点偏差术语的话请原谅我我还没有找到任何有关这部分题目的文档因此我编造了我自己的词汇另外如果你认为我根本就不对请告诉我好了
当Windows调用传递到SetWindowsHookEx()的回调函数时它们会因不同类型的钩子而被区别调用基本上有两种情况切换执行上下文的钩子和不切换执行上下文的钩子用另一种方式说也就是在放钩子的应用程序进程空间执行钩子回调函数的情况和在被钩住的应用程序进程空间执行钩子回调函数的情况
钩子类型例如鼠标和键盘钩子都是在被Windows调用之前切换上下文的整个过程大致如下
应用程序X拥有焦点并执行
用户按下一个键
Windows从应用程序X接管上下文并把执行上下文切换到放钩子的应用程序
Windows用放钩子的应用程序进程空间中的键消息参数调用钩子回调函数
Windows从放钩子的应用程序接管上下文并把执行上下文切换回应用程序X
Windows把消息放进应用程序X的消息排队
稍微一会儿之后当应用程序X执行时它从自己的消息排队中取出消息并且调用它的内部按键(或松开或按下)处理器
[] [] [] [] []