Microsoft KB Archive/174569

{|
 * width="100%"|

BUG: Int 21 Read/Write Track on Logical Drive Fails on OSR2 and Later

 * }

Q174569

-

The information in this article applies to:


 * Microsoft Win32 Application Programming Interface (API), used with:
 * the operating system: Microsoft Windows 95
 * the operating system: Microsoft Windows 98
 * the operating system: Microsoft Windows Millennium Edition

-

SYMPTOMS
On Windows 95 OEM Service Release2 (OSR2), Windows 98, and Windows Me, Read Track on Logical Drive (Int 21h function 440Dh minor code 61h) and Write Track on Logical Drive (Int 21h function 440Dh minor code 41h), do not work when called through the DeviceIoControl API. When these functions are called, both DeviceIoControl and the Int 21h functions succeed, but the data is not read or written. However, both functions work correctly when called from Win16-based and MS-DOS based applications.

On the retail version of Windows 95, both functions work when called through DeviceIOControl as well as Win16-based and MS-DOS based applications.

CAUSE
There is a bug that affects Int 21h function 440Dh minor codes 61h and 41h only when called through DeviceIoControl.

RESOLUTION
There are two ways to work around this bug:


 * 1) Use DeviceIoControl with VWIN32_DIOC_DOS_INT25 and VWIN32_DIOC_DOS_INT26 to issue Absolute Disk Read (Int 25h) and Absolute Disk Write (Int 26h) respectively. This method works for FAT12 and FAT16 volumes. This method is compatible with the retail release version of Windows 95, but will not work on FAT32 volumes.
 * 2) Use DeviceIoControl with VWIN32_DIOC_DOS_DRIVEINFO to issue Ext Absolute Disk Read & Write (Int 21h function 7305h). This method works for FAT12, FAT16, and FAT32 volumes, but is not backward compatible with the retail release version of Windows 95.

STATUS
Microsoft has confirmed this to be a bug in the Microsoft products listed at the beginning of this article. We are researching this bug and will post new information here in the Microsoft Knowledge Base as it becomes available.

MORE INFORMATION
Win32 and console applications running on Windows 95 and its successors use the DeviceIoControl API to issue MS-DOS Interrupt 21h functions to perform low-level disk I/O. Such applications usually are disk utilities that must bypass the file system in order to perform activities such as formatting and defragmenting disks.

Windows 95 and its successors provides several functions to access sectors on a logical drive. These functions correspond to those available to MS-DOS and Win16-based applications, including Int 21h function 440Dh functions, Int 25h, and Int 26h. In addition, Windows 95 OEM Service Release 2 (OSR2) includes a new function, Int 21h function 7305h.

If your application must be compatible with the retail release version of Windows 95, but still support FAT32, then it should check the operating system version. If Windows 95 OSR2 or later is running, your application can call Int 21h function 7305h. If it is running on the retail release of Windows 95, it should use Int 25h and Int 26h. The following code demonstrates how to call these functions.

Sample Code
  #include 

#define VWIN32_DIOC_DOS_INT25    2 #define VWIN32_DIOC_DOS_INT26    3 #define VWIN32_DIOC_DOS_DRIVEINFO 6

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;

#define CARRY_FLAG 1

#pragma pack(1) typedef struct _DISKIO { DWORD dwStartSector;   // starting logical sector number WORD  wSectors;        // number of sectors DWORD dwBuffer;        // address of read/write buffer } DISKIO, * PDISKIO; #pragma pack

/*--  ReadLogicalSectors (hDev, bDrive, dwStartSector, wSectors, lpSectBuff)

Purpose: Reads sectors from a logical drive. Uses Int 25h.

Parameters: hDev Handle of VWIN32

bDrive The MS-DOS logical drive number. 1 = A, 2 = B, 3 = C, etc.

dwStartSector The first logical sector to read

wSectors The number of sectors to read

lpSectBuff The caller-supplied buffer that will contain the sector data

Return Value: Returns TRUE if successful, or FALSE if failure.

Comments: This function does not validate its parameters. --*/   BOOL ReadLogicalSectors (HANDLE hDev,                            BYTE   bDrive,                            DWORD  dwStartSector,                            WORD   wSectors,                            LPBYTE lpSectBuff) {     BOOL           fResult; DWORD         cb; DIOC_REGISTERS reg = {0}; DISKIO        dio = {0};

dio.dwStartSector = dwStartSector; dio.wSectors     = wSectors; dio.dwBuffer     = (DWORD)lpSectBuff;

reg.reg_EAX = bDrive - 1;   // Int 25h drive numbers are 0-based. reg.reg_EBX = (DWORD)&dio; reg.reg_ECX = 0xFFFF;       // use DISKIO struct

fResult = DeviceIoControl(hDev, VWIN32_DIOC_DOS_INT25,                               &reg, sizeof(reg),                                &reg, sizeof(reg), &cb, 0);

// Determine if the DeviceIoControl call and the read succeeded. fResult = fResult && !(reg.reg_Flags & CARRY_FLAG);

return fResult; }

