VXD program design
We have learned how to write a VXD program that don't do anything in the previous section. In this section, we have to give it to increase the functionality of processing control messages.
Initialization and end of VXD
The VXD program is divided into two types: static and dynamic. Each load method is different, and the initialization and end control messages are accepted are also different.
Static VXD:
In the following cases, VMM loads a static VXD:
This VXD is called by calling the interrupt 2FH, 1605H by calling interrupt. This VXD is defined in the following location in the registry:
HKEY_LOCAL_MACHINE / SYSTEM / CURRENTCONTROLSET / SERVICES / VXD / Key / StaticVxd = VXD with path file name
This VXD is defined in [386ENH] in System.ini: [386ENH] Section:
Device = VXD with path file name
When developing, I suggest that you load the VXD program from System.ini, because if your VXD program is failed to start, you can modify system.ini under DOS, and if you use the registry Loaded approaches, you can't modify it. When VMM loads your static VXD program, your VXD program will receive three system control messages in the following order:
Sys_critical_init VMM issued this control message before turning to the protection mode. Most VXD programs do not use this message unless:
Your VXD program is to take over some other VXD programs or the interrupts to be used by the protection mode program. Since the interrupt has not been opened when you handle this message, you can determine that this interrupt will not be called when you take over this interrupt. Your VXD program provides some VXD services for other VXD programs. For example, some VXD programs loaded after your VXD program need to call some of your VXD service when processing the Device_init control message, since the sys_critical_init control message is sent before the Device_init message, so you should initialize your program when you send your program when Sys_Critical_init messages . If you want to handle this message, you should do the initialization work as quickly as possible to avoid the hard interruption loss caused by too long execution time. (Remember: Interruption has not yet opened) Device_init VMM sends this information after the open interrupt. Most VXD programs are initialized when this message is obtained. Because the interrupt is open, the time-consuming operation can also be performed here without fearing that will result in a loss of hard interruption. You can initialize this at this time (if you need it). After all VXD programs are processed, the VMM release initialization segment (ICODE and RCODE segment class), the VMM issues this control message before all VXD programs are processed. Only a few VXDs have to process this message.
After your VXD program is successfully initialized, you must return the flag to zero, but in turn, you must set the return flag to an error message before returning. If your VXD does not need to initialize, you don't have to process these messages. When you want to end the static VXD, the VMM sends the following control message:
System_exit2 When your VXD program receives this message, Windows95 is turning off the system, except for all other virtual machines of the system virtual machine. Nevertheless, the CPU is still in protection mode, and the real mode encoding is also safe on the system virtual machine. At this time, kernel32.dll has also been uninstalled. SYS_CRITICAL_EXIT2 When all VXDs complete the response processing for system_exit2 and the interrupt is turned off, your VXD receives this message.
Many VXD programs do not respond to these two messages unless you want to convert to the system to real mode. To know, it enters the real mode when Window95 is turned off. So if your VXD program has made some acts that will cause its unstable operation, it needs to be recovered at this time. You may be surprised: Why is these two messages followed by "2" ". This is because: When the VMM loads the VXD program, it is loaded in the order of the VXD, which is small in the initial sequence value, so VXD The program can use the service provided by the VXD programs previously loaded. For example, Vxd2 is used to use the service in VXD1, which must define its initialization sequence value than VxD. The order of load is: ... .. vxd1 ===> vxd2 ===> vxd3 .....
So when uninstalled, the VXD program of the initialized order value is first uninstalled so that they can still use the services provided by those VXD programs loaded later. As the example above, the order is:
.... vxd3 ===> vxd2 ===> vxd1 .....
In the example on the top, if VXD2 calls some of the services in VXD1 during initialization, it may also be used to use the services in some VXD1 again. System_exit2 and sys_critical_exit2 are sequentially sent in the reverse initialization. This means that when VXD2 accepts these messages, VXD1 has not been uninstalled, and it can still call VXD1 service, and system_exit and sys_critical_exit messages are not sent in the reverse initialization order. This means that you can't definite whether you still call VXD services provided in VXD loaded before you. A new generation of VXD programs should not use these messages. There are two exit messages:
Device_reboot_notify2 tells the VXD program VMM is preparing to restart the system. At this time, it is interrupted or open. Crit_reboot_notify2 tells the VXD program VMM being ready to restart the system. At this time, the interrupt has been closed.
Here, you can guess that there is DEVICE_REBOOT_NOTIFY and CRIT_REBOOT_NOTIFY messages, but they are not sent in the reverse initialization as "2" version.
Dynamic VXD:
Dynamic VXD can be loaded and uninstalled in Windows9x. This feature is not in Window3.x. The main role of dynamic VXD programs is to support certain dynamic hardware devices, such as: Plug and Play devices. Despite this, you can load / uninstall it from your Win32 program, you can also think it as an extension of your program to Ring-0. The example we mentioned in the previous section is a static VXD, you can convert it into a dynamic VXD, just add the keyword Dynamic after the VXD tag in the .def file.
Vxd flightvxd Dynamic
This is what you convert a static VXD into a dynamic VXD. A dynamic VXD can be loaded as follows:
Put it in the / system / iosubsys directory under your Windows directory. VXD in this directory will be loaded by the input / output monitor (iOS). These VXDs must support layer devices. So loading your dynamic VXD in this way is not a good way. Load the service with VXD. VxDLDR is a static VXD that can load dynamic VXD. You can call its services in other VXDs or in the 16-bit code. Use the CreateFile API in Win32 applications. When you call CreateFile, your dynamic VXD will be filled in the following format:
//./VXD full path name
For example, if you want to load a dynamic VXD named firstvxd in the current directory, you need to do the following work: .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 ..... .File_flag_delete_on_close This flag is used to explain that the VXD is unloaded when the handle returned by CREATEFILE. If you use createfile to load a dynamic VXD, this dynamic VXD must process the W32_Deviceiocontrol message. When your dynamic VXD is first loaded by the CreateFile function, Vwin32 issues this message to your VXD. Your VXD responds to this message, the value in EAX must be zero when returning. When the application calls the DEVICEIOCONTROL API to communicate with a dynamic VXD, the W32_Deviceiocontrol message is also sent. We will tell the DeviceIocontrol interface in the next chapter. A dynamic VXD receives a message when initialization:
Sys_Dynamic_Device_init also received a control message at the end:
SYS_DYNAMIC_DEVICE_EXIT Dynamic VXD does not receive sys_critical_init, device_init, and init_complete control messages because these messages are sent when the system virtual machine is initialized. In addition to these three messages, dynamic VXD can receive all control messages as long as it is still in memory. It can do everything you can do in static VXD. Simply put, dynamic VXD can do everything you can do with static VXD in addition to the loading mechanism and the received initialization / end message with the static VXD. Other System Control Messages When VXD is in memory, in addition to receiving and initializing and ending related messages, it also receives a number of other control messages. Some messages are about virtual machine managers, and some are about various events. For example, the news about the virtual machine is as follows:
CREATE_VM VM_CRITICAL_INIT VM_SUSPEND VM_RESUME CLOSE_VM_NOTIFY DESTROY_VM Selectively Responding to what you are interested in is your own responsibility. Create a function in VXD You want to define your function in a segment. You should first define a segment, then put your function in. For example, if you want to put your function in a tunable page. You should first define a tonable page segment, like this:
Vxd_pageable_code_seg
(Your function is written here)
VXD_PAGEABLE_CODE_ENDS
You can insert multiple functions in a segment. As a VXD writer, you must decide which one of each function should be put in. If your function must always exist in memory, such as some hardware interrupt handles, put them in the lock page section, otherwise you should put them in the adjustable page. You have to define your function with beginProc and endproc macro:
BeginProc function name
Endproc function name
Use the BeginProc macro to add some parameters, you want to know these details, you can look at the Win95 DDK documentation. Most of the time, you only use the name of the function to fill in the function. Because BeginProc-EndProc macro is stronger than the procarproc function, you should use the BeginProc-Endproc macro to replace the procarn command VXD programming register to use all registers, FS, and GS. However, be careful when the change segment register must be careful. In particular, you must do not change the contents of CS and SS unless you have an absolute grasp of things that will happen. You can use DS and ES, but must remember to restore their initial values when returning. There are two feature points, especially important: direction and interrupt feature. Don't break the shield for a long time. Also if you want to change the direction of the direction, don't forget to restore its initial value before returning. Parameter delivery agreed VXD service functions There are two call conventions: register method and stack method. When calling the register method service function, you pass the parameters of the service function through various registers. Also, check whether the value is successful after the value of the register is checked. Don't always think that the value of the primary register is still the same as before calling the service function. When the stack method service function is called, you put the parameters you want to pass, and get the return value in Eax. The service function of the stack adjustment saves EBX, ESI, EDI, and EBP values. Many register calling method serviced from the era of Windows3.x. In most, you can distinguish between these two service functions through the name. If a function is named, if _Heapallocate, it is a stack method service function (except for a few functions exported from vwin32.vxd). If the function name is not a scribe, it is a register method service function. Call VXD service function
You can call VMM and VXD services via VMMCALL and VXDCALL macro. The syntax of these two macros is the same. When you want to call the VXD service function exported by the VMM, use VMMCALL. When you want to use the VXD service function exported by other VXD programs, use vxdcall.
Vmmcall service; call register method service function e vmmcall _service,
As I said in the previous, VMMCall and vxdcall decomposed a 20H interruption with a double word, which is very convenient to use. When you call the Stack Law Service, you have to enclose your parameters with corner spacing.
Vmmcall_heapallocate, << Size MyBuffer>, Heaplockedifdp>
_Heapallocate is a stack method service function. It has two parameters, we must enclose them with corners. Since the first parameter is an expression that cannot be explained correctly, we have to put it with a corner spacing.
FLAT address
In the old compilation tool, when you use the Offset operator, the compiler and the coupler generate an error address, so the VXD writer uses Offset Flat: instead of Offset. Imm.inc includes a simpler macro: OFFSET32 instead of Offset Flat :. So if you want to use the address operation, use Offset32 instead of the OFFSET operator.
Note: When I wrote this tutorial, I tried it with Offset operator. It can generate the correct address. So I think MASM6.14 fix this bug. But for safety, you should still use Offset32 macro to replace offset.