3.1.3 VxD的设计实现VxD的设计并不是通常我们所讲的调用API的Windows程序而是通过对DDK的调用来工作。DDK可以从微软的网站上下载。在DDK中有很多VxD的例子我们在设计时可以作为参照样板。VxD的设计一般要直接用汇编编程并且要直接地操作硬件所以设计比较困难。不过用汇编写VxD的框架结构、用C来完成具体的工作实现就会大大地提高开发的效率后面的例子中就是使用了这种方法。1. 静态VxD在下列情况下VMM加载一个静态VxD:1此VxD在注册表中的如下位置有定义HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\VxD\key\StaticVxDVxD带路径文件名2此VxD在system.ini中的[386enh]行下有定义[386enh] section:deviceVxD带路径文件名在开发的时候建议从system.ini载入VxD程序因为这样如果VxD程序有错而将导致Windows不能启动可以在DOS下修改system.ini而如果使用注册表载入的办法就无法修改了。当VMM加载静态VxD程序时VxD程序会按以下顺序接收到3个系统控制消息。1Sys_Critical_InitVMM在转入到保护模式后开放中断前发出这个控制消息。大多数VxD程序不要用这个消息除非VxD程序要接管一些其他VxD程序或者保护模式程序要用到的中断。既然处理这个消息的时候这个中断还没有打开就可以确定在你接管这个中断的时候此中断不会被调用。VxD程序为其他的VxD程序提供了一些VxD服务。2Device_Init控制消息时需要调用一些VxD服务既然Sys_Critical_Init 控制消息在Device_Init消息之前被发送所以你应该在Sys_Critical_Init 消息发送时初始化你的程序。如果要对这消息进行处理则应该尽可能快地做完初始化工作以免太长的执行时间导致硬中断丢失(记住中断还没打开)。Device_Init VMM在开放中断后发送此信息。大多数VxD程序都在得到这个消息时初始化。因为中断都开放了所以耗时的操作也可以在这里执行而不怕会导致硬中断的丢失。你可以在这时进行初始化(如果你需要的话)。3Init_Complete在所有的VxD程序处理完Device_Init 消息之后,VMM释放初始化段ICODE和RCODE段类之前VMM发出这个控制消息。只有少数几个VxD要处理这个消息。VxD程序在成功地初始化后必须将返回标志清零反之必须在返回之前把返回标志设为出错信息。如果VxD不需要初始化就不必对这些消息进行处理。当要结束静态VxD的时候VMM发送如下的控制消息。1System_Exit2当VxD程序收到这个消息Windows 9x正在关闭系统除了系统虚拟机外所有其他虚拟机都已经退出了。尽管如此CPU仍然处于保护模式下在系统虚拟机上执行实模式编码也是安全的。这时Kernel32.dll也已经被卸载了。2Sys_Critical_Exit2 当所有的VxD完成对System_Exit2的响应处理并且中断都被关闭后VxD收到这个消息。许多VxD程序并不要响应这两个消息除非你要为系统做转换到实模式的准备。要知道当Windows 95关闭时它进入到实模式。所以如果VxD程序对实模式影像做了一些会导致它不稳定的操作它就需要在这时进行恢复。你也许会感到奇怪为什么这两个消息后面都跟着个“2”这是因为在VMM加载VxD程序的时候它是按照初始化顺序值小的VxD先加载的顺序加载的这样VxD程序就可以使用那些在它们之前加载的VxD程序提供的服务。例如VxD2要用到VxD1中的服务它就必须把它的初始化顺序值定义得比VxD1小。加载的顺序是..... VxD1 VxD2 VxD3 .....那么卸载的时候理所当然地是初始化顺序值大的VxD程序先被卸载这样它们仍然可以使用比它们后加载的那些VxD程序提供的服务。如上面的例子次序是.... VxD3 VxD2 VxD1.....在上边的例子中如果VxD2在初始化时调用了VxD1中的某些服务那么卸载时它可能也要再次用到一些VxD1中的服务。System_Exit2和Sys_Critical_Exit2是按反初始化顺序发送的。这表示当VxD2接受到这些消息时VxD1还没有被卸载它仍可以调用VxD1的服务而System_Exit和Sys_Critical_Exit消息不是按照反初始化顺序发送的。这意味着你不能肯定你是否仍能调用在你之前加载的VxD提供的VxD服务。现在的VxD程序不应该使用这些消息而应该使用以下两种退出消息。1Device_Reboot_Notify2 告诉VxD程序VMM正在准备重新启动系统。这时候不管是中断还是开放的Crit_Reboot_Notify2都会告诉VxD程序VMM正在准备重新启动系统并把中断关闭。2Device_Reboot_Notify和Crit_Reboot_Notify 消息一样但它们并不是像“2”版本的消息那样按反初始化顺序发送。其他就和Device_Reboot_Notify2一样了。2. 动态VxD动态VxD在Windows 9x里可以动态地被加载和卸载。这个特点在Windows 3.x下是没有的。动态VxD程序的主要作用是用来支持某些动态的硬件设备的重装比如即插即用设备。尽管如此可以从Win32程序中加载/卸载它也可以把它看做是程序的一个到ring0的扩展。上一节我们提到的例子是一个静态的VxD你可以把它转换成一个动态的VxD只要在.def文件中VxD标记的后面加上关键字DYNAMICVxD STHVxD DYNAMIC这就是把一个静态VxD转换成一个动态的VxD所要做的一切。一个动态的VxD可以按以下的方法被加载。1把它放到Windows目录下的\SYSTEM\IOSUBSYS目录中。在这个目录里的VxD会被输入输出监视器(IOS)加载。这些VxD必须支持层设备驱动。所以用这种方法加载动态VxD并不是一个好办法。用VxD加载服务。VxDLDR是一个可以加载动态VxD的静态VxD。你可以在其他VxD里面或者在16位代码里面调用它的服务。