Using VWIN32 to Carry Out MS-DOS Functions

Windows 95 provides a VxD named VWIN32.VXD that supports a set of control codes that Win32-based applications can use to carry out selected MS-DOS system functions. These system-defined control codes consist of the following values.

Control code (value) Meaning
VWIN32_DIOC_DOS_DRIVEINFO (6) Performs Interrupt 21h Function 730X commands. This value is supported in Windows 95 OEM Service Release 2 and later.
VWIN32_DIOC_DOS_INT13 (4) Performs Interrupt 13h commands
VWIN32_DIOC_DOS_INT25 (2) Performs the Absolute Disk Read command (Interrupt 25h)
VWIN32_DIOC_DOS_INT26 (3) Performs the Absolute Disk Write command (Interrupt 25h)
VWIN32_DIOC_DOS_IOCTL (1) Performs the specified MS-DOS device I/O control function (Interrupt 21h Function 4400h through 4411h)

When an application calls the DeviceIoControl function with the dwIoControlCode parameter set to one of the predefined control codes, the lpvInBuffer and lpvOutBuffer parameters must specify the addresses of DIOC_REGISTERS structures. The DIOC_REGISTERS structure specified by lpvInBuffer contains a set of register values that specify a command for the VxD to execute and any data that the VxD needs to execute the command. After completing the command, the VxD fills the DIOC_REGISTERS structure specified by lpvOutBuffer with the register values that resulted from executing the command. The meaning of the register values depends on the specified command. Many of the MS-DOS and BIOS functions require segment:offset register pairs for pointers. However, because 32-bit code does not have segments, the DIOC_REGISTERS structure does not contain members for segment registers. Place the full pointer that would go into a real-mode segment:offset register pair into the structure member that corresponds to the offset of the register pair. For example, use the reg_EDI member for the pointer that would go into the ES:DI registers. When an application uses the DeviceIoControl function to send commands to a VxD other than VWIN32.VXD, the meaning of the function's parameters are defined by the VxD. The system does not validate the parameters. The system VxD, VWIN32.VXD, supports the IOCTL functions originally provided by MS-DOS Interrupt 21h. The following example shows how to call Get Media ID (Interrupt 21h Function 440Dh Minor Code 66h) from a Win32-based application.

#define VWIN32_DIOC_DOS_IOCTL 1

typedef struct _DIOC_REGISTERS {
    DWORD reg_EBX;
    DWORD reg_EDX;
    DWORD reg_ECX;
    DWORD reg_EAX;
    DWORD reg_EDI;
    DWORD reg_ESI;
    DWORD reg_Flags;
} DIOC_REGISTERS, *PDIOC_REGISTERS;

// Important: All MS_DOS data structures must be packed on a 
// one-byte boundary. 

#pragma pack(1) 
typedef struct _MID {
    WORD  midInfoLevel;
    DWORD midSerialNum;
    BYTE  midVolLabel[11];
    BYTE  midFileSysType[8];
} MID, *PMID;
#pragma pack()

HANDLE hDevice;
DIOC_REGISTERS reg;
MID mid;
BOOL fResult;
DWORD cb;
int nDrive = 3;  // Drive C:

hDevice = CreateFile("\\\\.\\vwin32",
    0, 0, NULL, 0, FILE_FLAG_DELETE_ON_CLOSE, NULL);

reg.reg_EAX = 0x440D;       // IOCTL for block devices 
reg.reg_EBX = nDrive;       // zero-based drive identifier 
reg.reg_ECX = 0x4866;       // Get Media ID command 
reg.reg_EDX = (DWORD) ∣ // receives media identifier information 
reg.reg_Flags = 0x0001;     // assume error (carry flag is set) 

fResult = DeviceIoControl(hDevice, 
    VWIN32_DIOC_DOS_IOCTL,
    &reg, sizeof(reg), 
    &reg, sizeof(reg), 
    &cb, 0);

if (!fResult || (reg.reg_Flags & 0x0001))
    ; // error if carry flag is set 

CloseHandle(hDevice);