..... 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程序不应该使用这些消息。
VxD FIRSTVxD DYNAMIC这就是你把一个静态VxD转换成一个动态的VxD所要做的一切。
例如,如果你要加载一个在当前目录下名为FirstVxD的动态VxD,你需要做如下的工作:
.data
VxDName db
"\\.\FirstVxD.VxD",0
......
.data?
hDevice dd
?
.....
.code
.....
invoke CreateFile, addr
VxDName,0,0,0,0, FILE_FLAG_DELETE_ON_CLOSE,0
mov
hDevice,eax
......
invoke
CloseHandle,hDevice
......
VxD_PAGEABLE_CODE_SEG你可以在一个段里面插入多个的函数。作为一个VxD编写者,你必须决定每一个函数应该放到哪个段里面去。如果你的函数必须时刻存在于内存中,如某些硬件中断处理程序,就把它们放到锁定页面段里面,否则,你应该把它们放到可调页段。(你的函数写在这里)
VxD_PAGEABLE_CODE_ENDS
BeginProc 函数名使用BeginProc 宏还可以加上一些参数,想了解这些细节,你可以看看Win95 DDK的文档。大多数时候,你只用填写函数的名字就够了。EndProc 函数名
VMMCall service ; 调用寄存器法服务函数e正如我在前面所讲的,VMMCall和VxDCall分解出一个跟着一个双字的20h中断,这样用起来很方便。 当你调用堆栈法服务时,你必须用角括号把你的参数列括起来。
VMMCall _service, <argument list> ; 调用堆栈法服务函数
VMMCall _HeapAllocate, <<size mybuffer>, HeapLockedIfDP>_HeapAllocate是一个堆栈法服务函数。它有两个参数,我们必须用角括号把它们括起来。由于第一个参数是一个这个宏不能正确解释的表达式,所以我们又要用一个角括号把它括起来。
注意: 当我写这篇教程的时候,我试了一下用offset
操作符。它可以生成正确的地址。所以我想MASM6.14修正了这个bug。但是为了安全起见,你还是应该用OFFSET32宏来代替offset。