三使用代码
在我们深入开发这个库之前让我们快速看一下我们的目标在本文中我们将开发一个类库它安装全局系统钩子并且暴露这些由钩子处理的事件作为我们的钩子类的一个NET事件为了说明这个系统钩子类的用法我们将在一个用C#编写的Windows表单应用程序中创建一个鼠标事件钩子和一个键盘事件钩子
这些类库能用于创建任何类型的系统钩子其中有两个预编译的钩子MouseHook和KeyboardHook我们也已经包含了这些类的特定版本分别称为MouseHookExt和KeyboardHookExt根据这些类所设置的模型你能容易构建系统钩子针对Win API中任何种钩子事件类型中的任何一种另外这个完整的类库中还有一个编译的HTML帮助文件它把这些类归档化请确信你看了这个帮助文件如果你决定在你的应用程序中使用这个库的话
MouseHook类的用法和生命周期相当简单首先我们创建MouseHook类的一个实例
mouseHook = new MouseHook();//mouseHook是一个成员变量
接下来我们把MouseEvent事件绑定到一个类层次的方法上
mouseHookMouseEvent+=new MouseHookMouseEventHandler(mouseHook_MouseEvent);
//
private void mouseHook_MouseEvent(MouseEvents mEvent int x int y){
string msg =stringFormat(鼠标事件:{}:({}{})mEventToString()xy);
AddText(msg);//增加消息到文本框
}
为开始收到鼠标事件简单地安装下面的钩子即可
mouseHookInstallHook();
为停止接收事件只需简单地卸载这个钩子
mouseHookUninstallHook();
你也可以调用Dispose来卸载这个钩子
在你的应用程序退出时卸载这个钩子是很重要的让系统钩子一直安装着将减慢系统中的所有的应用程序的消息处理它甚至能够使一个或多个进程变得很不稳定因此请确保在你使用完钩子时一定要移去你的系统钩子我们确定在我们的示例应用程序会移去该系统钩子通过在Form的Dispose方法中添加一个Dispose调用
protected override void Dispose(bool disposing) {
if (disposing) {
if (mouseHook != null) {
mouseHookDispose();
mouseHook = null;
}
//
}
}
使用该类库的情况就是如此该类库中有两个系统钩子类并且相当容易扩充
四构建库
这个库共有两个主要组件第一部分是一个C#类库你可以直接使用于你的应用程序中该类库反过来在内部使用一个非托管的C++ DLL来直接管理系统钩子我们将首先讨论开发该C++部分接下来我们将讨论怎么在C#中使用这个库来构建一个通用的钩子类就象我们讨论C++/C#交互一样我们将特别注意C++方法和数据类型是怎样映射到NET方法和数据类型的
你可能想知道为什么我们需要两个库特别是一个非托管的C++ DLL你还可能注意到在本文的背景一节中提到的两篇参考文章其中并没有使用任何非托管的代码为此我的回答是对!这正是我写这篇文章的原因当你思考系统钩子是怎样实际地实现它们的功能时我们需要非托管的代码是十分重要的为了使一个全局的系统钩子能够工作Windows把你的DLL插入到每个正在运行的进程的进程空间中既然大多数进程不是NET进程所以它们不能直接执行NET装配集我们需要一种非托管的代码代理Windows可以把它插入到所有将要被钩住的进程中
首先是提供一种机制来把一个NET代理传递到我们的C++库这样我们用C++语言定义下列函数(SetUserHookCallback)和函数指针(HookProc)
int SetUserHookCallback(HookProc userProc UINT hookID)
typedef void (CALLBACK *HookProc)(int code WPARAM w LPARAM l)
SetUserHookCallback的第二个参数是钩子类型这个函数指针将使用它现在我们必须用C#来定义相应的方法和代理以使用这段代码下面是我们怎样把它映射到C#
private static extern SetCallBackResults
SetUserHookCallback(HookProcessedHandler hookCallback HookTypes hookType)
protected delegate void HookProcessedHandler(int code UIntPtr wparam IntPtr lparam)
public enum HookTypes {
JournalRecord =
JournalPlayback =
//
KeyboardLL =
MouseLL =
};
[] [] [] [] []