//--------------------------------------------------------------------------- #include #include #pragma hdrstop #include "DiskAccess.h" //--------------------------------------------------------------------------- #pragma package(smart_init) //--------------------------------------------------------------------------- #define VWIN32_DIOC_DOS_IOCTL 1 // DOS ioctl calls 4400h-4411h #define VWIN32_DIOC_DOS_INT25 2 // absolute disk read, DOS int 25h #define VWIN32_DIOC_DOS_INT26 3 // absolute disk write, DOS int 26h #define VWIN32_DIOC_DOS_DRIVEINFO 6 // OEM Service Release 2 // Int 21h, 73xxh extensions 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; // Intel x86 processor status flag #define CARRY_FLAG 0x1 /********************************************************* **** Note: all MS-DOS data structures must be packed **** **** on a one-byte boundary. **** *********************************************************/ #pragma pack(1) typedef struct _DOSDPB { BYTE specialFunc; // BYTE devType; // WORD devAttr; // WORD cCyl; // number of cylinders BYTE mediaType; // WORD cbSec; // Bytes per sector BYTE secPerClus; // Sectors per cluster WORD cSecRes; // Reserved sectors BYTE cFAT; // FATs WORD cDir; // Root Directory Entries WORD cSec; // Total number of sectors in image BYTE bMedia; // Media descriptor WORD secPerFAT; // Sectors per FAT WORD secPerTrack; // Sectors per track WORD cHead; // Heads DWORD cSecHidden; // Hidden sectors DWORD cTotalSectors; // Total sectors, if cbSec is zero BYTE reserved[6]; // } DOSDPB, *PDOSDPB; typedef struct _DISKIO { DWORD diStartSector; // sector number to start at WORD diSectors; // number of sectors DWORD diBuffer; // address of buffer } DISKIO, *PDISKIO; #pragma pack() //--------------------------------------------------------------------------- DWORD __fastcall GetDriveFormFactor(int iDrive) { HANDLE h; TCHAR tsz[8]; DWORD dwRc; if ((int)GetVersion() < 0) { // Windows 95 /* On Windows 95, use the technique described in the Knowledge Base article Q125712 and in MSDN under "Windows 95 Guide to Programming", "Using Windows 95 features", "Using VWIN32 to Carry Out MS-DOS Functions". */ h = CreateFileA("\\\\.\\VWIN32", 0, 0, NULL, 0, FILE_FLAG_DELETE_ON_CLOSE, 0); if (h != INVALID_HANDLE_VALUE) { DWORD cb; DIOC_REGISTERS reg; DOSDPB dpb; dpb.specialFunc = 0; // return default type; do not hit disk reg.reg_EBX = iDrive; // BL = drive number (1-based) reg.reg_EDX = (DWORD)&dpb; // DS:EDX -> DPB reg.reg_ECX = 0x0860; // CX = Get DPB reg.reg_EAX = 0x440D; // AX = Ioctl reg.reg_Flags = CARRY_FLAG; // assume failure // Make sure both DeviceIoControl and Int 21h succeeded. if (DeviceIoControl (h, VWIN32_DIOC_DOS_IOCTL, ®, sizeof(reg), ®, sizeof(reg), &cb, 0) && !(reg.reg_Flags & CARRY_FLAG)) { switch (dpb.devType) { case 0: // 5.25 360K floppy case 1: // 5.25 1.2MB floppy dwRc = 525; break; case 2: // 3.5 720K floppy case 7: // 3.5 1.44MB floppy case 9: // 3.5 2.88MB floppy dwRc = 350; break; case 3: // 8" low-density floppy case 4: // 8" high-density floppy dwRc = 800; break; case 5: // hard drive dwRc = 1; break; case 6: // tape drive case 8: // optical disk dwRc = 2; break; default: // unknown dwRc = 0; break; } } else dwRc = 0; CloseHandle(h); } else dwRc = 0; } else { // Windows NT /* On Windows NT, use the technique described in the Knowledge Base article Q115828 and in the "FLOPPY" SDK sample. */ wsprintf(tsz, TEXT("\\\\.\\%c:"), TEXT('@') + iDrive); h = CreateFile(tsz, 0, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0); if (h != INVALID_HANDLE_VALUE) { DISK_GEOMETRY Geom[20]; DWORD cb; if (DeviceIoControl (h, IOCTL_DISK_GET_MEDIA_TYPES, 0, 0, Geom, sizeof(Geom), &cb, 0) && cb > 0) { switch (Geom[0].MediaType) { case F5_1Pt2_512: // 5.25 1.2MB floppy case F5_360_512: // 5.25 360K floppy case F5_320_512: // 5.25 320K floppy case F5_320_1024: // 5.25 320K floppy case F5_180_512: // 5.25 180K floppy case F5_160_512: // 5.25 160K floppy dwRc = 525; break; case F3_1Pt44_512: // 3.5 1.44MB floppy case F3_2Pt88_512: // 3.5 2.88MB floppy case F3_20Pt8_512: // 3.5 20.8MB floppy case F3_720_512: // 3.5 720K floppy dwRc = 350; break; case RemovableMedia: dwRc = 2; break; case FixedMedia: dwRc = 1; break; default: dwRc = 0; break; } } else dwRc = 0; CloseHandle(h); } else dwRc = 0; } /* If you are unable to determine the drive type via ioctls, then it means one of the following: 1. It is hard drive and we do not have administrator privilege 2. It is a network drive 3. The drive letter is invalid GetDriveType can distinguish these three cases. */ if (dwRc == 0) { wsprintf(tsz, TEXT("%c:\\"), TEXT('@') + iDrive); switch (GetDriveType(tsz)) { case DRIVE_FIXED: dwRc = 1; break; case DRIVE_REMOVABLE: case DRIVE_REMOTE: case DRIVE_CDROM: case DRIVE_RAMDISK: dwRc = 2; break; default: dwRc = 0; } } return dwRc; } //--------------------------------------------------------------------------- __fastcall TDiskAccess::TDiskAccess(char v) { unsigned short drive_flags; int ret; volz = v - 'A'; // requested volume, 'A'=0, 'B'=1 hVWin32Device = CreateFile( "\\\\.\\vwin32", 0, 0, NULL, 0, FILE_FLAG_DELETE_ON_CLOSE, NULL ); if ( hVWin32Device ) return; ret = VolumeCheck( &drive_flags ); if ( ret ) { CloseHandle( hVWin32Device ); hVWin32Device = NULL; } } //--------------------------------------------------------------------------- __fastcall TDiskAccess::~TDiskAccess() { if ( hVWin32Device ) CloseHandle( hVWin32Device ); } //--------------------------------------------------------------------------- int __fastcall TDiskAccess::VolumeCheck( WORD* flags ) { DIOC_REGISTERS reg; BOOL bResult; DWORD cb; reg.reg_EAX = 0x4409; // Is Drive Remote reg.reg_EBX = volz + 1; // one-based drive number reg.reg_Flags = CARRY_FLAG; // preset the carry flag bResult = DeviceIoControl( hVWin32Device, VWIN32_DIOC_DOS_IOCTL, ®, sizeof( reg ), ®, sizeof( reg ), &cb, 0 ); if ( !bResult || (reg.reg_Flags & CARRY_FLAG) ) return (reg.reg_EAX & 0xffff); *flags = (WORD)(reg.reg_EDX & 0xffff); return 0; } //--------------------------------------------------------------------------- int __fastcall TDiskAccess::Read( DWORD start_sector, WORD num_sectors, void* pBuf ) { BOOL bResult; DWORD cb; DIOC_REGISTERS reg = { 0 }; DISKIO di; if ( !hVWin32Device ) return -1; di.diStartSector = start_sector; di.diSectors = num_sectors; di.diBuffer = (DWORD)pBuf; reg.reg_EAX = volz; // zero-based volume number reg.reg_EBX = (DWORD)&di; reg.reg_ECX = 0xffff; // use DISKIO structure reg.reg_Flags = CARRY_FLAG; // preset the carry flag bResult = DeviceIoControl( hVWin32Device, VWIN32_DIOC_DOS_INT25, ®, sizeof( reg ), ®, sizeof( reg ), &cb, 0 ); if ( !bResult || (reg.reg_Flags & CARRY_FLAG) ) return -1; return 0; } //--------------------------------------------------------------------------- int __fastcall TDiskAccess::Write( DWORD start_sector, WORD num_sectors, void* pBuf ) { BOOL bResult; DWORD cb; DIOC_REGISTERS reg; DISKIO di; if ( !hVWin32Device ) return -1; di.diStartSector = start_sector; di.diSectors = num_sectors; di.diBuffer = (DWORD)pBuf; reg.reg_EAX = volz; // zero-based volume number reg.reg_EBX = (DWORD)&di; reg.reg_ECX = 0xffff; // use DISKIO structure reg.reg_Flags = CARRY_FLAG; // preset the carry flag bResult = DeviceIoControl( hVWin32Device, VWIN32_DIOC_DOS_INT26, ®, sizeof( reg ), ®, sizeof( reg ), &cb, 0 ); if ( !bResult || (reg.reg_Flags & CARRY_FLAG) ) return -1; return 0; } //---------------------------------------------------------------------------