📄 diskio.pas
字号:
unit DiskIO;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms;
const
BytesPerSector = 512;
type
{ TDiskIO }
TDiskIO = class(TObject)
public
function ReadLogicalSector(Drive: Char; SectorStart, SectorCount: Longint;
DataStream: TMemoryStream): Boolean; virtual; abstract;
function WriteLogicalSector(Drive: Char; SectorStart, SectorCount: Longint;
DataStream: TMemoryStream): Boolean; virtual; abstract;
end;
{ TWin9xDiskIO }
TWin9xDiskIO = class(TDiskIO)
public
function ReadLogicalSector(Drive: Char; SectorStart, SectorCount: Longint;
DataStream: TMemoryStream): Boolean; override;
function WriteLogicalSector(Drive: Char; SectorStart, SectorCount: Longint;
DataStream: TMemoryStream): Boolean; override;
end;
{ TWinNTDiskIO }
TWinNTDiskIO = class(TDiskIO)
public
function ReadLogicalSector(Drive: Char; SectorStart, SectorCount: Longint;
DataStream: TMemoryStream): Boolean; override;
function WriteLogicalSector(Drive: Char; SectorStart, SectorCount: Longint;
DataStream: TMemoryStream): Boolean; override;
end;
var
DiskIOObject: TDiskIO;
implementation
uses WinVer;
{ TWin9xDiskIO }
const
FILE_FLAG_DELETE_ON_CLOSE = $04000000;
VWIN32_DIOC_DOS_IOCTL = 1; { MS-DOS Int 21h 44xxh functions call }
VWIN32_DIOC_DOS_INT25 = 2; { MS-DOS Int 25h function call }
VWIN32_DIOC_DOS_INT26 = 3; { MS-DOS Int 26h function call }
VWIN32_DIOC_DOS_INT13 = 4; { MS-DOS Int 13h functions call }
VWIN32_DIOC_DOS_DRIVEINFO = 6; {MS-DOS Int 21h function 730X}
type
TDiskIORec = packed Record
dwStartSector: Longint;
wSectors: Smallint;
lpBuffer: PChar;
end;
P32Regs = ^T32Regs; //32位寄存器结构
T32Regs = record
EBX: Longint;
EDX: Longint;
ECX: Longint;
EAX: Longint;
EDI: Longint;
ESI: Longint;
Flags: Longint;
end;
function LockDisk(VMM32Handle: Cardinal; Disk: Byte; LockOrNot: Boolean): Boolean;
var
R: T32Regs;
cb: DWord;
begin
if VMM32Handle = INVALID_HANDLE_VALUE then
begin
Result := False;
Exit;
end;
FillChar(R, SizeOf(R), 0);
if LockOrNot then
begin
R.ECX := $084b;
R.EBX := $100 + Disk; //bh:0-3级 0,1,$80,$81...
R.EDX := 1; //1允许写,0允许格式化
end else
begin
R.ECX := $086b;
R.EBX := Disk; //0,1,$80,$81...
end;
R.EAX := $440D;
DeviceiOControl(VMM32Handle, VWIN32_DIOC_DOS_IOCTL, @R, SizeOf(R), @R, SizeOf(R), cb, nil);
Result := (R.Flags and 1 = 0);
end;
function LockDrive(VMM32Handle: Cardinal; Drive: Byte; LockOrNot: Boolean): Boolean;
var
R: T32Regs;
cb: DWord;
begin
if VMM32Handle = INVALID_HANDLE_VALUE then
begin
Result := False;
Exit;
end;
FillChar(R, SizeOf(R), 0);
if LockOrNot then
begin
R.ECX := $084a;
R.EBX := $100 + drive; //bh:0-4级 0当前盘,1:A,2:B,3:C
R.EDX := 1; //1允许写,0允许格式化
end
else begin
R.ECX := $086A;
R.EBX := Drive; //0当前盘,1:A,2:B,3:C
end;
R.EAX := $440D;
DeviceiOControl(VMM32Handle, VWIN32_DIOC_DOS_IOCTL, @R, SizeOf(R), @R, SizeOf(R), cb, nil);
Result := (R.Flags and 1 = 0); //and (R.EAX and $FFFF = 0);
end;
function TWin9xDiskIO.ReadLogicalSector(Drive: Char;
SectorStart, SectorCount: Integer; DataStream: TMemoryStream): Boolean;
var
cb: DWord;
DriveNo: integer;
DiskIORec: TDiskIORec;
Reg: T32Regs;
DeviceHandle: THandle;
begin
Result := False;
DriveNo := Ord(UpCase(Drive)) - Ord('A') + 1;
DeviceHandle := CreateFile('\\.\VWIN32', 0, 0, nil, 0, FILE_FLAG_DELETE_ON_CLOSE, 0);
if DeviceHandle <> INVALID_HANDLE_VALUE then
begin
DataStream.Clear;
DataStream.SetSize(SectorCount * BytesPerSector);
DiskIORec.dwStartSector := SectorStart;
DiskIORec.wSectors := SectorCount;
DiskIORec.lpBuffer := DataStream.Memory;
Reg.EAX := $7305;
Reg.EBX := Integer(@DiskIORec);
Reg.ECX := -1;
Reg.EDX := DriveNo; //1-A 2-B 3-C
Reg.ESI := 0; //读
Reg.Flags := 0;
DeviceIoControl(DeviceHandle, VWIN32_DIOC_DOS_DRIVEINFO, @Reg, SizeOf(Reg), @Reg, SizeOf(Reg), cb, nil);
Result := (Reg.Flags and 1) <> 1;
end;
end;
function TWin9xDiskIO.WriteLogicalSector(Drive: Char;
SectorStart, SectorCount: Integer; DataStream: TMemoryStream): Boolean;
var
cb: DWord;
DriveNo: integer;
DiskIORec: TDiskIORec;
Reg: T32Regs;
DeviceHandle: THandle;
begin
Result := False;
DriveNo := Ord(UpCase(Drive)) - Ord('A') + 1;
DeviceHandle := CreateFile('\\.\VWIN32', 0, 0, nil, 0, FILE_FLAG_DELETE_ON_CLOSE, 0);
if DeviceHandle <> INVALID_HANDLE_VALUE then
begin
DataStream.Clear;
DataStream.SetSize(SectorCount * BytesPerSector);
LockDrive(DeviceHandle, DriveNo, True);
DiskIORec.dwStartSector := SectorStart;
DiskIORec.wSectors := SectorCount;
DiskIORec.lpBuffer := DataStream.Memory;
Reg.EAX := $7305;
Reg.EBX := Integer(@DiskIORec);
Reg.ECX := -1;
Reg.EDX := DriveNo; //1-A 2-B 3-C
Reg.ESI := 1; //写
Reg.Flags := 0;
DeviceIoControl(DeviceHandle, VWIN32_DIOC_DOS_DRIVEINFO, @Reg, SizeOf(Reg), @Reg, SizeOf(Reg), cb, nil);
Result := (Reg.Flags and 1) <> 1;
LockDrive(DeviceHandle, DriveNo, False);
end;
end;
{ TWinNTDiskIO }
function TWinNTDiskIO.ReadLogicalSector(Drive: Char;
SectorStart, SectorCount: Integer; DataStream: TMemoryStream): Boolean;
var
I: Integer;
DriveStr: string;
DeviceHandle: THandle;
begin
Result := False;
DriveStr := Format('\\.\%s:', [Drive]);
DeviceHandle := CreateFile(PChar(DriveStr), GENERIC_READ,
FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
if (DeviceHandle <> INVALID_HANDLE_VALUE) then
begin
DataStream.Clear;
DataStream.SetSize(SectorCount * BytesPerSector);
FileSeek(DeviceHandle, SectorStart * BytesPerSector, 0);
I := FileRead(DeviceHandle, DataStream.Memory^, SectorCount*BytesPerSector);
Result := (I = SectorCount*BytesPerSector);
CloseHandle(DeviceHandle);
end;
end;
function TWinNTDiskIO.WriteLogicalSector(Drive: Char;
SectorStart, SectorCount: Integer; DataStream: TMemoryStream): Boolean;
var
I: Integer;
DriveStr: string;
DeviceHandle: THandle;
begin
Result := False;
DriveStr := Format('\\.\%s:', [Drive]);
DeviceHandle := CreateFile(PChar(DriveStr), GENERIC_ALL,
FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
if (DeviceHandle <> INVALID_HANDLE_VALUE) then
begin
DataStream.Clear;
DataStream.SetSize(SectorCount * BytesPerSector);
FileSeek(DeviceHandle, SectorStart * BytesPerSector, 0);
I := FileWrite(DeviceHandle, DataStream.Memory^, SectorCount*BytesPerSector);
Result := (I = SectorCount*BytesPerSector);
CloseHandle(DeviceHandle);
end;
end;
initialization
if WinVersion in [wvWinNT, wvWin2000, wvWinXP] then
DiskIOObject := TWinNTDiskIO.Create
else
DiskIOObject := TWin9xDiskIO.Create;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -