uses Windows;
type
TDiskGeometry =
packed record
Cylinders: Int64;
MediaType: Integer;
TracksPerCylinder: DWORD;
SectorsPerTrack: DWORD;
BytesPerSector: Integer;
// wichtig für die Reservierung des Buffer-Speichers
end;
TRawDrive =
record
DiskGeometry: TDiskGeometry;
Handle: THandle;
end;
var
IOCTL_DISK_GET_DRIVE_GEOMETRY = $00070000;
FSCTL_LOCK_VOLUME = $00090018;
FSCTL_UNLOCK_VOLUME = $0009001C;
function RawOpenDrive(DriveLetter: Char): TRawDrive;
var num: Cardinal;
begin
FillChar(Result, SizeOf(TRawDrive), 0);
Result.Handle := CreateFile(PChar('
\\.\' + DriveLetter + '
:'),
GENERIC_READ
or GENERIC_WRITE,
FILE_SHARE_READ
or FILE_SHARE_WRITE,
nil,
OPEN_EXISTING,
0,
0);
if Result.Handle = INVALID_HANDLE_VALUE
then RaiseLastOSError;
// Laufwerk für andere sperren
if not DeviceIoControl(Result, FSCTL_LOCK_VOLUME,
nil, 0,
nil, 0, num,
nil)
then
RaiseLastOSError;
{ Disk-Geometry ermitteln. Vor allem ist das Feld BytesPerSector wichtig, da nur vielfache Bytes gelesen werden können. Ist also BytesPerSector z.B: 512 und man will nur 1 Byte lesen, muss man 512 Bytes lesen. }
if not DeviceIoControl(h, IOCTL_DISK_GET_DRIVE_GEOMETRY,
nil, 0, @Result.DiskGeometry,
SizeOf(TDiskGeometry), num,
nil)
then
RaiseLastOSError;
end;
procedure RawCloseDrive(
var RawDrive: TRawDrive);
var num: Cardinal;
begin
DeviceIoControl(RawDrive.Handle, FSCTL_UNLOCK_VOLUME,
nil, 0,
nil, 0, num,
nil);
CloseHandle(RawDrive.Handle);
RawDrive.Handle := 0;
end;
procedure RawReadSectors(
const RawDrive: TRawDrive;
var Buf; Count: Integer);
var num: Cardinal;
begin
if not ReadFile(RawDrive.Handle, Buf, Count * RawDrive.DiskGeometry.BytesPerSector, num,
nil)
then
RaiseLastOSError;
end;
procedure RawWriteSectors(
const RawDrive: TRawDrive;
var Buf; Count: Integer);
var num: Cardinal;
begin
if not WriteFile(RawDrive.Handle, Buf, Count * RawDrive.DiskGeometry.BytesPerSector, num,
nil)
then
RaiseLastOSError;
end;