📄 ldiskio.pas
字号:
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.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -