The second strategy allows the VDM to intercept device accesses at a much lower level. The original MS-DOS application and its driver are not modified. The VDM intercepts low-level port I/O or board-memory accesses and attempts to route the operation through the appropriate VDD. The VDD then calls Win32 functions, such as DeviceIoControl, to access the kernel-mode driver. This method involves writing a VDD and kernel-mode device driver, but not a replacement 16-bit driver.
Although this low-level interception is convenient, it is inefficient because the VDM has to trap and dispatch the disallowed operations. If your application needs higher performance in its communication with a hardware device, modify the application (or its 16-bit driver or TSR) so it dispatches directly to the VDD rather than relying on the VDM to intercept disallowed device-access operations.
For example, consider an MS-DOS 3270 terminal program using a 16-bit device driver to communicate with a plug-in 3270 communications board. The driver provides a control call to send a block of text out over the 3270 cable. The application prepares the block of data and then passes the data to the 16-bit driver. The driver then initiates a series of I/O port operations to directly communicate with the 3270 board. In a Windows NT system, the 16-bit device driver does not have sufficient privilege to access the I/O ports. A modified 16-bit driver makes a call to the 3270 VDD instead of trying to access the board’s I/O ports. The VDD then calls the 32-bit kernel-mode device driver to control the board. You can think of the modified 16-bit driver as a stub driver, where most of the functionality has been delegated to the VDD and its corresponding kernel-mode driver.
The following illustration shows how VDM-based intercepts flow through the various levels of the system from the application to the hardware. Shaded boxes show elements that must be written by the developer.
VDM-based intercepts of device access
Note You can actually use a combination of application-based and VDM-based intercepts when moving your MS-DOS program to Windows NT. The application-based intercepts provide the best performance, but using the VDM-based intercepts can save you the effort of rewriting parts of your application or 16-bit driver where performance is not crucial.
The VDM needs a mechanism to determine the specific device an application is trying to access. To accomplish this, each VDD tells the VDM which I/O ports it supports and the range of board memory it accesses. Each VDD/device pair claims a unique range of port addresses and memory ranges it supports. The VDD installs callback functions for ranges of I/O ports and memory areas. The VDM directs application I/O port operations and memory accesses to the appropriate VDD-installed callback functions.
For example, assume a fax board is supporting an MS-DOS application in a Windows NT system. The fax board supports I/O ports in the range 0x230-0x250 and has 32K of memory, starting at address 0xE8000. When the fax board’s VDD is initialized, the VDD tells the VDM which ports it supports and where the board memory is located. When the MS-DOS fax application tries to access these I/O ports or board memory, the VDM intercepts the operations and passes them on to the fax VDD callback functions. In turn, the VDD callback functions call Win32 functions, such as DeviceIoControl, to request services from the kernel-mode device driver for the fax board.