📄 ldiskio.pas
字号:
{
Logical Disk Access for Delphi
(Absolute disk read/write under Windows 95/98/ME and NT/2000/XP)
Written 2001 by Alexander Grau
Contact: alexander_grau@web.de
}
unit LDISKIO;
interface
const
{ Media types }
LMEDIA_TYPE_UNKNOWN = 0;
LMEDIA_TYPE_FLOPPY = 1;
LMEDIA_TYPE_REMOVABLE = 2;
LMEDIA_TYPE_FIXED = 3;
LMEDIA_TYPE_CDROM = 4;
{ Media attributes }
LMEDIA_ATTR_REMOVABLE = 1;
type
PLogDriveParams = ^TLogDriveParams;
TLogDriveParams = record
MediaType : word; { see equals above }
MediaAttr : word; { see equals above }
Heads : longword;
TracksPerHead : longword;
SectorsPerTrack : longword;
BytesPerSector : longword;
TotalPhysSec : longword;
end;
(* -------------- published functions --------------------------------- *)
// bDrive: The MS-DOS logical drive number. 1 = A, 2 = B, 3 = C, etc.
function ReadLogicalSectors (bDrive: BYTE;
dwStartSector: LONGWORD;
wSectors: WORD;
lpSectBuff: pointer): BOOLEAN;
function WriteLogicalSectors (bDrive: BYTE;
dwStartSector: LONGWORD;
wSectors: WORD;
lpSectBuff: pointer): BOOLEAN;
function GetLogDriveParams(bDrive: BYTE; params: PLogDriveParams): boolean;
var
optUseINT25: boolean;
(* ------------------------------------------------------------------ *)
implementation
uses windows, sysutils, math;
// -------- Windows 9X specific... -------------------------------------------------------
const
VWIN32_DIOC_DOS_IOCTL =1;
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 26h)
VWIN32_DIOC_DOS_DRIVEINFO =6; // Performs Interrupt 21h Function 730X commands. This value is supported in Windows 95 OEM Service Release 2 and later.
// Intel x86 processor status flag
CARRY_FLAG = 1;
type
PDIOC_REGISTERS = ^DIOC_REGISTERS;
DIOC_REGISTERS = packed record
reg_EBX: DWORD;
reg_EDX: DWORD;
reg_ECX: DWORD;
reg_EAX: DWORD;
reg_EDI: DWORD;
reg_ESI: DWORD;
reg_Flags: DWORD;
end;
PDISKIO = ^ DISKIO;
DISKIO = packed record
dwStartSector: DWORD; // starting logical sector number
wSectors : WORD; // number of sectors
lpBuffer : pointer; // address of read/write buffer
end;
PDOSDPB = ^DOSDPB;
DOSDPB = packed record
specialFunc: BYTE; //
devType : BYTE; //
devAttr : WORD; //
cCyl : WORD; // number of cylinders
mediaType : BYTE; //
cbSec : WORD; // Bytes per sector
secPerClus : BYTE; // Sectors per cluster
cSecRes : WORD; // Reserved sectors
cFAT : BYTE; // FATs
cDir : WORD; // Root Directory Entries
cSec : WORD; // Total number of sectors in image
bMedia : BYTE; // Media descriptor
secPerFAT : WORD; // Sectors per FAT
secPerTrack: WORD; // Sectors per track
cHead : WORD; // Heads
cSecHidden : DWORD; // Hidden sectors
cTotalSectors: DWORD; // Total sectors, if cbSec is zero
reserved: array[0..5] of BYTE //
end;
// ------ INT2F.VXD specific... ------------------------------------------------
const
DIOC_ISCDROM = 1;
DIOC_READSECTORS = 2;
type
cdromstruc = packed record { Important! Delphi is not allowed to align to 32-Bit here!
(otherwise something goes wrong...) }
drv : byte;
LBA : longword;
blocks: byte;
buf : pointer;
end;
// -------- Windows NT specific... -------------------------------------------------------
(*typedef enum _MEDIA_TYPE {
Unknown, // Format is unknown
F5_1Pt2_512, // 5.25", 1.2MB, 512 bytes/sector
F3_1Pt44_512, // 3.5", 1.44MB, 512 bytes/sector
F3_2Pt88_512, // 3.5", 2.88MB, 512 bytes/sector
F3_20Pt8_512, // 3.5", 20.8MB, 512 bytes/sector
F3_720_512, // 3.5", 720KB, 512 bytes/sector
F5_360_512, // 5.25", 360KB, 512 bytes/sector
F5_320_512, // 5.25", 320KB, 512 bytes/sector
F5_320_1024, // 5.25", 320KB, 1024 bytes/sector
F5_180_512, // 5.25", 180KB, 512 bytes/sector
F5_160_512, // 5.25", 160KB, 512 bytes/sector
RemovableMedia, // Removable media other than floppy
FixedMedia, // Fixed hard disk media
F3_120M_512, // 3.5", 120M Floppy
F3_640_512, // 3.5" , 640KB, 512 bytes/sector
F5_640_512, // 5.25", 640KB, 512 bytes/sector
F5_720_512, // 5.25", 720KB, 512 bytes/sector
F3_1Pt2_512, // 3.5" , 1.2Mb, 512 bytes/sector
F3_1Pt23_1024, // 3.5" , 1.23Mb, 1024 bytes/sector
F5_1Pt23_1024, // 5.25", 1.23MB, 1024 bytes/sector
F3_128Mb_512, // 3.5" MO 128Mb 512 bytes/sector
F3_230Mb_512, // 3.5" MO 230Mb 512 bytes/sector
F8_256_128 // 8", 256KB, 128 bytes/sector
} MEDIA_TYPE, *PMEDIA_TYPE;*)
type
PLARGE_INTEGER = ^LARGE_INTEGER;
LARGE_INTEGER = packed record
LowPart: dword;
HighPart: dword;
end;
PDISK_GEOMETRY = ^TDISK_GEOMETRY;
TDISK_GEOMETRY = packed record
Cylinders: LARGE_INTEGER;
MediaType: dword;
TracksPerCylinder: dword;
SectorsPerTrack: dword;
BytesPerSector: dword;
end;
const
FILE_DEVICE_DISK = $00000007;
FILE_DEVICE_MASS_STORAGE = $0000002d;
FILE_ANY_ACCESS = 0;
FILE_READ_ACCESS = $0001; // file & pipe
METHOD_BUFFERED = 0;
IOCTL_DISK_BASE = FILE_DEVICE_DISK;
IOCTL_STORAGE_BASE = FILE_DEVICE_MASS_STORAGE;
IOCTL_DISK_GET_DRIVE_GEOMETRY = ( ((IOCTL_DISK_BASE) SHL 16) OR ((FILE_ANY_ACCESS) SHL 14) OR (($0000) SHL 2) OR (METHOD_BUFFERED) );
IOCTL_DISK_CHECK_VERIFY = ( ((IOCTL_DISK_BASE) SHL 16) OR ((FILE_READ_ACCESS) SHL 14)OR (($0200) SHL 2) OR (METHOD_BUFFERED) );
IOCTL_STORAGE_CHECK_VERIFY = ( ((IOCTL_STORAGE_BASE) SHL 16)OR((FILE_READ_ACCESS)SHL 14)OR (($0200) SHL 2) OR (METHOD_BUFFERED) );
IOCTL_DISK_GET_MEDIA_TYPES = ( ((IOCTL_DISK_BASE) SHL 16) OR((FILE_ANY_ACCESS)SHL 14) OR (($0300) SHL 2) OR (METHOD_BUFFERED) );
// ------------------------------------------------------------------------------
const
TEMPSECTORS = 128;
var
CDHandle: thandle; // Win9X only: current CD-ROM handle (INT2F.VXD)
W95Handle: thandle; // Win9X only: current handle (VWIN32.VXD)
NTHandle: thandle; // WinNT only: current handle
NTDrive: byte; // WinNT only: drive currently opened
NT_DRV_Params : TLogDriveParams; // WinNT only: current drive params
NT_ShiftBase : byte; //WinNT only: NT_DRV_Params.BytesPerASector in Bit-Shifts
fWin95OSR2orLater: boolean;
fWinNT : boolean;
tempbuf: array[0..512*TEMPSECTORS-1] of byte;
ExitSave: Pointer;
(* --- some forward declarations ----------------------------------------- *)
//----------- under Windows 95 OEM Service Release 2 and later... -----------
function NewReadSectors (bDrive: BYTE;
dwStartSector: LONGWORD;
wSectors: WORD;
lpSectBuff: pointer): BOOLEAN; forward;
function NewWriteSectors (bDrive: BYTE;
dwStartSector: LONGWORD;
wSectors: WORD;
lpSectBuff: pointer): BOOLEAN; forward;
// ------------- CD-ROM absolute read sector ---------------------------------
function IsCDROM(drv: byte): boolean; forward;
function ReadCDROMSectors(drv: byte; LBA: longword; blocks: byte; buf: pointer;
ErrorDlg: boolean): boolean; forward;
// -------------- under Windows NT... ----------------------------------------
function NT_Read ( bDrive: BYTE;
dwStartSector: LONGWORD;
wSectors: WORD;
lpSectBuff: pointer): BOOLEAN; forward;
function NT_Write ( bDrive: BYTE;
dwStartSector: LONGWORD;
wSectors: WORD;
lpSectBuff: pointer): BOOLEAN; forward;
(* --- helper functions --------------------------------------------------- *)
function IsWin95OSR2orLater: boolean;
var
os: TOSVersionInfo;
res: boolean;
begin
ZeroMemory(@OS,SizeOf(OS));
OS.dwOSVersionInfoSize:=SizeOf(OS);
GetVersionEx(OS);
res:=false;
// from Microsoft Programmer's Guide to Win95:
// "The GetVersionEx function fills the members of an OSVERSIONINFO data structure. If the dwPlatformId member of that structure
// is VER_PLATFORM_WIN32_WINDOWS, and the low word of the dwBuildNumber member is greater than 1080, the system is running
// Windows 95,OEM Service Release 2 or a later release of Windows 95."
// if the there are problems with the following detection use above one...
if os.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS then
begin
if (OS.dwMajorVersion >= 4) and (OS.dwMinorVersion>0) then res:=true
else begin
if (OS.dwMajorVersion=4) and (OS.dwMinorVersion=0) then
begin
if (Trim(OS.szCSDVersion)='B') then res:=true;
end;
end;
end;
result:=res;
end;
function IsWinNT: boolean;
var
info: TOSVersionInfo;
begin
IsWinNT:=false;
info.dwOSVersionInfoSize:=sizeof(TOSVersionInfo);
if GetVersionEx(info) then
begin
if info.dwPlatformId = VER_PLATFORM_WIN32_NT then IsWinNT:=true;
end;
end;
(*------------------------------------------------------------------
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.
------------------------------------------------------------------*)
function ReadLogicalSectors (bDrive: BYTE;
dwStartSector: LONGWORD;
wSectors: WORD;
lpSectBuff: pointer): BOOLEAN;
var
fResult: BOOL;
cb: DWORD;
reg: DIOC_REGISTERS;
dio: DISKIO;
begin
if fWinNT then
begin
result:=NT_read( bDrive, dwStartSector, wSectors, lpSectBuff);
exit;
end;
// CD-ROM (MSCDEX/CDFS) ?
if IsCDROM( bDrive ) then
begin
result:=ReadCDROMSectors( bDrive, dwStartSector, wSectors, lpSectBuff, TRUE);
exit;
end;
if optUseINT25 then
begin
// Windows 95 OEM Service Release 2 and later ?
if fWin95OSR2orLater then
begin
result:=NewReadSectors( bDrive, dwStartSector, wSectors, lpSectBuff);
exit;
end;
fillchar(reg, sizeof(DIOC_REGISTERS), 0);
fillchar(dio, sizeof(DISKIO), 0);
dio.dwStartSector := dwStartSector;
dio.wSectors := wSectors;
dio.lpBuffer := lpSectBuff;
reg.reg_EAX := bDrive - 1; // Int 25h drive numbers are 0-based.
reg.reg_EBX := DWORD(@dio);
reg.reg_ECX := $FFFF; // use DISKIO struct
fResult := DeviceIoControl(W95Handle, VWIN32_DIOC_DOS_INT25,
@reg, sizeof(reg),
@reg, sizeof(reg), cb, 0);
// Determine if the DeviceIoControl call and the read succeeded.
fResult := fResult AND (reg.reg_Flags AND CARRY_FLAG=0);
result:=fResult;
end else result:=FALSE;
end;
(*------------------------------------------------------------------
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.
------------------------------------------------------------------*)
function WriteLogicalSectors (bDrive: BYTE;
dwStartSector: LONGWORD;
wSectors: WORD;
lpSectBuff: pointer): BOOLEAN;
var
fResult: BOOL;
cb : DWORD;
reg : DIOC_REGISTERS;
dio : DISKIO;
begin
if fWinNT then
begin
result:=NT_write( bDrive, dwStartSector, wSectors, lpSectBuff);
exit;
end;
if optUseINT25 then
begin
// Windows 95 OEM Service Release 2 and later ?
if fWin95OSR2orLater then
begin
result:=NewWriteSectors(bDrive, dwStartSector, wSectors, lpSectBuff);
exit;
end;
fillchar(reg, sizeof(DIOC_REGISTERS), 0);
fillchar(dio, sizeof(DISKIO), 0);
dio.dwStartSector := dwStartSector;
dio.wSectors := wSectors;
dio.lpBuffer := lpSectBuff;
reg.reg_EAX := bDrive - 1; // Int 26h drive numbers are 0-based.
reg.reg_EBX := DWORD(@dio);
reg.reg_ECX := $FFFF; // use DISKIO struct
fResult := DeviceIoControl(W95Handle, VWIN32_DIOC_DOS_INT26,
@reg, sizeof(reg),
@reg, sizeof(reg), cb, 0);
// Determine if the DeviceIoControl call and the write succeeded.
fResult := fResult AND (reg.reg_Flags AND CARRY_FLAG=0);
result:=fResult;
end else result:=FALSE;
end;
(*------------------------------------------------------------------
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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -