Delphi驱动开发研究(12)-- Shared Event
假如我们需要实现一个驱动程序去收集一些操作系统的统计信息,并将这些信息发送给用户层的管理程序去处理,这就需要驱动程序与管理程序交互,如何实现这种功能呢?最简单的办法就是在管理程序里创建一个计时器,这个计时器每隔一定的间隔时间(例如,每秒一次)就触发一次,通过使用DeviceIoControl函数向驱动程序发送I/O控制码来收集统计信息(RegMon和FileMon就是这样做的)。但是如果我们的驱动程序要收集的是一些不常发生的事件信息,比如我们要收集进程创建、销毁的信息,由于系统并非每时每刻都有进程创建或者销毁,所以定时执行DeviceIoControl往往都是白忙一场,获取不到任何信息。此时我们可以考虑增加触发定时器的间隔时间(例如,把间隔时间增加到10秒),但是如果间隔时间过长又可能会出现驱动程序已经收集到信息但是由于管理程序的定时器尚未被触发而导致未能及时获取统计信息的情况发生。显然,比较合理的方案应该是由驱动程序来决定管理程序什么时候获取统计信息,因为只有驱动程序才知道具体的事件是什么时候发生的,当事件发生后,驱动程序以某种方式通知管理程序,有事件发生,你可以获取数据了,此时管理程序再用DeviceIoControl向驱动程序发送控制码以获取最新的统计信息数据。
事实上,Windows给我们提供了两种比较好的方法可以让我们达到目的。一种方法是使用异步的DeviceIoControl,这种方法要求用户在使用CreateFile创建对象时必须要设置FILE_FLAG_OVERLAPPED标志,同时填充一个OVERLAPPED结构并将其地址做为CreateFile的最后一个参数传递。异步DeviceIoControl调用可能返回的结果有三种:返回TRUE,这说明驱动程序的分派子程序可以立即完成请求;返回FALSE并且调用GetLastError取得的错误码是ERROR_IO_PENDING,这表明驱动程序的分派子程序返回STATUS_PENDING并会在稍后完成控制操作。这里要注意的是,ERROR_IO_PENDING并不代表真的出错了,它仅仅是一种系统表明任何事件正在被正常处理的途径而已;如果返回FALSE并且用GetLastError取得的错误码也不是STATUS_PENDING,那就是真的出错了。这里我们不打算详细讨论异步DeviceIoControl方法,有兴趣的话,您可以参考DDK或者MSDN。另一种方法就是同步调用了,这种方法相对要容易些,这种方法要求在驱动程序和用户程序间共享一个事件,驱动程序通过这个事件对象向客户程序发送信号,客户程序收到信号后,就可以从驱动程序接收一些自己感兴趣的信息。
如何才能共享事件呢?你可以使用一个命名对象,然后通过名字访问这个对象。我们之前在SharedSection的例子中就使用过这种方法。这种方法的基本技巧就是让该命名对象一直存在于内存中,所以缺点也就显而易见了,这个命名对象对所有进程都是可见的,但是即便如些,它也比使用无名对象要些。当然,我们还有更好的方法,就是先在客户程序中用CreateEvent创建一个对象,然后调用DeviceIoControl把事件句柄传递给驱动程序。在本章中我们将使用这种方法创建一个简单的进程监视器,这个监视器可以监视进程的创建与销毁。下面是ProcessMon管理程序运行时的截图:

12.1 全局数据
我们先来看一下common.pas中定义的一些全局数据。
注意:上传附件及图片大小不得大于30M。
⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途。
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。
