..... VxD1 ===> VxD2 ===> VxD3 .....Now during unloading, it stands to reason that the VxDs that initialize later should uninitialize first so that they may still call VxD services of the VxDs that were loaded before them. In the above example, the order should be:
.... VxD3 ===> VxD2 ===> VxD1.....In the above example, if VxD2 called some VxD1's services during initialization, it may need to rely on VxD1's services again during unloading. System_Exit2 and Sys_Critical_Exit2 are sent in reverse initialization order. It means that, when VxD2 receives those messages, VxD1 hasn't done uninitialization yet and it can still call VxD1's services. System_Exit and Sys_Critical_Exit messages are not sent in reverse initialization order. It means that when you process those two messages, you can't be sure that you can still call VxD's services of the VxDs that were loaded before you. Those messages should not be used for newer VxDs.
VXD FIRSTVXD DYNAMICThat's all you have to do to convert a static VxD into a dynamic one.
For
example, if you want to load a dynamic VxD named FirstVxD which is in the
current directory, you should do it as follows:
.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_SEGYou can put many procedures inside a segment. You as the VxD writer must decide in which segment you should put your procedures. If your procedures must be in memory at all time such as hardware interrupt handlers, put them in a locked segment. Otherwise you should put them in the pageable segment.[Your procedure here]
VxD_PAGEABLE_CODE_ENDS
BeginProcnamename is the name of your procedure. BeginProc macro can take several more parameters, you should consult Win95 DDK documentation for detail. But most of the time, you can get by with only the name of the procedure.EndProcname
VMMCall service ; for calling register-based serviceVMMCall and VxDCall decompose to int 20h followed by a dword that I described in the previous tutorial but they are much more convenient to use. In the case of stack-based services, you must enclose the argument list with a pair of angle bracket.
VMMCall _service, <argument list> ; for calling stack-based service
VMMCall _HeapAllocate, <<size mybuffer>, HeapLockedIfDP>_HeapAllocate is a stack-based service. It accepts two parameters. We must enclose them inside an angle bracket. However, the first parameter is an expression that the macro may interpret incorrectly, so we put it inside another angle bracket.