/*--  WriteLogicalSectors (hDev, bDrive, dwStartSector, wSectors, lpSectBuff)

Purpose: Writes sectors to a logical drive. Uses Int 26h

Parameters: hDev Handle of VWIN32

bDrive The MS-DOS logical drive number. 1 = A, 2 = B, 3 = C, etc.

dwStartSector The first logical sector to write

wSectors The number of sectors to write

lpSectBuff The caller-supplied buffer that contains the sector data

Return Value: Returns TRUE if successful, or FALSE if failure.

Comments: This function does not validate its parameters. --*/   BOOL WriteLogicalSectors (HANDLE hDev,                             BYTE   bDrive,                             DWORD  dwStartSector,                             WORD   wSectors,                             LPBYTE lpSectBuff) {     BOOL           fResult; DWORD         cb; DIOC_REGISTERS reg = {0}; DISKIO        dio = {0};

dio.dwStartSector = dwStartSector; dio.wSectors     = wSectors; dio.dwBuffer     = (DWORD)lpSectBuff;

reg.reg_EAX = bDrive - 1;   // Int 26h drive numbers are 0-based. reg.reg_EBX = (DWORD)&dio; reg.reg_ECX = 0xFFFF;       // use DISKIO struct

fResult = DeviceIoControl(hDev, VWIN32_DIOC_DOS_INT26,                               &reg, sizeof(reg),                                &reg, sizeof(reg), &cb, 0);

// Determine if the DeviceIoControl call and the write succeeded. fResult = fResult && !(reg.reg_Flags & CARRY_FLAG);

return fResult; }

/*--  NewReadSectors(hDev, bDrive, dwStartSector, wSectors, lpSectBuff)

Purpose: Reads the specified number of sectors into a caller-supplied buffer. Uses Int 21h function 7305h

Parameters: hDev Handle of VWIN32

bDrive The MS-DOS logical drive number. 0 = default, 1 = A, 2 = B,       3 = C, etc.

dwStartSector The first sector to read.

wSectors The number of sectors to read.

lpSectBuff The caller-supplied buffer to read into.

Return Value: Returns TRUE if successful, or FALSE if failure.

Comments: This function does not validate its parameters. It assumes that lpSectBuff is allocated by the caller and is large enough to    hold all of the data from all of the sectors being read. --*/   BOOL NewReadSectors (HANDLE hDev,                        BYTE   bDrive,                        DWORD  dwStartSector,                        WORD   wSectors,                        LPBYTE lpSectBuff) {    BOOL           fResult; DWORD         cb; DIOC_REGISTERS reg = {0}; DISKIO        dio;

dio.dwStartSector = dwStartSector; dio.wSectors     = wSectors; dio.lpBuffer     = (DWORD)lpSectBuff;

reg.reg_EAX = 0x7305;  // Ext_ABSDiskReadWrite reg.reg_EBX = (DWORD)&dio; reg.reg_ECX = -1; reg.reg_EDX = bDrive;  // Int 21h, fn 7305h drive numbers are 1-based

fResult = DeviceIoControl(hDev, VWIN32_DIOC_DOS_DRIVEINFO,                              &reg, sizeof(reg),                               &reg, sizeof(reg), &cb, 0);

// Determine if the DeviceIoControl call and the read succeeded. fResult = fResult && !(reg.reg_Flags & CARRY_FLAG);

return fResult; }

/*--  NewWriteSectors(hDev, bDrive, dwStartSector, wSectors, lpSectBuff)

Purpose: Writes the specified number of sectors from a caller-supplied buffer. Uses Int 21h function 7305h

Parameters: hDev Handle of VWIN32

bDrive The MS-DOS logical drive number. 0 = default, 1 = A, 2 = B,       3 = C, etc.

dwStartSector The first sector to write.

wSectors The number of sectors to write.

lpSectBuff The caller-supplied buffer from which to write.

Return Value: Returns TRUE if successful, or FALSE if failure.

Comments: This function does not validate its parameters. It assumes that lpSectBuff is allocated by the caller and is large enough to    hold all of the data to be written. --*/   BOOL NewWriteSectors (HANDLE hDev,                        BYTE   bDrive,                        DWORD  dwStartSector,                        WORD   wSectors,                        LPBYTE lpSectBuff) {    BOOL           fResult; DWORD         cb; DIOC_REGISTERS reg = {0}; DISKIO        dio;

dio.dwStartSector = dwStartSector; dio.wSectors     = wSectors; dio.lpBuffer     = (DWORD)lpSectBuff;

reg.reg_EAX = 0x7305;  // Ext_ABSDiskReadWrite reg.reg_EBX = (DWORD)&dio; reg.reg_ECX = -1; reg.reg_EDX = bDrive;  // Int 21h, fn 7305h drive numbers are 1-based

reg.reg_ESI = 0x6001;  // Normal file data (See function                             // documentation for other values)

fResult = DeviceIoControl(hDev, VWIN32_DIOC_DOS_DRIVEINFO,                              &reg, sizeof(reg),                               &reg, sizeof(reg), &cb, 0);

// Determine if the DeviceIoControl call and the write succeeded. fResult = fResult && !(reg.reg_Flags & CARRY_FLAG);

return fResult; }