Virtual equipment driver structure
Now everyone has a certain understanding of VMM and VXD. Let's take a look at how to write VXD code. First, you must have Windows 95/98 Device Driver Development Kit. WINDOW95 DDK only MSDN subscribers can be obtained, but Windows98 DDK can get free from Microsoft. Although Windows 98 DDK is WDM, you can also use it to develop VXD programs. You can download Window98 DDK from http://www.microsoft.com/hwdev/ddk/install98ddk.htm?.
You can download the entire package (approximately 30m), or you can download only the part you are interested. If you don't have downloaded the entire package, don't forget to download other.exe
Window95 ddk documentation inside. Windows98 DDK contains a 6.11D version of MASM. You need to upgrade it to the latest version. If you don't know where to download the latest version, you can go to my home page to check.
Window9x DDK contains some important library files that MASM32 packages.
You can download this chapter here.
Le file format
VXD uses linear executable format (Le). This file format is designed for OS / 2 2.0. It also contains 16-bit and 32-bit code, this is also the need for the VXD program. Revelling VXD in the era of Windows3.x, at that time, starting Windows from DOS, Windows needs to be initialized in real mode before turning the machine to the protection mode. The 16-bit code of the real mode must be placed in the executable with 32-bit code. So the LE file format is based on the choice. Fortunately, the Windows NT driver does not have to initialize in the real mode, so they don't have to use the Le file format. They use the PE file format.
In the LE file, code and data are stored in several types of running properties. Here are some available paragraphs.
The code and data segments of the LCODE page are locked in memory. In other words, this paragraph will never be put on the hard drive, so you must use this para class to avoid waste of valuable memory. Codes and data that must be placed in memory every moment should be placed in this segment. Especially those hardware interrupt handles. The PCode Display Code Segment VMM can do pages processing on this segment, and the code in this segment does not have to be placed in memory. When VMM needs physical memory, it will put this section on the hard disk. PDATA Display Data Section ICODE is only used in this segment using only the initialization of VXD only. When the initialization is completed, the VMM releases this paragraph from memory. DBOCODE is only used to debug code data segment When you want to debug the VXD program, you should use the code and data in this segment, for example, it contains the processing code for the message to be debugged. SCODE static code and data segment presents in memory, even if VXD has been uninstalled, this segment is useful for some dynamic VXD programs, and these VXD programs need to be loaded / uninstalled in a Windows process. It is also necessary to record the last environment and status. Rcode Real Mode Initialization Code Data Segment This segment contains 16-bit code and data required for real mode initialization. 16IDE 16icode USE16 Protection Mode Initialization Data Segment This is a 16-bit segment that contains VXD to copy from the protection mode to the V86 mode. For example, if you want to copy some V86 code to a virtual machine, you want to copy the code here. If you put it in other segments, the compiler will generate an error code, for example, it produces 32-bit code instead of 16-bit code. McODE Locked Message Strings This section contains a message string that helps compile by the VMM message macro, which helps you construct your international version of your drive.
This doesn't mean that your VXD program must contain all paragraphs, you can choose the paragraph for your VXD program. For example, if your VXD program does not perform real mode initialization, it is not necessary to include the RCODE segment. Most of you want to use Lcode, Pcode, and PDATA. As a VXD programmaker, select the appropriate paragraph for your code and data depends on your own judgment. Overall, you should use Pcode and PDATA as much as possible because it is necessary to transfer the segment into the memory. In addition, the hardware interrupt procedures and their services must be placed in the LCODE segment.
You cannot use these segments directly, you have to use these segments to define segments, and the definitions of these segments are stored in the module definition file (.def). Below is a standard module definition file:
Vxd flightvxd
Segments
_LPText Class 'Lcode' Preload Nondiscardable
_LText Class 'Lcode' Preload Nondiscardable
_LData Class 'Lcode' Preload Nondiscardable
_Text Class 'Lcode' Preload Nondiscardable
_Data class 'lcode' preload nondiscardable
Const Class 'Lcode' Preload Nondiscardable
_TLS Class 'Lcode' Preload Nondiscardable
_BSS Class 'Lcode' Preload Nondiscardable
_Lmgtable Class 'Mcode' Preload Nondiscardable Iopl
_LMSGData Class 'Mcode' Preload Nondiscardable Iopl
_Imsgtable class 'Mcode' Preload Discardable Iopl
_Imsgdata class 'Mcode' Preload Discardable Iopl
_IText Class 'icode' Discardable
_Idata class 'icode' Discardable
_PText Class 'Pcode' Nondiscardable
_Pmsgtable class 'Mcode' Nondiscardable Iopl
_PMSGData Class 'Mcode' Nondiscardable Iopl
_PDATA CLASS 'PDATA' Nondiscardable Shared
_SText Class 'Scode' ResIdent
_SDATA CLASS 'Scode' Resident
_DBOSTART CLAS 'DBOCODE' PRELOAD NONDISCARDABLE CONFORMING
_DBOCODE CLASS 'DBOCODE' PRELOAD NONDISCARDABLE CONFORMING
_DBODATA CLASS 'DBOCODE' PRELOAD NONDISCARDABLE CONFORMING_16ICODE CLASS '16IDE' PRELOAD DISCARDABLE
_Rcode Class 'Rcode'
Exports
Firstvxd_ddb @ 1
The first statement defines the name of the VXD. The name of a VXD must be all uppercase. I have tried to use lowercase, and the result VXD does not do anything else.
Next is the definition of the paragraph, the definition of the segment includes three parts: the name of the segment, the segment class, and the required segment running properties. You can see that many paragraphs are based on the same paragraph, such as, _lptext, _ltext, _ldata is based on the LCODE segment class, and the attribute is exactly the same. This definition segment facilitates making the code easier to understand. Such as: Lcode can include code and data, for a programmer, if he can put the data into the _LDATA segment, put the code in the _ltext segment, it will be easy to understand. Finally, these two segments will be compiled into the same segment of the last executable program.
A VXD program exports and exports only one tag: its device description block (DDB). DDB is actually a structure that contains all VXD information that VMM needs to be known. You must export DDB in the module definition file.
Most of the time, you can use the .def files in your new VXD project. You just have to change the VXD name of the first line of the .def file and the last line. In a compiletable VXD project, the definition of the segment is unnecessary, and the definition of the segment is mainly used for C's VXD project writing, but it is also possible in assembly. You will get a lot of warning information but it can be compiled. You can also delete the paragraph definition you have not used in your project to remove these annoying warning information.
VMM.inc contains many macros for defining segments in your source file:
_LTEXTVxD_LOCKED_CODE_SEG_PTEXTVxD_PAGEABLE_CODE_SEG_DBOCODEVxD_DEBUG_ONLY_CODE_SEG_ITEXTVxD_INIT_CODE_SEG_LDATAVxD_LOCKED_DATA_SEG_IDATAVxD_IDATA_SEG_PDATAVxD_PAGEABLE_DATA_SEG_STEXTVxD_STATIC_CODE_SEG_SDATAVxD_STATIC_DATA_SEG_DBODATAVxD_DEBUG_ONLY_DATA_SEG_16ICODEVxD_16BIT_INIT_SEG_RCODEVxD_REAL_INIT_SEG
Each macro has its corresponding end macro, for example, if you want to define a _ltext paragraph in your source file, you should write:
Vxd_locked_code_seg
(Write your code here)
VXD_LOCKED_CODE_ENDS
VXD structure
Now you know the paragraph in the Le file, we can continue to see the source file. You will find that the VXD program has a feature, that is, it uses a lot of macros. You can see that in VXD, almost everywhere, this is a habit. These macros are used to hide some of the underlying details and also increase the portability of the source program. If you are interested, you can see the definitions of these macros in library files like VMM.inc.
Here is the VXD source file structure:
.386P
Include vmm.inc
Declare_virtual_device firstvxd, 1,0, firstvxd_control, undefined_Device_id, undefined_init_order
Begin_Control_Dispatch firstvxd end_control_dispatch firstvxdend
The first impression given by this source program is: it is not like a assembly program. That is because it used a lot of macros. Let's analyze the source program so you can understand it quickly.
.386P
Tell the compiler We want to use the 80386 instruction system including the CPU privilege instruction. You can also use .486p or .586p.
Include vmm.inc
Every VXD source program must contain Imm.inc because it contains the definition of the macro you want to use in the source program. You can also include other library files as needed.
Declare_virtual_device firstvxd, 1,0, firstvxd_control, undefined_Device_id, undefined_init_order
As we just said, the VMM describes the block (DDB) of the VXD program to obtain all the information about VXD it needs. A device description block is a structure that contains many important information about VXD, such as the name of VXD, its device ID, its VXD service function portfolio (if any), and so on. You can check this structure in imm.inc, which is defined as VXD_DESC_BLOCK. You must export this structure in the .def file. This structure has 22 data, but you only use several of them. Then VMM.inc contains a macro that is initialized and fill in these data. This macro is called Declare_Virtual_Device. Its format is as follows:
Declare_virtual_device name, Majorver, Minorver, CtrlProc, DeviceId, Initorder, V86Proc, PMProc, Refdata
You can see that the labels in the VXD source program are not case sensitive, you can use uppercase, lowercase or mix. Let's take a look at each parameter in declare_virtual_device.
Name vxd's name up to 8 characters. It must be uppercase! In all VXD programs in the system, their names cannot be repeated, and each VXD name should be unique. This macro will also generate DDB names based on this name, the way is: add _ddb after this name. So if your VXD's name is firstvxd, DECLARE_VIRTUAL_DEVICE This macro will set DDB's name to firstvxd_ddb. Remember, you have to export DDB in the .def file. So you must make the name of the DDB and the .def file definition. Majorver and Minorver your main and secondary versions of your VXD. CtrlProc's name of the device control function of your VXD program. The device control function is a function of accepting and processing the VXD program. You can regard the device control function as an equivalent of the Window function. Since we have to generate our device control functions with begin_control_dispatch, we should use the name of a standard format, which is the name of VXD_Control. Begin_control_dispatch This macro adds _Control to the name behind it (and we usually write the VXD's name behind it) as the name of the device control function, so we should add the name of the VXD as a CtrlProc parameter Value. DEVICEID The 16-bit unique identifier of your VXD program When you need to handle the following: you need to use this ID:
Your VXD program exports some VXD services for other VXD programs. Since the interface is located with the device ID of the interface to locate / distinguish the VXD program, a unique ID is necessary for your VXD programs. Your VXD Your VXD program To notify the real mode program to exist when the initialization interrupt 2Fh, 1607h. Some Software (TSR) To load your VXD program with interrupt 2FH, 1605H. If your VXD program does not require a unique device ID, you can set this to undefined_device_id, if you need it, you can go to Microsoft to be one. Initorder initialization sequence, simply, is the order of load. VMM loads the VXD program in accordance with this order. Each VXD program has a subscriber number, for example: vmm_init_order EQU 000000000H
Debug_init_order EQU 000000000H
Debugcmd_init_order EQU 000000000H
Perf_init_order EQU 000900000H
APM_INIT_ORDER EQU 001000000H
You can see: VMM, Debug and DebugCMD are the first VXD program that is loaded, then PERF and APM. The lower the VXD program, the lower the order of initialization, the better. If your VXD program needs to use the services provided by other VXD programs during initialization, you must set the value of the initialization order than the VXD program you want to call, this way, when your VXD program is loaded, you The required VXD has been ready for you in memory. If you don't want to deal with your VXD initialization order, fill this parameter as undefined_init_order.
V86Proc and PMProc Your program can export APIs used by V86 and protection mode programs, which are used to fill out the addresses of these APIs. Remember, VXD programs except for monitoring system virtual machines, also monitor one or more virtual machine programs running in DOS or protection mode. If you are reasonable, the VXD program provides API support for DOS and protection mode programs. If you don't export these API, you can not fill the two parameters. RefData inputs the reference data to be used by the output monitor (iOS). Only one case you want to use this parameter: When you write a layer driver for iOS. Otherwise, you can not fill this parameter.
Next is Begin_Control_Dispatch macro.
Begin_Control_Dispatch firstvxd
END_CONTROL_DISPATCH FIRSTVXD
These two macros define the device control function. When the VXD control message occurs, the VMM calls this function. You must fill in the first half of the device control function name, in this case, we use firstvxd. This macro will add _Control as the name of the device control function after the first half of your input. This name must be consistent with the names you fill in the parameter ctrlproc in the declare_virtual_device macro. The device control function is always placed within the lock segment (VxD_locked_code_seg). The device control function defined above is nothing. You need to indicate what control message should be responded, and you can use the control_dispatch macro to achieve this.
Control_dispatch message, function
For example, if your VXD program uses the device_init message, your device controller should write this:
Begin_Control_Dispatch firstvxd
Control_dispatch device_init, ONDEviceInit
END_CONTROL_DISPATCHFIRSTVXD
OnDeviceInit is the name of the function to process the device_init message. You can give your function to take any name you want to take.
You can end your VXD source program with END.
In summary, a VXD program contains at least one device control block and a device control function. You have to define a device control block with a declare_virtual_device macro, define a device control program with begin_control_dispatch macro. You must fill out the name of the device control block under Exports in the .def file to export the device control block.
Compile VXD
The process of compilation is the same as compiling a normal Win32 program. First call Ml.exe to compile the ASM source file, and then use link.exe to connect the Object file. Different places are different from Ml.exe and Link.exe.
ml -coff -c -cx -dmasm6 -dbld_coff -dis_32 firstvxd.asm
-COFF indicates that the COFF data format-C is only assembled, and the connection program is not called so that we can use more parameters when calling link.exe. -CX saves public, external tags. -D
#define BLD_COFF
#define IS_32
#define masm6
Link -vxd -def: firstvxd.def firstvxd.obj
-vxd indicates that we have to generate a VXD file according to the OBJ file. -def: <. DEF File> Specifies the mode definition file for the VXD file.
I think it is very convenient to use Makefile. If you don't like to use makefile, you can also create a batch file to move the compilation process. My makefile is as follows:
Name = firstvxd
$ (Name) .vxd: $ (name) .Obj link -vxd -def: $ (name) .def $ (name) .Obj
$ (Name) .Obj: $ (name) .asm ml -coff -c -cx -dmasm6 -dbld_coff -dis_32 $ (name) .asm