www.pudn.com > DriveRescuev1.8.zip > 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
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.
------------------------------------------------------------------*)
function NewReadSectors (bDrive: BYTE;
dwStartSector: LONGWORD;
wSectors: WORD;
lpSectBuff: pointer): BOOLEAN;
var
fResult: BOOL;
cb : DWORD;
reg : DIOC_REGISTERS;
dio : DISKIO;
begin
fillchar(reg, sizeof(DIOC_REGISTERS), 0);
fillchar(dio, sizeof(DISKIO), 0);
dio.dwStartSector := dwStartSector;
dio.wSectors := wSectors;
dio.lpBuffer := lpSectBuff;
reg.reg_EAX := $7305; // Ext_ABSDiskReadWrite
reg.reg_EBX := DWORD(@dio);
reg.reg_ECX := DWORD(-1);
reg.reg_EDX := bDrive; // Int 21h, fn 7305h drive numbers are 1-based
fResult := DeviceIoControl(W95Handle, VWIN32_DIOC_DOS_DRIVEINFO,
@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;
(*------------------------------------------------------------------
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.
------------------------------------------------------------------*)
function NewWriteSectors (bDrive: BYTE;
dwStartSector: LONGWORD;
wSectors: WORD;
lpSectBuff: pointer): BOOLEAN;
var
fResult: BOOL;
cb : DWORD;
reg : DIOC_REGISTERS;
dio : DISKIO;
begin
fillchar(reg, sizeof(DIOC_REGISTERS), 0);
fillchar(dio, sizeof(DISKIO), 0);
dio.dwStartSector := dwStartSector;
dio.wSectors := wSectors;
dio.lpBuffer := lpSectBuff;
reg.reg_EAX := $7305; // Ext_ABSDiskReadWrite
reg.reg_EBX := DWORD(@dio);
reg.reg_ECX := DWORD(-1);
reg.reg_EDX := bDrive; // Int 21h, fn 7305h drive numbers are 1-based
reg.reg_ESI := $6001; // Normal file data (See function
// documentation for other values)
fResult := DeviceIoControl(W95Handle, VWIN32_DIOC_DOS_DRIVEINFO,
@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;
// Get Logical Drive Parameters
function GetLogDriveParams(bDrive: BYTE; params: PLogDriveParams): boolean;
var
h: tHANDLE;
reg: DIOC_REGISTERS;
cb: DWORD;
res: boolean;
dpb: DOSDPB;
hDevice: thandle;
dg: TDISK_GEOMETRY;
begin
res:=false;
if (fWinNT) then
begin
// ---------- Windows NT... ----------------------------------------------
hDevice := CreateFile(pchar('\\.\'+chr(ord('A')+bDrive-1)+':'), 0, FILE_SHARE_WRITE,
nil, OPEN_EXISTING, 0, 0);
if hDevice <> INVALID_HANDLE_VALUE then
begin
{ if NT CD-ROM }
if GetDriveType(pchar(chr(ord('A')+bDrive-1)+':\'))=DRIVE_CDROM then
begin
fillchar(params^, sizeof(TLogDriveParams), 0);
params^.MediaType:=LMEDIA_TYPE_CDROM;
params^.MediaAttr:=LMEDIA_ATTR_REMOVABLE;
params^.BytesPerSector:=2048;
result:=true;
exit;
end;
{ if NT Floppy, Harddisk, etc. }
res := DeviceIoControl(hDevice,
IOCTL_DISK_GET_DRIVE_GEOMETRY, nil, 0,
@dg, sizeof(TDISK_GEOMETRY), cb, nil);
CloseHandle(hDevice);
if res then
begin
params^.MediaAttr:=0;
params^.Heads:=dg.cylinders.lowpart;
params^.TracksPerHead:=dg.trackspercylinder;
params^.SectorsPerTrack:=dg.sectorspertrack;
params^.BytesPerSector:=dg.bytespersector;
params^.TotalPhysSec:=dg.cylinders.lowpart * dg.TracksPerCylinder * dg.SectorsPerTrack;
case dg.MediaType of
0: params^.MediaType:=LMEDIA_TYPE_UNKNOWN;
1..10, 13..22: begin
params^.MediaType:=LMEDIA_TYPE_FLOPPY;
params^.MediaAttr:=LMEDIA_ATTR_REMOVABLE;
end;
11: begin
params^.MediaType:=LMEDIA_TYPE_REMOVABLE;
params^.MediaAttr:=LMEDIA_ATTR_REMOVABLE;
end;
12: params^.MediaType:=LMEDIA_TYPE_FIXED;
end;
end;
end;
end else
begin
// --------- Windows 9X... --------------------------------------------
if IsCDROM(bDrive) then
begin
fillchar(params^, sizeof(TLogDriveParams), 0);
params^.MediaType:=LMEDIA_TYPE_CDROM;
params^.MediaAttr:=LMEDIA_ATTR_REMOVABLE;
params^.BytesPerSector:=2048;
result:=true;
exit;
end;
if optUseINT25 then
begin
dpb.specialFunc := 0; // return default type; do not hit disk
reg.reg_EBX := bDrive; // BL = drive number (1-based)
reg.reg_EDX := DWORD(@dpb); // DS:EDX -> DPB
reg.reg_ECX := $0860; // CX = Get DPB
reg.reg_EAX := $440D; // AX = Ioctl
reg.reg_Flags := CARRY_FLAG; // assume failure
// Make sure both DeviceIoControl and Int 21h succeeded.
res:=(DeviceIoControl (W95handle, VWIN32_DIOC_DOS_IOCTL, @reg,
sizeof(reg), @reg, sizeof(reg), cb, 0)
AND (reg.reg_Flags AND CARRY_FLAG=0));
if res then
begin
params^.MediaAttr:=0;
params^.Heads:=dpb.cHead;
params^.TracksPerHead:=dpb.cCyl;
params^.SectorsPerTrack:=dpb.secPerTrack;
params^.BytesPerSector:=dpb.cbSec;
params^.TotalPhysSec:=dpb.cCyl * dpb.cHead * dpb.secPerTrack;
case dpb.devType of
0..4, 7,8: params^.MediaType:=LMEDIA_TYPE_FLOPPY;
5: params^.MediaType:=LMEDIA_TYPE_FIXED;
6,9: if (dpb.devAttr AND 1) = 0 then params^.MediaType:=LMEDIA_TYPE_REMOVABLE
else params^.MediaType:=LMEDIA_TYPE_UNKNOWN;
end;
if (dpb.devAttr AND 1) = 0 then params^.MediaAttr:=LMEDIA_ATTR_REMOVABLE;
end;
end;
end;
result:=res;
end;
// -----------------------------------------------------------------------------------
// MSCDEX / CDFS (INT2F.VXD) ...
// -----------------------------------------------------------------------------------
function IsCDROM(drv: byte):Boolean;
var
res: boolean;
inbuf: byte;
outbuf: byte;
cb: dword;
begin
inbuf:=drv-1;
res:=DeviceIoControl(CDhandle, DIOC_ISCDROM,
@inbuf, 1,
@outbuf, 1, cb, nil);
result:=res AND (outbuf=1);
end;
function ReadCDROMSectors(drv: byte; LBA: longword; blocks: byte; buf: pointer;
ErrorDlg: boolean): boolean;
var
res: boolean;
struc: cdromstruc;
cb: dword;
tempbuf: array[0..2047] of byte;
count: integer;
msgRes: integer;
begin
count:=0;
struc.Drv := drv-1;
struc.LBA := LBA;
struc.blocks := 1; //blocks;
struc.buf := {buf;} @tempbuf;
repeat
repeat
res:=DeviceIoControl(CDhandle, DIOC_READSECTORS,
@struc, sizeof(cdromstruc),
nil, 0, cb, nil);
msgRes := id_abort;
if (NOT res) AND (ErrorDlg) then
begin
msgRes:=messagebox(0, pchar('Error reading sector, '+#13#10+'drv:'+inttostr(drv)+' LBA:'+inttostr(LBA)
+' blocks:'+inttostr(blocks) +#13#10#13#10
+' Abort, Retry or Ignore?'), pchar('MSCDEX/CDFS CD-ROM read error '+inttostr(windows.GetLastError)),
mb_applmodal or mb_iconwarning or mb_abortretryignore);
end;
until NOT ((ErrorDlg) AND (msgRes = id_Retry));
if (NOT res) AND (ErrorDlg) AND (msgRes = id_ignore) then res:=true;
if res then move(tempbuf, buf^, 2048);
inc(longword(buf),2048);
inc(count);
inc(struc.LBA);
until (NOT res) OR (count >= blocks);
result:=res;
end;
// -------------------------------------------------------------------------
// same stuff for Windows NT . . .
// -------------------------------------------------------------------------
(* -- open / close drive handle ------------------------------------------ *)
function NT_changeDrive(bDrive: BYTE; ReadOnly: boolean): boolean;
var
hDevice: thandle;
begin
// notice: under WinNT each drive has to be opened - under Win9X/ME one handle is for all drives
if (NThandle <> INVALID_HANDLE_VALUE) then
begin
if NTdrive = bDrive then
begin
result:=true;
exit;
end else
begin
CloseHandle(NThandle);
end;
end;
if ReadOnly then
hDevice := CreateFile(pchar('\\.\'+chr(ord('A')+bDrive-1)+':'), GENERIC_READ, FILE_SHARE_READ OR FILE_SHARE_WRITE,
nil, OPEN_EXISTING, FILE_FLAG_WRITE_THROUGH, 0)
else
hDevice := CreateFile(pchar('\\.\'+chr(ord('A')+bDrive-1)+':'), GENERIC_WRITE, FILE_SHARE_READ OR FILE_SHARE_WRITE,
nil, OPEN_EXISTING, FILE_FLAG_WRITE_THROUGH, 0);
NThandle:=hDevice;
NTdrive:=bDrive;
GetLogDriveParams(bDrive, @nt_drv_params);
NT_ShiftBase:=round(log2(nt_drv_params.bytespersector));
result:=(hDevice <> INVALID_HANDLE_VALUE);
end;
function NT_Read ( bDrive: BYTE;
dwStartSector: LONGWORD;
wSectors: WORD;
lpSectBuff: pointer): BOOLEAN;
var
res: boolean;
bytestoread, numread, transfer: dword;
dwpointer: dword;
ldistancelow, ldistancehigh : dword;
DestSector : longword;
begin
res:=false;
if NT_changeDrive(bDrive, true) then
begin
ldistanceLow:=longword(dwStartSector) SHL NT_ShiftBase;
ldistanceHigh:=longword(dwStartSector) SHR (32-NT_ShiftBase);
dwpointer:=SetFilePointer(NThandle, ldistancelow, @ldistancehigh, FILE_BEGIN);
if dwPointer <> $FFFFFFFF then
begin
bytestoread:=wSectors*nt_drv_params.bytespersector;
repeat
transfer:=bytestoread;
if (transfer > TEMPSECTORS * nt_drv_params.bytespersector) then
transfer:=TEMPSECTORS * nt_drv_params.bytespersector;
res:=ReadFile(NThandle, tempbuf, transfer, numread, nil);
if res then res:=boolean(numread=transfer);
if res then move(tempbuf, lpSectBuff^, transfer);
inc(longword(lpSectBuff),transfer);
dec(bytestoread, transfer);
until (NOT res) OR (bytestoread = 0);
end;
end;
result:=res;
end;
function NT_Write ( bDrive: BYTE;
dwStartSector: LONGWORD;
wSectors: WORD;
lpSectBuff: pointer): BOOLEAN;
var
res: boolean;
bytestoread, numread: dword;
dwpointer: dword;
ldistancelow, ldistancehigh: dword;
begin
res:=false;
if NT_changeDrive(bDrive, false) then
begin
ldistanceLow:=dword(dwStartSector SHL 9);
ldistanceHigh:=dword(dwStartSector SHR (32-9));
dwpointer:=SetFilePointer(NThandle, ldistancelow, @ldistancehigh, FILE_BEGIN);
if dwPointer <> $FFFFFFFF then
begin
bytestoread:=wSectors*nt_drv_params.bytespersector;
res:=WriteFile(NThandle, lpSectBuff^, bytestoread, numread, nil);
res:=(res AND (numread =bytestoread));
end;
end;
result:=res;
end;
procedure MyExit;
begin
ExitProc := ExitSave; { first restore old vector }
if NOT (fWinNT) then
begin
// Win9X...
if W95Handle <> INVALID_HANDLE_VALUE then
CloseHandle(W95Handle);
if CDHandle <> INVALID_HANDLE_VALUE then
CloseHandle(CDHandle);
end else
begin
// WinNT...
if NThandle <> INVALID_HANDLE_VALUE then
CloseHandle(NThandle);
end;
end;
begin
optUseINT25:=TRUE;
W95Handle := INVALID_HANDLE_VALUE;
NTHandle := INVALID_HANDLE_VALUE;
fWin95OSR2orLater:=IsWin95OSR2orLater;
fWinNT :=IsWinNT;
ExitSave := ExitProc;
ExitProc := @MyExit;
if NOT (fWinNT) then
begin
W95Handle := CreateFile('\\.\vwin32',
0, 0, nil, 0, FILE_FLAG_DELETE_ON_CLOSE, 0);
if W95handle = INVALID_HANDLE_VALUE then
MessageBox(0, 'Error loading "VWIN32.VXD (INT25/26)"', 'Error', mb_IconExclamation + mb_ok);
CDhandle:=CreateFile('\\.\INT2F.VXD',
0, 0, nil, 0, FILE_FLAG_DELETE_ON_CLOSE, 0);
if CDhandle = INVALID_HANDLE_VALUE then
MessageBox(0, 'Error loading "INT2F.VXD" (MSCDEX/CDFS)', 'Error', mb_IconExclamation + mb_ok);
end;
end.