📄 pdiskio.pas
字号:
{
Physical Disk Access for Delphi
(physical disk read/write under Windows 95/98/ME and NT/2000/XP)
Written 2001 by Alexander Grau
Contact: alexander_grau@web.de
}
unit pdiskio;
interface
const
{ Media types }
PMEDIA_TYPE_UNKNOWN = 0;
PMEDIA_TYPE_FLOPPY = 1;
PMEDIA_TYPE_REMOVABLE = 2;
PMEDIA_TYPE_FIXED = 3;
{ Media attributes }
PMEDIA_ATTR_REMOVABLE = 1;
type
PPhysDriveParams = ^TPhysDriveParams;
TPhysDriveParams = record
MediaType : word; { see equals above }
MediaAttr : word; { see equals above }
Heads : longword;
TracksPerHead : longword;
SectorsPerTrack : longword;
BytesPerSector : longword;
TotalPhysSec : longword;
end;
(* -------------- published functions --------------------------------- *)
(* drv: the INT13 drive, 0=first floppy
1=second floppy
...
80h=first fixed/removable disk
81h=second fixed/removable disk
... *)
function ReadPhysicalSectors(drv: byte; LBA: longword; blocks: word; buf: pointer; ErrorDlg: boolean): boolean;
function WritePhysicalSectors(drv: byte; LBA: longword; blocks: word; buf: pointer;
verify: boolean; ErrorDlg: boolean): boolean;
function GetPhysDriveParams(drv: byte; resultbuf: PPhysDriveParams): boolean;
var
OptUseINT13: boolean;
OptUseINT13EXT: boolean;
implementation
uses sysutils, windows, helpers;
// --------------- INT13 Extensions specific... ----------------------------------------------------
const
IFLAG_HANDLES_DMA_BOUNDARY = 1;
IFLAG_GEOMETRY_VALID = 2;
IFLAG_REMOVABLE = 4;
IFLAG_VERIFY_SUPPORT = 8;
IFLAG_CHANGE_LINE_SUPPORT = 16;
IFLAG_IS_LOCKABLE = 32;
IFLAG_NO_MEDIA_PRESENT = 64;
type
PDriveParams = ^TDriveParams;
TDriveParams = packed record { used by GetDriveParams }
bufsize : word;
infoflags : word;
physcyl : longword;
physheads : longword;
physsecptrk: longword;
physsecLO : longword;
physsecHI : longword;
bytesPerSec: word;
EDDptr : pointer;
{ DevPathInfoFlag: word;
DevPathInfoLen : byte;
res0 : byte;
res1 : word;
HostBusType : array[0..3] of char;
InterfaceType : array[0..7] of char;
InterfacePath : Qword;
DevicePath : Qword;
res2 : byte;
DevPathInfoChksum: byte; }
end;
// --------- Windows NT specific... -------------------------------------------------------------
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) );
(*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;
// ------ INT13EXT.VXD specific... ------------------------------------------------
const
DIOC_CHECKEXTENSIONS = 1;
DIOC_EXTENDEDREAD = 2;
DIOC_EXTENDEDWRITE = 3;
DIOC_GETDRIVEPARAMS = 4;
type
extstruc = 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;
verify: byte;
end;
// --------------------------------------------------------------------------------
const
TEMPSECTORS = 128;
var
W95Handle: thandle; // Win9X/ME only: current handle
NTHandle: thandle; // WinNT only: current handle
NTDrive: byte; // WinNT only: drive currently opened
ExitSave: Pointer;
winNTflag: boolean;
i: integer;
disk_geometry: tdisk_geometry;
tempbuf: array[0..512*TEMPSECTORS-1] of byte;
// -----------------------------------------------------------------------------------
// Windows NT specific...
// -----------------------------------------------------------------------------------
function NT_changedrive(drv: byte; ReadOnly: boolean): boolean;
var
hDevice: thandle;
begin
if NThandle <> INVALID_HANDLE_VALUE then
begin
if NTdrive = drv then
begin
result:=true;
exit;
end else
begin
CloseHandle(NThandle);
end;
end;
{ handle drive numbers like INT13 Extensions! 0..$7f are removable, $80 and above are fixed }
if drv IN [0..$7f] then
begin
if (drv IN [0..1]) then
begin
if ReadOnly then
hDevice := CreateFile(pchar('\\.\'+chr(ord('A')+drv)+':'), GENERIC_READ, FILE_SHARE_READ OR FILE_SHARE_WRITE,
nil, OPEN_EXISTING, FILE_FLAG_WRITE_THROUGH, 0)
else
hDevice := CreateFile(pchar('\\.\'+chr(ord('A')+drv)+':'), GENERIC_WRITE, FILE_SHARE_WRITE,
nil, OPEN_EXISTING, FILE_FLAG_WRITE_THROUGH, 0)
end;
end
else begin
if ReadOnly then
hDevice:=CreateFile(pchar('\\.\PhysicalDrive'+inttostr(drv-$80)), GENERIC_READ, FILE_SHARE_READ OR FILE_SHARE_WRITE,
nil, OPEN_EXISTING, FILE_FLAG_WRITE_THROUGH, 0)
else
hDevice:=CreateFile(pchar('\\.\PhysicalDrive'+inttostr(drv-$80)), GENERIC_WRITE, FILE_SHARE_WRITE,
nil, OPEN_EXISTING, FILE_FLAG_WRITE_THROUGH, 0);
end;
NThandle:=hDevice;
NTdrive:=drv;
result:=(hDevice <> INVALID_HANDLE_VALUE);
end;
function NT_CheckMedia(hDev: thandle): boolean;
var
cb: DWORD;
begin
cb:=0;
result := DeviceIoControl(hDev,
IOCTL_STORAGE_CHECK_VERIFY, nil, 0,
nil, 0, cb, nil);
// here's something wrong with floppy disks...
result:=true;
end;
function NT_GetDriveGeometry(drv: byte; dg: PDISK_GEOMETRY): boolean;
var
hDevice: thandle;
fResult: boolean;
cb: DWORD;
begin
fResult:=false; hDevice:=INVALID_HANDLE_VALUE;
{ handle drive numbers like INT13 Extensions! 0..$7f are removable, $80 and above are fixed }
if drv IN [0..$7f] then
begin
if (drv IN [0..1]) then
hDevice := CreateFile(pchar('\\.\'+chr(ord('A')+drv)+':'),
0, FILE_SHARE_READ OR FILE_SHARE_WRITE,
nil, OPEN_EXISTING, 0, 0);
if (hDevice <> INVALID_HANDLE_VALUE) then
begin
if NOT (NT_CheckMedia(hDevice)) then
begin
CloseHandle(hDevice);
hDevice:=INVALID_HANDLE_VALUE;
end;
end;
end
else
hDevice := CreateFile(pchar('\\.\PhysicalDrive'+inttostr(drv-$80)),
0, FILE_SHARE_READ OR FILE_SHARE_WRITE,
nil, OPEN_EXISTING, 0, 0);
if (hDevice <> INVALID_HANDLE_VALUE) then
begin
fResult := DeviceIoControl(hDevice,
IOCTL_DISK_GET_DRIVE_GEOMETRY, nil, 0,
dg, sizeof(TDISK_GEOMETRY), cb, nil);
CloseHandle(hDevice);
end;
NT_GetDriveGeometry:=fResult;
end;
function NT_Read(drv: byte; LBA: longword; blocks: word; buf: pointer; ErrorDlg: boolean): boolean;
var
res: boolean;
bytestoread, numread, transfer: longword;
err: dword;
i: integer;
dwpointer: dword;
ldistancelow, ldistancehigh: dword;
msgRes: integer;
begin
res:=false;
if NT_changedrive(drv, true) then
begin
ldistanceLow:=dword(LBA SHL 9);
ldistanceHigh:=dword(LBA SHR (32-9));
dwpointer:=SetFilePointer(NThandle, ldistancelow, @ldistancehigh, FILE_BEGIN);
if dwPointer <> $FFFFFFFF then
begin
bytestoread:=blocks*512;
repeat
transfer:=bytestoread;
if (transfer > TEMPSECTORS * 512) then transfer:=TEMPSECTORS * 512;
repeat
res:=ReadFile(NThandle, tempbuf, transfer, numread, nil);
if res then res:=boolean(numread=transfer);
msgRes := id_abort;
if (NOT res) AND (ErrorDlg) then
begin
err:=GetLastError;
msgRes:=messagebox(0, pchar('error no.'+inttostr(err)+#13#10+'drv:'+inttostr(drv)+' LBA:'+inttostr(LBA)
+' blocks:'+inttostr(blocks)+#13#10#13#10
+'Abort, Retry or Ignore?'), 'NT_read error', 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^, transfer);
inc(longword(buf),transfer);
dec(bytestoread, transfer);
until (NOT res) OR (bytestoread = 0);
end;
end;
NT_Read:=(res); // AND (numread=blocks*512);
end;
function NT_Write(drv: byte; LBA: longword; blocks: word; buf: pointer; ErrorDlg: boolean): boolean;
var
res: boolean;
bytestowrite, numwritten, transfer: longword;
err: dword;
i: integer;
bufp: ^byte;
dwpointer: dword;
ldistancelow, ldistancehigh: dword;
msgRes: integer;
begin
res:=false;
if NT_changedrive(drv, false) then
begin
ldistanceLow:=dword(LBA SHL 9);
ldistanceHigh:=dword(LBA SHR (32-9));
dwpointer:=SetFilePointer(NThandle, ldistancelow, @ldistancehigh, FILE_BEGIN);
if dwPointer <> $FFFFFFFF then
begin
bytestowrite:=blocks*512;
repeat
transfer:=bytestowrite;
if (transfer > TEMPSECTORS * 512) then transfer:=TEMPSECTORS * 512;
move(buf^, tempbuf, transfer);
repeat
res:=WriteFile(NThandle, tempbuf, transfer, numwritten, nil);
if res then res:=boolean(numwritten=transfer);
msgRes := id_abort;
if (NOT res) AND (ErrorDlg) then
begin
err:=GetLastError;
msgRes:=messagebox(0, pchar('error no.'+inttostr(err)+#13#10+'drv:'+inttostr(drv)+' LBA:'+inttostr(LBA)
+' blocks:'+inttostr(blocks)+#13#10#13#10
+'Abort, Retry or Ignore?'), 'NT_write error', 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;
inc(longword(buf),transfer);
dec(bytestowrite, transfer);
until (NOT res) OR (bytestowrite = 0);
end;
end;
NT_write:=(res); // AND (numread=blocks*512);
end;
// -----------------------------------------------------------------------------------
// legacy INT13 functions...
// -----------------------------------------------------------------------------------
const
VWIN32_DIOC_DOS_IOCTL = 1;
VWIN32_DIOC_DOS_INT13 = 4;
CARRY_FLAG = $0001; // Intel x86 processor status flags
type
PLegacyDriveParams = ^TLegacyDriveParams;
TLegacyDriveParams = record
status : byte;
CMOS_DriveType : byte;
cylinders : word;
secpertrack : byte;
heads : byte;
drives : byte;
end;
DEVIOCTL_REGISTERS=record
case Integer of
0: (
bl, bh, bl2, bh2: byte;
dl, dh, dl2, dh2: byte;
cl, ch, cl2, ch2: byte;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -