home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2002 March
/
Chip_2002-03_cd1.bin
/
zkuste
/
delphi
/
kompon
/
d5
/
cak
/
CAKDIR.ZIP
/
VWIN32.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1999-10-21
|
110KB
|
2,369 lines
{------------------------------------------------------------------------------}
{ unit : vwin32 }
{ version : 1.0 }
{ last update: 1999/04/06 }
{ written for: Delphi 3 & 4 }
{ written by : Geir Wikran }
{ e-mail : gwikran@online.no }
{ }
{ This source code is freeware. You may use, change, and distribute without }
{ charge the source code as you like. This unit can be used freely in any }
{ commercial applications. However, it may not be sold as a standalone product }
{ and the source code may not be included in a commercial product. This unit }
{ is provided as is with no warrent or support. Make sure to read relevant }
{ information and documentation from Microsoft before using this unit. }
{------------------------------------------------------------------------------}
{- Relevant information and documentation from Microsoft ----------------------}
{ }
{ Go to http://www.microsoft.com/ and select "Search". }
{ Enter "VWIN32" for search word, and select search }
{ category "Support & the Knowledge Base". The search }
{ will give articles on how to do low-level disk access }
{ under Win9x. }
{ }
{ Go to http://msdn.microsoft.com/library/ }
{ Browse down the tree to find }
{ -Platform SDK }
{ -Windows Base Services }
{ -Windows 95 Features }
{ -Windows 95 Reference }
{ Before doing any direct disk I/O make sure to read }
{ all information on using the drive locking and lock }
{ hierarcy. This is important. }
{ }
{------------------------------------------------------------------------------}
unit vwin32;
{==============================================================================}
interface
uses
Windows;
{- VWIN32 DeviceIoControl -----------------------------------------------------}
{ Windows 95/98 does not support opening disk drives or partitions with the }
{ CreateFile() function as Windows NT does. Windows 9x does not support the }
{ DeviceIoControl() IOCTL APIs as Windows NT does. Instead, low-level disk }
{ access in Windows 9x is supported through DeviceIoControl() calls to the }
{ VWIN32 VxD, which supports a set of control codes that applications can use }
{ to issue low-level disk I/O functions. These functions include interrup 13h, }
{ interrupt 25h, interrupt 26h, interrupt 21h function 44xx and function 730x. }
const
{ Name of DIOC device: }
VWIN32_DEVICE_NAME = '\\.\VWIN32';
{ VWIN32 device control codes used with VWIN32DIOC function: }
VWIN32_DIOC_CLOSE = 0; { Close the device. }
VWIN32_DIOC_DOS_IOCTL = 1; { MS-DOS device I/O control function, }
{ interrupt 21h function 4400h through 4411h }
VWIN32_DIOC_DOS_INT25 = 2; { MS-DOS absolute disk read command, }
{ interrupt 25h. }
VWIN32_DIOC_DOS_INT26 = 3; { MS-DOS absolute disk write command, }
{ interrupt 26h. }
VWIN32_DIOC_DOS_INT13 = 4; { Low-level BIOS disk functions, }
{ interrupt 13h. }
VWIN32_DIOC_DOS_DRIVEINFO = 6; { MS-DOS Interrupt 21h new function 730x. }
{ Supported only by Windows 95 OSR2 and later.}
type
PDIOC_Registers = ^TDIOC_Registers;
TDIOC_Registers = record
case Byte of
0: (EBX,EDX,ECX,EAX,EDI,ESI,Flags: DWord);
1: (BX,BXE,DX,DXE,CX,CXE,AX,AXE,DI,DIE,SI,SIE: Word);
end;
{ Some functions require far pointers passed in segment:offset pairs. Since }
{ 32-bit code does not have segments, the TDIOC_Registers structure contains }
{ no segment registers. The full pointer should be placed into the register }
{ corresponding to the offset portion of the real-mode pointer. For example, }
{ use EDX for pointer that go into DS:DX. }
const
FLAG_CARRY = $00000001;
function VWIN32DIOC(ControlCode: Integer; Registers: PDIOC_Registers): Boolean;
{ Implements DeviceIoControl() calls to VWIN32.VXD. The device is }
{ automatically opened when needed. The ControlCode VWIN32_DIOC_CLOSE}
{ can be used to close the device. However, the device will be closed}
{ automatically by the units finalization. The function returnes }
{ ERROR_OS_NOT_SUPPORTED in VWIN32Error it is not supported by the }
{ running Windows version, or it returne ERROR_OPENING_DEVICE if an }
{ error occured when trying to open the device. }
{- Windows Version ------------------------------------------------------------}
function WindowsVersion(Major,Minor,Build,Platform: DWord): Boolean;
{ Tests the running version of Windows. Returns true if it is equal }
{ or higher than the specified version info. See GetVersionEx in }
{ Win32.hlp for more information. }
{ Windows 9x - WindowsVersion(0,0,0,VER_PLATFORM_WIN32_WINDOWS) }
{ Windows 95 OSR2 - WindowsVersion(0,0,1081,VER_PLATFORM_WIN32_WINDOWS) }
{ Because of changes to functions and data structures after the introduction }
{ of FAT32 in Windows 95 OSR2, a test for this Windows version will often be }
{ needed. To make the test simple this unit provides the boolean variable }
{ Win95OSR2, which is initialized to true if the running Windows 9x is }
{ Windows 95 OSR2 or later. }
var
Win95OSR2: Boolean;
{------------------------------------------------------------------------------}
{ Logical drives: 0=default, 1=A, 2=B, 3=C ... 26=Z }
{------------------------------------------------------------------------------}
function DriveIsRemovable(Drive: Byte): Boolean;
{ Returns true if a drive is removable. }
function DriveIsRemote(Drive: Byte): Boolean;
{ Returns true if a drive is remote. }
function DriveIsSubstitute(Drive: Byte): Boolean;
{ Returns true if a drive is substituted (see MS-DOS subst command). }
function DirectAccessAllowed(Drive: Byte): Boolean;
{ Returns true if a drive allows direct I/O. }
function LockRemovableMedia(Drive: Byte): Boolean;
{ Locks the media in a drive (preventing its removal). }
function UnlockRemovableMedia(Drive: Byte): Boolean;
{ Unlocks the media in a drive (permitting its removal). }
function GetRemovableMediaLocks(Drive: Byte; var Locks: Byte): Boolean;
{ Returns the lock status on a drive (number of pending locks). }
function EjectRemovableMedia(Drive: Byte): Boolean;
{ Ejects the media in a drive. }
function GetAccessFlag(Drive: Byte; var Flag: Byte): Boolean;
{ Returns the access flag for a drive. Flag=0 if access blocked }
{ (unformatted), Flag<>0 if access allowed. }
function SetAccessFlag(Drive: Byte; Flag: Byte): Boolean;
{ Sets the access flag for a drive. }
{- Volume Locking -------------------------------------------------------------}
const
{ Lock peermission codes: }
LOCK_ALLOW_WRITING = $0001; { Allow write operations in level 1 lock. Write }
{ operations are always blocked in level 2 & 3 }
{ lock. }
LOCK_BLOCK_MAPPING = $0002; { Block new file mappings in level 1 & 2 lock. }
{ New file mappings are always blocked in level }
{ 3 lock. }
{ Read operations are always allowed in level }
{ 1 & 2 lock, and blocked in level 3 lock. }
LOCK_FOR_FORMATTING = $0004; { Locks the volume for formatting. Specified }
{ when a level 0 lock is obtained for the second}
{ time. }
function LockLogicalVolume(Drive: Byte; Level,Permission: Byte): Boolean;
{ Locks a logical drive. A drive must be locked before direct disk }
{ write operations through Interrupt 26h or Interrupt 21h IOCTL }
{ functions can be performed. }
function LockPhysicalVolume(Disk: Byte; Level,Permission: Byte): Boolean;
{ Locks a physical disk. Disk 00-7Fh for floppy disk drives }
{ (00=first floppy drive, 01=second, and so on). Disk 80-FEh }
{ for hard disk drives (80=first hard disk, 81=second, and so on). }
{ A disk must be locked before direct disk write operations through }
{ Interrupt 13h can be performed. The system automatically takes a }
{ logical volume lock on all logical drives on the physical disk. }
function UnlockLogicalVolume(Drive: Byte): Boolean;
{ Unlocks a logical drive and decrements the lock level. To release }
{ the lock on a drive the unlock function must be called the same }
{ number of times that lock function was called. }
function UnlockPhysicalVolume(Disk: Byte): Boolean;
{ Unlocks a physical disk and decrements the lock level. To release }
{ the lock on a disk the unlock function must be called the same }
{ number of times that lock function was called. }
function GetCurrentLockState(Drive: Byte; var Level,Permission: Byte): Boolean;
{ Returns a drive's current lock level and permission. }
function GetLockFlagState(Drive: Byte; var Flags: Word): Boolean;
{ Polls the state of the access flag for a drive to determine if a }
{ write operation (deleting or renaming a file, writing to a file }
{ etc.) or a new file mapping has occurred since the last time the }
{ flags were polled. Flag values: }
{ 0= no operation has occured }
{ 1= write operations have occured }
{ 2= file mapping has occured }
const
{ Access modes (bits 0-3): }
OPEN_ACCESS_READONLY = $0000;
OPEN_ACCESS_WRITEONLY = $0001;
OPEN_ACCESS_READWRITE = $0002;
OPEN_ACCESS_RO_NOMODLASTACCESS = $0004;
{ Share modes (bits 4-6): }
OPEN_SHARE_COMPATIBLE = $0000;
OPEN_SHARE_DENYREADWRITE = $0010;
OPEN_SHARE_DENYWRITE = $0020;
OPEN_SHARE_DENYREAD = $0030;
OPEN_SHARE_DENYNONE = $0040;
{ Open flags (bits 7-15): }
OPEN_FLAGS_NOINHERIT = $0080;
OPEN_FLAGS_NO_BUFFERING = $0100;
OPEN_FLAGS_NO_COMPRESS = $0200;
OPEN_FLAGS_ALIAS_HINT = $0400;
OPEN_FLAGS_NOCRITERR = $2000;
OPEN_FLAGS_COMMIT = $4000;
{ File types: }
FILE_TYPE_NORMAL = $0000; { Normal file }
FILE_TYPE_MEMORY_MAPPED = $0001; { Memory-mapped file (are unmovable) }
FILE_TYPE_UNMOVABLE = $0002; { Unmovable (32-bit DLLs and EXEs) }
FILE_TYPE_SWAP = $0004; { Windows' swap file }
function EnumerateOpenFiles(Drive: Byte; FileIndex: DWord; var FilePath: String;
var OpenMode,FileType: Word): Boolean;
{ Enumerates open files on the specified drive. The function returns }
{ information about one file at a time. To enumerate all open files, }
{ the function must be called repeatedly with FileIndex set to a new }
{ value for each call. FileIndex should be set to zero initially and }
{ then incremented by one for each subsequent call. The path of the }
{ open file is returned in PathBuf. The mode that the file was opened}
{ in is returned in OpenMode, which is a combination of access mode, }
{ share mode, and open flags. The type of the file is returned in }
{ FileType. }
{ ERROR_NO_MORE_FILES are returned when all open files on the volume }
{ have been enumerated. ERROR_ACCESS_DENIED is returned if FileIndex }
{ exceeds the number of open files on the drive. }
{ The function may return inconsistent results when used on a volume }
{ where other processes may be opening and closing files. The volume }
{ should be in a level 3 lock before enumerating open files. }
function FindSwapFile(var FilePath: String; var PagerType: Word; var PageCount: DWord): Boolean;
{ Returns information about Windows' swap file. The path of the swap }
{ file is returned in FilePath. The type of the pager is returned in }
{ PagerType (1=no pager, 2=paging trough MS-DOS, 3=paging through }
{ protected-mode I/O supervisor). The current number of 4Kb pages in }
{ the swap file is returned in PageCount. }
const
{ Reset drive flags: }
RESET_DRIVE_BUFFERS = $0000; { Reset drive, flush file system buffers. }
RESET_DRIVE_BUFFERS_CACHE = $0001; { Reset drive, flush file system buffers, }
{ flush and ivalidate drive cache. }
RESET_DRIVE_DRIVESPACE = $0002; { Remounts drivespace volume. }
{function ResetDrive(Drive: Byte; Flag: Word): Boolean;}
{ Flushes file system buffers and cache and optionally remounts the }
{ drivespace volume. Any Buffered write operations are performed, and}
{ all waiting data is written to the appropriate drive. }
{- Media Identifier -----------------------------------------------------------}
type
TMediaIdentifier = packed record
InfoLevel : Word; { Information level (must be zero). }
SerialNumber : DWord; { Serial number for the medium. }
VolumeLabel : array[0..10] of Char; { Volume label for the medium. }
FileSysType : array[0..7] of Char; { 'FAT12' 12-bit FAT file system }
{ 'FAT16' 16-bit FAT file system }
{ 'FAT32' 32-bit FAT file system }
{ 'CDROM' High Sierra file system}
{ 'CD001' ISO9660 file system }
{ 'CDAUDIO' Audio disk }
end;
function GetMediaIdentifier(Drive: Byte; var Media: TMediaIdentifier): Boolean;
{ Returnes a drive's serial number, volume label, and file system. }
function SetMediaIdentifier(Drive: Byte; Media: TMediaIdentifier): Boolean;
{ Sets a drive's serial number, volume label, and file system. }
{- Media Type -----------------------------------------------------------------}
type
TMediaType = packed record
DefaultType : ByteBool; { True for the default media type. }
CurrentType : Byte; { See TDeviceParameters.DeviceType. }
end;
function SenseMediaType(Drive: Byte; var Media: TMediaType): Boolean;
{ Returnes the media type for a drive. }
{- Drive Map Info -------------------------------------------------------------}
const
{ Drive map info flags: }
PROT_MODE_LOGICAL_DRIVE = $01; { Protected-mode driver is in use for this }
{ logical drive. }
PROT_MODE_PHYSICAL_DRIVE = $02; { Protected-mode driver is in use for the }
{ physical drive of this logical drive. }
PROT_MODE_ONLY_DRIVE = $04; { Drive is not available when running with }
{ MS-DOS. }
PROT_MODE_EJECT = $08; { Protected-mode drive supports an electronic}
{ eject operation. }
PROT_MODE_ASYNC_NOTIFY = $10; { Drive issues media arrival and removal }
{ notifications. }
type
TDriveMapInfo = packed record
Flags : Byte; { Combination of flags describing the drive. }
Int13Unit : Byte; { Physical drive number of the given drive. }
{ 00-7Fh = floppy disk drive (00 for the first }
{ floppy drive, 01 for the second, and so on). }
{ 80-FEh = hard disk drive (80 for the first }
{ hard disk, 81 for the second, and so on). }
{ FFh = drive does not map to a physical drive.}
AssociatedDriveMap : DWord; { Logical drive numbers associated with the }
{ physical drive. For example, a host drive C }
{ with child drive letters A and B would return}
{ with bits 0 and 1 set. }
PartitionStartRBA : DWord; { 64 bits relative block address offset from }
PartitionStartRBAHi: DWord; { start of the physical volume to start of the }
{ given partition. }
end;
function GetDriveMapInfo(Drive: Byte; var Info: TDriveMapInfo): Boolean;
{ Retrieves maping information about the specified drive. }
{- Parameter Blocks -----------------------------------------------------------}
type
PDPB = ^TDPB;
TDPB = packed record { Drive Parameter Block for FAT12 and FAT16: }
DriveNumber : Byte; { Drive number (0=A, 1=B, and so on). }
UnitNumber : Byte; { Drive unit number on device driver. }
SectorSize : Word; { Size of each sector in bytes. }
ClusterMask : Byte; { Number of sectors per cluster minus 1. }
ClusterShift : Byte; { Number of sectors per cluster as power of 2. }
FirstFAT : Word; { First sector for the File Allocation Table. }
FATCount : Byte; { Number of FATs on the drive. }
RootEntries : Word; { Number of entries in root directory. }
FirstSector : Word; { First sector of the first cluster. }
MaxCluster : Word; { Number of clusters on drive plus 1. }
FATSize : Word; { Number of sectors occupied by each FAT. }
DirSector : Word; { First sector for the root directory. }
Reserved2 : DWord;
MediaID : Byte; { Media descriptor for the drive. }
FirstAccess : Byte; { 00h if disk accessed, FFh if not accessed. }
Reserved3 : DWord;
NextFree : Word; { Most recently allocated cluster. Cluster at }
{ which to start search for free clusters. }
FreeCount : Word; { Number of free clusters on the drive. }
{ FFFF if the number is unknown. }
end;
PExtDPB = ^TExtDPB;
TExtDPB = packed record { Extended Drive Parameter Block for FAT32: }
DriveNumber : Byte; { Drive number (0=A, 1=B, and so on). }
UnitNumber : Byte; { Drive unit number on device driver. }
SectorSize : Word; { Size of each sector in bytes. }
ClusterMask : Byte; { Number of sectors per cluster minus 1. }
ClusterShift : Byte; { Number of sectors per cluster as power of 2. }
FirstFAT : Word; { First sector for the File Allocation Table. }
FATCount : Byte; { Number of FATs on the drive. }
RootEntries : Word; { Number of entries in root directory. }
FirstSector : Word; { First sector of the first cluster. }
MaxCluster : Word; { Number of clusters on drive plus 1. }
{ Field is undefined for FAT32 drives. }
FATSize : Word; { Number of sectors occupied by each FAT. }
{ Zero indicates a FAT32 drive. }
{ Use ExtFATSize for FAT32 media. }
DirSector : Word; { First sector for the root directory. }
{ Field is undefined for FAT32 drives. }
Reserved2 : DWord;
MediaID : Byte; { Media descriptor for the drive. }
Reserved : Byte;
Reserved3 : DWord;
NextFree : Word; { Most recently allocated cluster. Cluster at }
{ which to start search for free clusters. }
ExtFreeCount : DWord; { Number of free clusters on the drive. }
{ FFFFFFFF if the number is unknown. }
ExtFlags : Word; { Flags describing the drive: }
{ bits 0-3: 0-based number of active FAT }
{ bits 4-6: reserved }
{ bit 7: FAT mirroring enabled if bit cleared }
{ bits 8-15: reserved }
ExtFSInfoSec : Word; { Sector containing information about the file }
{ system in TBifFATBootFSInfo structure. }
{ This field is set to 0FFFFh if there is no }
{ FileSysInfo sector. Otherwise, this value }
{ must be non-zero and less than the reserved }
{ sector count. }
ExtBkUpBootSec : Word; { Sector containing the backup boot sector. }
{ This field is set to 0FFFFh if there is no }
{ backup boot sector. Otherwise, this value }
{ must be non-zero and less than the reserved }
{ sector count. }
ExtFirstSector : DWord; { First sector of the first cluster. }
ExtMaxCluster : DWord; { Number of clusters on drive plus 1. }
ExtFATSize : DWord; { Number of sectors occupied by each FAT. }
ExtRootCluster : DWord; { First cluster in the root directory. }
ExtNextFree : DWord; { Most recently allocated cluster. Cluster at }
{ which to start search for free clusters. }
end;
PBPB = ^TBPB;
TBPB = packed record { BIOS Parameter Block for FAT12 and FAT16: }
BytesPerSector : Word; { Number of bytes per sector. }
SectorsPerCluster : Byte; { Number of sectors per cluster. }
ReservedSectors : Word; { Number of reserved sectors. }
NumberOfFATs : Byte; { Number of File Allocation Tables. }
RootDirEntries : Word; { Number of entries in root directory. }
SectorsOnDrive : Word; { Number of sectors on the drive or partition. }
MediaDescriptor : Byte; { Media descriptor. }
SectorsPerFAT : Word; { Number of sectors per FAT. }
SectorsPerTrack : Word; { Number of sectors per track. }
NumberOfHeads : Word; { Number of heads on the drive. }
HiddenSectors : DWord; { Number of hidden sectors on the drive. }
BigSectorsOnDrive : DWord; { Number of sectors if SectorsOnDrive=0. }
end;
PExtBPB = ^TExtBPB;
TExtBPB = packed record { Extended BIOS Parameter Block for FAT32: }
BytesPerSector : Word; { Number of bytes per sector. }
SectorsPerCluster : Byte; { Number of sectors per cluster. }
ReservedSectors : Word; { Number of reserved sectors. }
NumberOfFATs : Byte; { Number of File Allocation Tables. }
RootDirEntries : Word; { Number of entries in root directory. }
{ Ignored on FAT32 drives. }
SectorsOnDrive : Word; { Number of sectorson the drive or partition. }
MediaDescriptor : Byte; { Media descriptor. }
SectorsPerFAT : Word; { Number of sectors per FAT. }
{ This field will be zero in a FAT32 BPB. }
{ Use BigSectorsPerFat for FAT32 media. }
SectorsPerTrack : Word; { Number of sectors per track. }
NumberOfHeads : Word; { Number of heads on the drive. }
HiddenSectors : DWord; { Number of hidden sectors on the drive. }
BigSectorsOnDrive : DWord; { Number of sectors if SectorsOnDrive=0. }
BigSectorsPerFat : DWord; { Number of sectors per FAT on FAT32 drive. }
ExtFlags : Word; { Flags describing the drive: }
{ bits 0-3: 0-based number of active FAT }
{ bits 4-6: reserved }
{ bit 7: FAT mirroring enabled if bit cleared }
{ bits 8-15: reserved }
FileSysVersion : Word; { File system version of the FAT32 drive: }
{ high byte: major version. }
{ low byte: minor version. }
RootDirStartCluster: DWord; { First cluster of root directory on FAT32 }
{ drive. }
FileSysInfoSector : Word; { Sector containing information about the file }
{ system in TBifFATBootFSInfo structure. }
{ This field is set to FFFFh if there is no }
{ FileSysInfo sector. Otherwise, this value }
{ must be non-zero and less than the reserved }
{ sector count. }
BackupBootSector : Word; { Sector containing the backup boot sector. }
{ This field is set to FFFFh if there is no }
{ backup boot sector. Otherwise, this value }
{ must be non-zero and less than the reserved }
{ sector count. }
Reserved : array[0..5] of Word;
end;
PBigFATBootInfo = ^TBigFATBootInfo;
TBigFATBootInfo = packed record
Signature : DWord; { Signature of FileSysInfo sector, 61417272h. }
FreeClustersCount : DWord; { Number of free clusters on drive, }
{ FFFFFFFF if the number is unknown. }
NextFreeCluster : DWord; { Most recently allocated cluster. }
Reserved : array[0..5] of Word;
end;
{- Device Parameters ----------------------------------------------------------}
PSectorEntry = ^TSectorEntry;
TSectorEntry = packed record { Sector entry for SectorTable: }
SectorNumber: Word;
SectorSize : Word;
end;
PDeviceParameters = ^TDeviceParameters;
TDeviceParameters = packed record { Device Parameters for FAT12 and FAT16: }
SpecialFunctions : Byte; { Special functions: }
{ bit 0 set to use current BPB }
{ clear to use BPB in this structure }
{ bit 1 set to use track layout field only }
{ must be clear for get function }
{ bit 2 set if all sectors has the same size }
{ (should be set) }
{ bit 3-7 reserved }
DeviceType : Byte; { Device type: }
{ 00h = 5.25" 320Kb/360Kb disk }
{ 01h = 5.25" 1.2Mb disk }
{ 02h = 3.5" 720Kb disk }
{ 03h = 8" low-density disk }
{ 04h = 8" high-density disk }
{ 05h = hard disk }
{ 06h = tape drive }
{ 07h = 3.5" 1.44Mb disk }
{ 08h = optical disk }
{ 09h = 3.5" 2.88Mb disk }
DeviceAttributes : Word; { Device attributes: }
{ bit 0 set if nonremovable media }
{ bit 1 set if door lock supported }
{ bit 2-15 reserved }
Cylinders : Word; { Number of cylinders }
MediaType : Byte; { Media type: }
{ for 1.2Mb drive: }
{ 00h=1.2Mb disk }
{ 01h=320Kb/360Kb disk }
{ always 00h for other drive types }
BPB : TBPB; { 31 bytes reserved for BPB }
Fill31Bytes : array[1..31-SizeOf(TBPB)] of Byte; { fill up 31 bytes }
EntriesInTable : Word; { Number of entries in SectorTable. Should be }
{ equal to SectorsPerTrack. (Not used by the }
{ get function.) }
SectorTable : array[0..0] of TSectorEntry; { When planing to use a }
{ device parameters structure with calls to set }
{ function, one should allocate memory for this }
{ structure (SizeOf(TDeviceParameters)) + }
{ SizeOf(TSectoryEntry) * SectorsPerTrack. }
end;
PExtDeviceParameters = ^TExtDeviceParameters;
TExtDeviceParameters = packed record { Extended Device Parameters for FAT32: }
SpecialFunctions : Byte; { Special functions: }
{ bit 0 set to use current BPB }
{ clear to use BPB in this structure }
{ bit 1 set to use track layout field only }
{ must be clear for get function }
{ bit 2 set if all sectors has the same size }
{ (should be set) }
{ bit 3-7 reserved }
DeviceType : Byte; { Device type: }
{ 00h = 5.25" 320Kb/360Kb disk }
{ 01h = 5.25" 1.2Mb disk }
{ 02h = 3.5" 720Kb disk }
{ 03h = 8" low-density disk }
{ 04h = 8" high-density disk }
{ 05h = hard disk }
{ 06h = tape drive }
{ 07h = 3.5" 1.44Mb disk }
{ 08h = optical disk }
{ 09h = 3.5" 2.88Mb disk }
DeviceAttributes : Word; { Device attributes: }
{ bit 0 set if nonremovable media }
{ bit 1 set if door lock supported }
{ bit 2-15 reserved }
Cylinders : Word; { Number of cylinders }
MediaType : Byte; { Media type: }
{ for 1.2Mb drive: }
{ 00h=1.2Mb disk }
{ 01h=320Kb/360Kb disk }
{ always 00h for other drive types }
BPB : TExtBPB; { ExtBPB for FAT32 }
Reserved : array[0..31] of Byte;
EntriesInTable : Word; { Number of entries in SectorTable. Should be }
{ equal to SectorsPerTrack. (Not used by the }
{ get function.) }
SectorTable : array[0..0] of TSectorEntry; { When planing to use a }
{ device parameters structure with calls to set }
{ function, one should allocate memory for this }
{ structure (SizeOf(TFAT32DeviceParameters)) + }
{ SizeOf(TSectoryEntry) * SectorsPerTrack. }
end;
function GetDeviceParameters(Drive: Byte; Buffer: Pointer; Size: Word): Boolean;
{ Returnes device parameters for a drive. The device parameters are }
{ returned in the buffer pointet to by Buffer. The buffer should be }
{ able to hold a TExtDeviceParameters structure. The size of the }
{ structure wanted must be given in the Size parameter to identify }
{ for the function which structure (TDeviceParameters or TExtDevice- }
{ Parameters) is wanted on return. If the function failes geting a }
{ FAT32 device parameters structure it will get a FAT12/16 structure }
{ In any case it will convert the structure it gets to the structure }
{ that are wanted in the buffer on return. }
function SetDeviceParameters(Drive: Byte; Buffer: Pointer; Size: Word): Boolean;
{ Sets the device parameters for a drive. The buffer pointed to by }
{ Buffer should hold a correct device parameters structure for the }
{ current file system (FAT12/16 or FAT32). The size of the structure }
{ must be given in the Size parameter to identify for the function }
{ which structure (TDeviceParameters or TExtDeviceParameters) is }
{ pased in the buffer. If the function failes seting a FAT32 device }
{ parameters structure it will convert to a FAT12/16 structure and }
{ try to set that. This will not affect the original structure in }
{ the buffer. }
{ Even though these two functions can take and return either FAT12/16 or FAT32 }
{ device parameter (intentifying the actual structure by the Size parameter) }
{ it will be wise not to use the FAT12/16 structure, but to only implement the }
{ FAT32 structure. For these two functions the FAT32 structure will work fine }
{ on FAT12/16 drives as well as for FAT32. However, the FAT12/16 structure will}
{ not be appropriate for working with FAT32 drives. By usin the FAT32 structure}
{ in any case there will be no need to match the device parameter structure to }
{ the different drives because the functions will temporarily convert a FAT32 }
{ structure to FAT12/16 if needed. }
{- Cylinders, Heads, Sectors --------------------------------------------------}
{ }
{ Sectors are the smallest accessable units on a disk drive, and (usually) are }
{ 512 bytes in size. Sectors are organized on a drive in a matrix of cylinders,}
{ heads, and sectors. The cylinder/head/sector (CHS) values are referred to as }
{ a drive's geometry. Hard disks are made up of several disk plates stacked on }
{ top of each other, with tracks defined as concentric circles on both sides }
{ of each plate. The read/write heads are part of an assembly with one head }
{ for each side of each platter. In the CHS system, cylinder refers to the set }
{ of tracks for all the plates that line up on top of each other, head refers }
{ to a side of a platter, and a sector is a 512 bytes portion of a track. }
{ The cylinders on a drive is numbered from 0 and up, heads are numbered from }
{ 0 and up, and sectors on each track are numbered from 1 and up. }
{ Logical sectors are numbered sequentially from cylinder 0 and up, head 0 and }
{ up. Sector 1 on head 0, cylinder 0 is the first logical sector (sector 0) on }
{ the drive, and sector 2 on the same head and cylinder is the second logical }
{ sector (sector 1). The formula for calculating logical sector numbers are: }
{ Cylinder * (BPB.NumberOfHeads * BPB.SectorsPerTrack) }
{ + Head * BPB.SectorsPerTrack }
{ + Sector - 1 (-1 because logical sectors on a drive are 0-based) }
{- Direct Drive Access --------------------------------------------------------}
{ Windows 95 OSR2 has a bug that affects interrupt 21h function 440Dh code 61h }
{ (read track) and code 41h (write track). The function succeed but no data is }
{ read or written. Both functions work on the retail version of Windows 95. }
{ Solutions: (1) Use interrupt 25h and 26h to read and write logical sectors. }
{ This works on FAT12 and FAT16, but is not compatible with }
{ FAT32. }
{ (2) Use interrupt 21h function 7305h to read and write logical }
{ sectors. This method works on FAT12, FAT16, and FAT32, but }
{ is only supported on Windows 95 OSR2 and later. }
function ReadTrack(Drive: Byte; Cylinder,Head,Sector,Count: Word; Buffer: Pointer): Boolean;
{ Reads Count number of sectors from the drive into the buffer. On }
{ Windows 95 OSR2 this function will return successful but no data }
{ will be read. }
function WriteTrack(Drive: Byte; Cylinder,Head,Sector,Count: Word; Buffer: Pointer): Boolean;
{ Writes Count number of sectors from the buffer onto the drive. On }
{ Windows 95 OSR2 this function will return successful but no data }
{ will be writen. }
function FormatTrack(Drive: Byte; Cylinder,Head: Word): Boolean;
{ Formats and verifies a track on the drive. }
function VerifyTrack(Drive: Byte; Cylinder,Head: Word): Boolean;
{ Verifies a track on the drive. }
const
{ Write modes for WriteSector: }
WRITE_MODE_UNSPECIFIED_DATA = $0000; { Other/unknown }
WRITE_MODE_FAT_DATA = $1000; { FAT data }
WRITE_MODE_DIRECTORY_DATA = $2000; { Directory data }
WRITE_MODE_NORMAL_FILE_DATA = $3000; { Normal file data }
function ReadSector(Drive: Byte; Sector: DWord; Count: Word; Buffer: Pointer): Boolean;
{ Reads Count number of logical sectors from the drive into the }
{ buffer. The Sector parameter gives the sector number (0 beeing the }
{ first sector on a drive) to start reading from. The buffer must be }
{ able to hold BytesPerSector*Count number of bytes. On Windows 95 }
{ OSR2 and later this function uses interrupt 21h function 7305h. }
function WriteSector(Drive: Byte; Sector: DWord; Count: Word; Buffer: Pointer; Mode: Byte): Boolean;
{ Write Count number of logical sectors from the buffer onto the }
{ drive. On Windows 95 OSR2 and later this function uses interrupt }
{ 21h function 7305h. The mode (one of the write modes) is needed in }
{ Windows 95 OSR2 and and later only. This provides information to }
{ applications (like compression drivers) so that they can write }
{ data properly based upon the data type specified. }
{- Master Boot Record ---------------------------------------------------------}
{ The Master Boot Record (MBR) is the first physical sector of a hard disk, }
{ and always contains a partition table. This partition table is 64 bytes long }
{ and is followed by a two-byte signature (55AAh), which indicates the end of }
{ the MBR. The 64-byte partition table and the 2-byte signature occupies the }
{ last 66 bytes of the sector. }
type
PPartitionEntry = ^TPartitionEntry;
TPartitionEntry = packed record
BootIndicator : Byte; { Boot indicator: }
{ 80h = active/bootable }
{ 00h = nonactive/non-bootable }
StartHead : Byte; { Starting head of partition. }
StartCylinderSector: Word; { Starting cylinder and sector of partition: }
{ 10 bits for cylinder, 6 bits for sector. }
{ bits 0-5 6 bits of sector }
{ bits 6-7 2 high bits of cylinder }
{ bits 8-15 8 low bits of cylinder }
{ Partitions usually start on sector 1, head 0, except the first partition }
{ after the master boot record which may start in sector 2. }
PartitionType : Byte; { Partition type (system flag/indicator): }
{ 00h = unused partition table entry }
{ 01h = FAT12 primary partition <16Mb }
{ 02h = XENIX }
{ 04h = FAT16 primary partition 16-32Mb }
{ 05h = FAT12/16 extended partition }
{ 06h = FAT16 primary partition >32Mb }
{ 07h = HPFS, NTFS, Unix, other }
{ 0Ah = OS/2 boot manager }
{ 0Bh = FAT32 }
{ 0Ch = FAT32 LBA (ext int 13h required) }
{ 0Eh = FAT16 LBA (ext int 13h required) }
{ 0Fh = FAT16 LBA ext (ext int 13h required) }
{ 64h = Novell }
{ 75h = PCIX }
{ 83h = Linux EXT2 }
{ A5h = FreeBSD, NetBSD, 386BSD }
{ DBh = CP/M }
{ FFh = BBT }
EndHead : Byte; { Ending head of partition. }
EndCylinderSector : Word; { Ending cylinder and sector of partition: }
{ 10 bits for cylinder, 6 bits for sector. }
SectorOffset : DWord; { Relative sector offset of partition. }
{ (Number of sectors preceding partition.) }
NumberOfSectors : DWord; { Number of sectors in partition. }
end;
PPartitionTable = ^TPartitionTable;
TPartitionTable = array[1..4] of TPartitionEntry;
PMBR = ^TMBR;
TMBR = packed record { Master Boot Record: }
{ The first portion (446 bytes on disks with 512 bytes per sector) of a }
{ master boot record, preceding the partition table and two-byte signature }
{ is occupied by executable bootup code. }
BootCode : array[0..445] of Byte; { Bootup program code. }
PartitionTable : TPartitionTable; { Partition table occupying the last }
{ 64 bytes preceding the two-byte }
{ signature (55h AAh). }
{ The last two bytes in a boot record containes a two-byte signature, and }
{ must always have the values: 55h AAh }
SectorSignature : Word;
end;
{- File System Boot Record ----------------------------------------------------}
PFSBR = ^TFSBR;
TFSBR = packed record { File System Boot Record for FAT12 and FAT16: }
BootJump : array[0..2] of Byte; { Jump instruction to boot code. }
OEMName : array[0..7] of Char; { System that formated the drive.}
BPB : TBPB; { BPB for FAT12 and FAT16. }
PhysicalDrive : Byte; { Number of physical drive. }
Reserved : Byte;
BootSignature : Byte; { Boot record signature, usually 29h. }
VolumeSerial : DWord; { Volume serial number. }
VolumeLabel : array[0..10] of Char; { Volume label. }
SystemType : array[0..7] of Char; { 'FAT12 ' or 'FAT16 ' }
{ The portion of a boot record following the extended BIOS parameter block }
{ (448 bytes on disks with 512 bytes per sector) is occupied by executable }
{ boot code. }
BootCode : array[0..447] of Byte; { Bootup program code. }
{ The last two bytes in a boot record containes a two-byte signature, and }
{ must always have the values: 55h AAh }
SectorSignature : Word;
end;
PExtFSBR = ^TExtFSBR;
TExtFSBR = packed record { Extended File System Boot Record for FAT32: }
BootJump : array[0..2] of Byte; { Jump instruction to boot code. }
OEMName : array[0..7] of Char; { System that formated the drive.}
BPB : TExtBPB; { ExtBPB for FAT32. }
PhysicalDrive : Byte; { Number of physical drive. }
Reserved : Byte;
BootSignature : Byte; { Boot record signature, usually 29h. }
VolumeSerial : DWord; { Volume serial number. }
VolumeLabel : array[0..10] of Char; { Volume label. }
SystemType : array[0..7] of Char; { 'FAT32 ' }
{ The portion of a boot record following the extended BIOS parameter block }
{ (420 bytes on disks with 512 bytes per sector) is occupied by executable }
{ boot code. }
BootCode : array[0..419] of Byte; { Bootup program code. }
{ The last two bytes in any boot record always have the values: 55h AAh. }
SectorSignature : Word;
end;
{- File Allocation Table ------------------------------------------------------}
{ Although sectors are the smallest addressable units on a disk, the data area }
{ (the area used to store files and directories, opposed to the system area }
{ where the boot record and FATs are stored) are organiced into clusters. A }
{ clusters (or allocation units) occupy several sectors grouped together. The }
{ number of sectors for each cluster depends on the partition, and is given in }
{ BPB.SectorsPerCluster. }
{ The File Allocation Table (FAT) is used to map each cluster in the data eara }
{ and will have one entry for each cluster on the drive. Thuse it is possible }
{ to keep track of clusters allocated to each files and directory. The size of }
{ the entries in the FAT depends on the FAT-type: FAT12 uses 12-bit entries, }
{ FAT16 uses 16-bit entries, and FAT32 uses 32-bit entries. Entries in a FAT }
{ are indexed from 0 and up. Because the first two entries are reserved, entry }
{ cluster 2 (index 2 in the FAT) is the first data cluster on a drive. The }
{ first byte in a FAT must always clontain a copy of the media desriptor byte }
{ (BPB.MediaDescriptor), and the remaining bytes for the first and second FAT }
{ entries (index 0 and 1) must be filled with FFh. }
{ Each entry in a FAT is an integer value. The values [FFFF]F]FF0-[FFFF]F]FFF }
{ are reserved. [FFFF]F]FF7 indicates a bad cluster. [FFFF]F]FFF indicates the }
{ end of cluster chain. Values from [FFFF]F]FF8-[FFFF]F]FFFF may also be used }
{ to indicate end of cluster chain. The value [0000]0]000 indicates an unused }
{ cluster. All other value will represent the next cluster in a cluster chain. }
{- Directory Entries ----------------------------------------------------------}
PDirEntry = ^TDirEntry;
TDirEntry = packed record
Name : array[0..7] of Char; { 8 character name. }
{ first byte: 00h = entry never used }
{ 05h = first character of name is E5h }
{ E5h = entry has been deleted }
{ 2Eh = subdirectory entry }
Extention : array[0..2] of Char; { 3 character extention. }
Attributes : Byte; { Bits: 0 = read-only }
{ 1 = hidden }
{ 2 = system }
{ 3 = volume label (Name+Ext=11 label) }
{ 4 = directory }
{ 5 = archive }
Reserved : array[0..9] of Char;
CreationTime : Word; { Bits: 0-4 = seconds/2 (0-29) }
{ 5-10 = minutes (0-59) }
{ 11-15 = hour (0-23) }
CreationDate : Word; { Bits: 0-4 = day (0-31) }
{ 5-8 = month (1-12) }
{ 9-15 = year-1980 }
FirstCluster : Word; { First cluster of the file/directory. }
FileSize : DWord; { Size of a file. }
end;
PLongNameDirEntry = ^TLongNameDirEntry;
TLongNameDirEntry = packed record
Sequence : Byte; { Number in the chain of directory entries for }
{ this name, 01h,02h, ... 4xh (last entry will }
{ have bit 6 set to indicate end of chaine). }
Name : array[0..4] of WideChar; { Charachters for long name. }
Attributes : Byte; { OFh (00001111b) a directory entry has the }
{ attributes read-only, hidden, system, and }
{ volume label set to indicate a long name. }
EntryType : Byte; { 00h }
Checksum : Byte; { Checksum for matching short (DOS) name. }
Name2 : array[0..5] of WideChar; { Charachters for long name. }
Reserved : Word;
Name3 : array[0..1] of WideChar; { Charachters for long name. }
end;
PVolumeLabelDirEntry = ^TVolumeLabelDirEntry;
TVolumeLabelDirEntry = packed record
VolumeLabel : array[0..10] of Char; { 11 character volume label. }
Attributes : Byte; { 00001000b (volume label attribute set) }
Reserved : array[0..9] of Byte;
CreationTime : Word;
CreationDate : Word;
Unused : array[0..5] of Byte;
end;
{------------------------------------------------------------------------------}
function GetFirstCluster(Path: String; var Cluster: DWord): Boolean;
{ Retrives the first cluster of a file or directory. Caller must }
{ a level 3 lock on the drive. It is the callers resposibility to }
{ check that the returned cluster number is valid. }
function MakeSerialNumber: DWord;
{ Generates a volume serial number using the current date and time. }
{ The current system date and time is converted into DOS date and }
{ DOS time, with date in the high word and time in the low word. }
{------------------------------------------------------------------------------}
{ Most functions have a boolean return value to indicate success or failiour. }
{ If a function failes an error code in the variable VWIN32Error, and when it }
{ succedes VWIN32Error will be zero. }
var
VWIN32Error: DWord;
const
ERROR_NON = $0000; { no error }
{ MS-DOS/Windows error codes: }
ERROR_INVALID_FUNCTION = $0001; { invalid function number }
ERROR_FILE_NOT_FOUND = $0002; { file not found }
ERROR_ACCESS_DENIED = $0005; { specified access denied on drive }
ERROR_INVALID_DRIVE = $000F; { invalid drive number }
ERROR_MEDIA_NOT_LOCKED = $00B0; { media is not locked in drive }
ERROR_MEDIA_LOCKED = $00B1; { media is locked in drive }
ERROR_MEDIA_NOT_REMOVABLE = $00B2; { media is not removable }
ERROR_LOCKE_COUNT_EXCEEDED = $00B4; { media locke count exceeded }
ERROR_EJECT_REQUEST_FAILED = $00B5; { valid media eject request failed }
{ Interrupt 13h/25h/26h error codes: }
ERROR_BAD_COMMAND = $10001; { bad command }
ERROR_BAD_ADDRESS_MARK = $10002; { bad address mark }
ERROR_WRITE_PROTECTED = $10003; { write-protected disk }
ERROR_SECTOR_NOT_FOUND = $10004; { requested sector not found }
ERROR_RESET_FAILED = $10005; { reset failed }
ERROR_DISK_CHANGED = $10006; { disk changed (floppy disk) }
ERROR_PARAMETER_FAILED = $10007; { drive parameter activity failed }
ERROR_DMA_FAILURE = $10008; { DMA failure/overrun }
ERROR_DMA_SEGMENT_FAULT = $10009; { attempted DMA across 64K boundary }
ERROR_BAD_SECTOR_DETECTED = $1000A; { bad sector detected }
ERROR_BAD_TRACK_DETECTED = $1000B; { bad track detected }
ERROR_INVALID_MEDIA = $1000C; { invalid media or unsupported track }
ERROR_INVALID_SECTORS = $1000D; { invalid number of sectors on format }
ERROR_CONTROL_DATA = $1000E; { control data address mark detected }
ERROR_DMA_ARBITRATION = $1000F; { DMA arbitration level out of range }
ERROR_DATA_ERROR = $10010; { data error (uncorrectable CRC or ECC) }
ERROR_DATA_ECC_CORRECTED = $10011; { data ECC corrected }
ERROR_CONTROLLER_FAILED = $10020; { controller failed }
ERROR_SEEK_FAILED = $10040; { seek operation failed }
ERROR_DEVICE_FAILED = $10080; { device failed to respond (timeout) }
ERROR_DRIVE_NOT_READY = $100AA; { drive not ready }
ERROR_UNDEFINED = $100BB; { undefined error }
ERROR_WRITE_FAULT = $100CC; { write fault }
ERROR_STATUS_REGISTER = $100E0; { status register error }
ERROR_SENSE_FAILED = $100FF; { sense operation failed }
{ VWIN32 custom error codes: }
ERROR_UNKNOWN = $00100000; { unknown error }
ERROR_OS_NOT_SUPPORTED = $00200000; { OS version not supported }
ERROR_OPENING_DEVICE = $00300000; { error trying to open device }
{==============================================================================}
implementation
var
VWIN32Device : THandle;
OSVersionInfo: TOSVersionInfo;
function VWIN32DIOC;
var
BytesReturned : DWord;
function OpenDevice: Boolean;
begin
VWIN32Error := ERROR_NON;
if VWIN32Device = INVALID_HANDLE_VALUE then begin
if WindowsVersion(0,0,0,VER_PLATFORM_WIN32_WINDOWS) then begin {supports only Win9x}
VWIN32Device := CreateFile(VWIN32_DEVICE_NAME,0,0,nil,0,FILE_FLAG_DELETE_ON_CLOSE,0);
if VWIN32Device = INVALID_HANDLE_VALUE then VWIN32Error := ERROR_OPENING_DEVICE;
end
else VWIN32Error := ERROR_OS_NOT_SUPPORTED;
end;
Result := VWIN32Error = ERROR_NON;
end;
procedure CloseDevice;
begin
if VWIN32Device <> INVALID_HANDLE_VALUE then CloseHandle(VWIN32Device);
VWIN32Device := INVALID_HANDLE_VALUE;
Result := true;
end;
begin
VWIN32Error := ERROR_NON;
if ControlCode = VWIN32_DIOC_CLOSE then CloseDevice
else if OpenDevice then begin
Result := DeviceIoControl(VWIN32Device,ControlCode,Registers,SizeOf(Registers^),
Registers,SizeOf(Registers^),BytesReturned,nil);
if not result then VWIN32Error := ERROR_UNKNOWN;
end
else Result := false;
end;
function WindowsVersion;
begin
with OSVersionInfo do
Result := (dwMajorVersion >= Major) and
(dwMinorVersion >= Minor) and
(Word(dwBuildNumber) >= Word(Build)) and
(dwPlatformID = Platform);
end;
{ The device category pased as parameter to most of the following functions }
{ is used to specifie FAT32, FAT16 or FAT12 drives: 08h = FAT16 or FAT12 drive,}
{ 48h = FAT32, FAT16 or FAT12 drive. The 48h value is supported on Windows 95 }
{ OSR2 and later only. Because function calls may be implemented in the device }
{ driver, the 48h form of a call may fail on FAT16 or FAT12 media. The caller }
{ must fall back on the 08h form if the 48h form call fails. Therefore, the }
{ folowing functions first makes a 48h form call, but only on Windows 95 OSR2 }
{ and later, and then a 08h form call if the 48h form call failed. }
function DriveIsRemovable;
{ int 21h, func 4408h }
{ in AX = 4408h }
{ BL = drive number }
{ out CF set on error }
{ AX = status }
{ out CF clear if successful }
{ AX = 0000h=removable 0001h=fixed }
var
Registers: TDIOC_Registers;
begin
VWIN32Error := ERROR_NON;
Result := false;
with Registers do begin
EAX := $4408;
EBX := Drive;
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
if (Flags and FLAG_CARRY) = 0 then Result := (AX and $0001) = 0
else VWIN32Error := AX;
end;
end;
end;
function DriveIsRemote;
{ int 21h, func 4409h }
{ in AX = 4409h }
{ BL = drive number }
{ out CF set on error }
{ AX = status }
{ out CF clear if successful }
{ DX = device attribute }
var
Registers: TDIOC_Registers;
begin
VWIN32Error := ERROR_NON;
Result := false;
with Registers do begin
EAX := $4409;
EBX := Drive;
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
if (Flags and FLAG_CARRY) = 0 then Result := (DX and $1000) > 0
else VWIN32Error := AX;
end;
end;
end;
function DriveIsSubstitute;
{ int 21h, func 4409h }
{ in AX = 4409h }
{ BL = drive number }
{ out CF set on error }
{ AX = status }
{ out CF clear if successful }
{ DX = device attribute }
var
Registers: TDIOC_Registers;
begin
VWIN32Error := ERROR_NON;
Result := false;
with Registers do begin
EAX := $4409;
EBX := Drive;
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
if (Flags and FLAG_CARRY) = 0 then Result := (DX and $8000) > 0
else VWIN32Error := AX;
end;
end;
end;
function DirectAccessAllowed;
{ int 21h, func 4409h }
{ in AX = 4409h }
{ BL = drive number }
{ out CF set on error }
{ AX = status }
{ out CF clear if successful }
{ DX = device attribute }
var
Registers: TDIOC_Registers;
begin
VWIN32Error := ERROR_NON;
Result := false;
with Registers do begin
EAX := $4409;
EBX := Drive;
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
if (Flags and FLAG_CARRY) = 0 then Result := (DX and $0200) = 0
else VWIN32Error := AX;
end;
end;
end;
type
TParamBlock = packed record
Operation : Byte;
NumLocks : Byte;
end;
function LockRemovableMedia;
{ int 21h, func 440Dh, code 48h }
{ in AX = 440Dh }
{ BL = drive number }
{ CH = device category (08h=FAT16, 48h=FAT32) }
{ CL = 48h }
{ DS:DX -> address of ParamBlock }
{ out CF set on error }
{ AX = status }
{ out CF clear if successful }
{ ParamBlock.NumLocks = number of pending locks }
var
Registers : TDIOC_Registers;
ParamBlock: TParamBlock;
begin
VWIN32Error := ERROR_NON;
Result := false;
ParamBlock.Operation := 0; {locks the volume in the drive}
if Win95OSR2 then with Registers do begin
EAX := $440D;
EBX := Drive;
ECX := $4848;
EDX := DWord(@ParamBlock);
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
if (Flags and FLAG_CARRY) = 0 then Result := true;
end;
if not Result then with Registers do begin
EAX := $440D;
EBX := Drive;
ECX := $0848;
EDX := DWord(@ParamBlock);
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
if (Flags and FLAG_CARRY) = 0 then Result := true
else VWIN32Error := AX;
end;
end;
end;
function UnlockRemovableMedia;
{ int 21h, func 440Dh, code 48h }
{ in AX = 440Dh }
{ BL = drive number }
{ CH = device category (08h=FAT16, 48h=FAT32) }
{ CL = 48h }
{ DS:DX -> address of ParamBlock }
{ out CF set on error }
{ AX = status }
{ out CF clear if successful }
{ ParamBlock.NumLocks = number of pending locks }
var
Registers : TDIOC_Registers;
ParamBlock: TParamBlock;
begin
VWIN32Error := ERROR_NON;
Result := false;
ParamBlock.Operation := 1; {unlocks the volume in the drive}
if Win95OSR2 then with Registers do begin
EAX := $440D;
EBX := Drive;
ECX := $4848;
EDX := DWord(@ParamBlock);
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
if (Flags and FLAG_CARRY) = 0 then Result := true;
end;
if not Result then with Registers do begin
EAX := $440D;
EBX := Drive;
ECX := $0848;
EDX := DWord(@ParamBlock);
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
if (Flags and FLAG_CARRY) = 0 then Result := true
else VWIN32Error := AX;
end;
end;
end;
function GetRemovableMediaLocks;
{ int 21h, func 440Dh, code 48h }
{ in AX = 440Dh }
{ BL = drive number }
{ CH = device category (08h=FAT16, 48h=FAT32) }
{ CL = 48h }
{ DS:DX -> address of ParamBlock }
{ out CF set on error }
{ AX = status }
{ out CF clear if successful }
{ ParamBlock.NumLocks = number of pending locks }
var
Registers : TDIOC_Registers;
ParamBlock: TParamBlock;
begin
VWIN32Error := ERROR_NON;
Result := false;
ParamBlock.Operation := 2; {returns the lock or unlock status}
if Win95OSR2 then with Registers do begin
EAX := $440D;
EBX := Drive;
ECX := $4848;
EDX := DWord(@ParamBlock);
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
if (Flags and FLAG_CARRY) = 0 then Result := true;
end;
if not Result then with Registers do begin
EAX := $440D;
EBX := Drive;
ECX := $0848;
EDX := DWord(@ParamBlock);
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
if (Flags and FLAG_CARRY) = 0 then Result := true
else VWIN32Error := AX;
end;
end;
if Result then Locks := ParamBlock.NumLocks;
end;
function EjectRemovableMedia;
{ int 21h, func 440Dh, code 49h }
{ in AX = 440Dh }
{ BL = drive number }
{ CH = device category (08h=FAT16, 48h=FAT32) }
{ CL = 49h }
{ out CF set on error }
{ AX = status }
{ out CF clear if successful }
var
Registers : TDIOC_Registers;
begin
VWIN32Error := ERROR_NON;
Result := false;
if Win95OSR2 then with Registers do begin
EAX := $440D;
EBX := Drive;
ECX := $4849;
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
if (Flags and FLAG_CARRY) = 0 then Result := true;
end;
if not Result then with Registers do begin
EAX := $440D;
EBX := Drive;
ECX := $0849;
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
if (Flags and FLAG_CARRY) = 0 then Result := true
else VWIN32Error := AX;
end;
end;
end;
type
TAccessFlag = packed record
SpecialFunction: Byte; { must be zero }
AccessFlag : Byte;
end;
function GetAccessFlag;
{ int 21h, func 440Dh, code 67h }
{ in AX = 440Dh }
{ BL = drive number }
{ CH = device category (08h=FAT16, 48h=FAT32) }
{ CL = 67h }
{ DS:DX -> address of buffer }
{ out CF set on error }
{ AX = status }
{ out CF clear if successful }
{ buffer = AccessFlag }
var
Registers : TDIOC_Registers;
AccessFlag: TAccessFlag;
begin
VWIN32Error := ERROR_NON;
Result := false;
if Win95OSR2 then with Registers do begin
EAX := $440D;
EBX := Drive;
ECX := $4867;
AccessFlag.SpecialFunction := 0;
EDX := DWord(@AccessFlag);
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
if (Flags and FLAG_CARRY) = 0 then Result := true;
end;
if not Result then with Registers do begin
EAX := $440D;
EBX := Drive;
ECX := $0867;
AccessFlag.SpecialFunction := 0;
EDX := DWord(@AccessFlag);
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
if (Flags and FLAG_CARRY) = 0 then Result := true
else VWIN32Error := AX;
end;
end;
if Result then Flag := AccessFlag.AccessFlag;
end;
function SetAccessFlag;
{ int 21h, func 440Dh, code 47h }
{ in AX = 440Dh }
{ BL = drive number }
{ CH = device category (08h=FAT16, 48h=FAT32) }
{ CL = 47h }
{ DS:DX -> address of AccessFlag }
{ out CF set on error }
{ AX = status }
{ out CF clear if successful }
var
Registers : TDIOC_Registers;
AccessFlag: TAccessFlag;
begin
VWIN32Error := ERROR_NON;
Result := false;
if Win95OSR2 then with Registers do begin
EAX := $440D;
EBX := Drive;
ECX := $4847;
AccessFlag.SpecialFunction := 0;
AccessFlag.AccessFlag := Flag;
EDX := DWord(@AccessFlag);
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
if (Flags and FLAG_CARRY) = 0 then Result := true;
end;
if not Result then with Registers do begin
EAX := $440D;
EBX := Drive;
ECX := $0847;
AccessFlag.SpecialFunction := 0;
AccessFlag.AccessFlag := Flag;
EDX := DWord(@AccessFlag);
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
if (Flags and FLAG_CARRY) = 0 then Result := true
else VWIN32Error := AX;
end;
end;
end;
function LockLogicalVolume;
{ int 21h, func 440Dh, code 4Ah }
{ in AX = 440Dh }
{ BH = lock level (0..3) }
{ BL = drive number }
{ CH = device category (08h=FAT16, 48h=FAT32) }
{ CL = 4Ah }
{ DX = permisson }
{ out CF set on error }
{ AX = status }
{ out CF clear if successful }
var
Registers: TDIOC_Registers;
begin
VWIN32Error := ERROR_NON;
Result := false;
if Level > 1 then Permission := $00
else Permission := Permission and $07;
if Win95OSR2 then with Registers do begin
EAX := $440D;
EBX := (Level shl 8) or Drive;
ECX := $484A;
EDX := Permission;
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
if (Flags and FLAG_CARRY) = 0 then Result := true;
end;
if not Result then with Registers do begin
EAX := $440D;
EBX := (Level shl 8) or Drive;
ECX := $084A;
EDX := Permission;
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
if (Flags and FLAG_CARRY) = 0 then Result := true
else VWIN32Error := AX;
end;
end;
end;
function LockPhysicalVolume;
{ int 21h, func 440Dh, code 4Bh }
{ in AX = 440Dh }
{ BH = lock level (0..3) }
{ BL = disk number }
{ CH = device category (08h=FAT16, 48h=FAT32) }
{ CL = 4Bh }
{ DX = permisson }
{ out CF set on error }
{ AX = status }
{ out CF clear if successful }
var
Registers: TDIOC_Registers;
begin
VWIN32Error := ERROR_NON;
Result := false;
if Level > 1 then Permission := $00
else Permission := Permission and $07;
if Win95OSR2 then with Registers do begin
EAX := $440D;
EBX := (Level shl 8) or Disk;
ECX := $484B;
EDX := Permission;
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
if (Flags and FLAG_CARRY) = 0 then Result := true;
end;
if not Result then with Registers do begin
EAX := $440D;
EBX := (Level shl 8) or Disk;
ECX := $084B;
EDX := Permission;
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
if (Flags and FLAG_CARRY) = 0 then Result := true
else VWIN32Error := AX;
end;
end;
end;
function UnlockLogicalVolume;
{ int 21h, func 440Dh, code 6Ah }
{ in AX = 440Dh }
{ BL = drive number }
{ CH = device category (08h=FAT16, 48h=FAT32) }
{ CL = 6Ah }
{ out CF set on error }
{ AX = status }
{ out CF clear if successful }
var
Registers: TDIOC_Registers;
begin
VWIN32Error := ERROR_NON;
Result := false;
if Win95OSR2 then with Registers do begin
EAX := $440D;
EBX := Drive;
ECX := $486A;
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
if (Flags and FLAG_CARRY) = 0 then Result := true;
end;
if not Result then with Registers do begin
EAX := $440D;
EBX := Drive;
ECX := $086A;
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
if (Flags and FLAG_CARRY) = 0 then Result := true
else VWIN32Error := AX;
end;
end;
function UnlockPhysicalVolume;
{ int 21h, func 440Dh, code 6Bh }
{ in AX = 440Dh }
{ BL = disk number }
{ CH = device category (08h=FAT16, 48h=FAT32) }
{ CL = 6Bh }
{ out CF set on error }
{ AX = status }
{ out CF clear if successful }
var
Registers: TDIOC_Registers;
begin
VWIN32Error := ERROR_NON;
Result := false;
if Win95OSR2 then with Registers do begin
EAX := $440D;
EBX := Disk;
ECX := $486B;
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
if (Flags and FLAG_CARRY) = 0 then Result := true;
end;
if not Result then with Registers do begin
EAX := $440D;
EBX := Disk;
ECX := $086B;
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
if (Flags and FLAG_CARRY) = 0 then Result := true
else VWIN32Error := AX;
end;
end;
end;
function GetCurrentLockState;
{ int 21h, func 440Dh, code 70h }
{ in AX = 440Dh }
{ BL = drive number }
{ CH = device category (08h=FAT16, 48h=FAT32) }
{ CL = 70h }
{ out CF set on error }
{ AX = status }
{ out CF clear if successful }
{ AX = lock level }
{ CX = lock permission }
var
Registers: TDIOC_Registers;
begin
VWIN32Error := ERROR_NON;
Result := false;
if Win95OSR2 then with Registers do begin
EAX := $440D;
EBX := Drive;
ECX := $4870;
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
if (Flags and FLAG_CARRY) = 0 then Result := true;
end;
if not Result then with Registers do begin
EAX := $440D;
EBX := Drive;
ECX := $0870;
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
if (Flags and FLAG_CARRY) = 0 then Result := true
else VWIN32Error := AX;
end;
end;
if Result then with Registers do begin
Level := AX;
Permission := CX;
end;
end;
function GetLockFlagState;
{ int 21h, func 440Dh, 6Ch }
{ in AX = 440Dh }
{ BL = drive number }
{ CH = device category (08h=FAT16, 48h=FAT32) }
{ CL = 6Ch }
{ out CF set on error }
{ AX = status }
{ out CF clear if successful }
{ AX = flag state }
var
Registers: TDIOC_Registers;
begin
VWIN32Error := ERROR_NON;
Result := false;
if Win95OSR2 then with Registers do begin
EAX := $440D;
EBX := Drive;
ECX := $486C;
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
if (Flags and FLAG_CARRY) = 0 then Result := true;
end;
if not Result then with Registers do begin
EAX := $440D;
EBX := Drive;
ECX := $086C;
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
if (Flags and FLAG_CARRY) = 0 then Result := true
else VWIN32Error := AX;
end;
end;
if Result then with Registers do Flags := AX;
end;
function EnumerateOpenFiles;
{ int 21h, func 440Dh, code 6Dh }
{ in AX = 440Dh }
{ BL = drive number }
{ CH = device category (08h=FAT16, 48h=FAT32) }
{ CL = 6Dh }
{ DS:DX -> address of buffer }
{ SI = file index }
{ DI = enumeraton type (0=all, 1=unmovable) }
{ out CF set on error }
{ AX = status }
{ out CF clear if successful }
{ AX = open mode }
{ CX = file type }
{ buffer = file path }
var
Registers : TDIOC_Registers;
PathBuffer: PChar;
begin
VWIN32Error := ERROR_NON;
Result := false;
GetMem(PathBuffer,MAX_PATH);
if Win95OSR2 then with Registers do begin
EAX := $440D;
EBX := Drive;
ECX := $486D;
EDX := DWord(PathBuffer);
ESI := FileIndex;
EDI := 0;
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
if (Flags and FLAG_CARRY) = 0 then Result := true;
end;
if not Result then with Registers do begin
EAX := $440D;
EBX := Drive;
ECX := $086D;
EDX := DWord(PathBuffer);
ESI := FileIndex;
EDI := 0;
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
if (Flags and FLAG_CARRY) = 0 then Result := true
else VWIN32Error := AX;
end;
end;
if Result then with Registers do begin
FilePath := PathBuffer;
OpenMode := AX;
FileType := CX;
end;
FreeMem(PathBuffer,MAX_PATH);
end;
function FindSwapFile;
{ int 21h, func 440Dh, code 6Eh }
{ in AX = 440Dh }
{ CH = device category (08h=FAT16, 48h=FAT32) }
{ CL = 6Eh }
{ DS:DX -> address of buffer }
{ out CF set on error }
{ AX = status }
{ out CF clear if successful }
{ AX = pager type }
{ CX:BX = file size (in 4Kb pages) }
{ buffer = file path }
var
Registers : TDIOC_Registers;
PathBuffer: PChar;
begin
VWIN32Error := ERROR_NON;
Result := false;
GetMem(PathBuffer,MAX_PATH);
if Win95OSR2 then with Registers do begin
EAX := $440D;
ECX := $486E;
EDX := DWord(PathBuffer);
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
if (Flags and FLAG_CARRY) = 0 then Result := true;
end;
if not Result then with Registers do begin
EAX := $440D;
ECX := $086E;
EDX := DWord(PathBuffer);
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
if (Flags and FLAG_CARRY) = 0 then Result := true
else VWIN32Error := AX;
end;
end;
if Result then with Registers do begin
FilePath := PathBuffer;
PagerType := AX;
PageCount := (CX shl 16) or BX;
end;
FreeMem(PathBuffer,MAX_PATH);
end;
{function ResetDrive;}
{ don't know how to perform this interrupt in Win9x }
{ int 21h, func 710Dh }
{ in AX = 710Dh }
{ CX = flag }
{ DX = drive number }
function GetMediaIdentifier;
{ int 21h, func 440Dh, code 66h }
{ in AX = 440Dh }
{ BL = drive number }
{ CH = device category (08h=FAT16, 48h=FAT32) }
{ CL = 66h }
{ DS:DX -> address of buffer }
{ out CF set on error }
{ AX = status }
{ out CF clear if successful }
{ buffer = MediaIdentifier }
var
Registers: TDIOC_Registers;
begin
VWIN32Error := ERROR_NON;
Result := false;
if Win95OSR2 then with Registers do begin
EAX := $440D;
EBX := Drive;
ECX := $4866;
EDX := DWord(@Media);
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
if (Flags and FLAG_CARRY) = 0 then Result := true;
end;
if not Result then with Registers do begin
EAX := $440D;
EBX := Drive;
ECX := $0866;
EDX := DWord(@Media);
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
if (Flags and FLAG_CARRY) = 0 then Result := true
else VWIN32Error := AX;
end;
end;
end;
function SetMediaIdentifier;
{ int 21h, func 440Dh, code 46h }
{ in AX = 440Dh }
{ BL = drive number }
{ CH = device category (08h=FAT16, 48h=FAT32) }
{ CL = 46h }
{ DS:DX -> address of MediaIdentifier }
{ out CF set on error }
{ AX = status }
{ out CF clear if successful }
var
Registers: TDIOC_Registers;
begin
VWIN32Error := ERROR_NON;
Result := false;
if Win95OSR2 then with Registers do begin
EAX := $440D;
EBX := Drive;
ECX := $4846;
Media.InfoLevel := 0;
EDX := DWord(@Media);
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
if (Flags and FLAG_CARRY) = 0 then Result := true;
end;
if not Result then with Registers do begin
EAX := $440D;
EBX := Drive;
ECX := $0846;
Media.InfoLevel := 0;
EDX := DWord(@Media);
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
if (Flags and FLAG_CARRY) = 0 then Result := true
else VWIN32Error := AX;
end;
end;
end;
function SenseMediaType;
{ int 21h, func 440Dh, code 68h }
{ in AX = 440Dh }
{ BL = drive number }
{ CH = device category (08h=FAT16, 48h=FAT32) }
{ CL = 68h }
{ DS:DX -> address of MediaIdentifier }
{ out CF set on error }
{ AX = status }
{ out CF clear if successful }
var
Registers: TDIOC_Registers;
begin
VWIN32Error := ERROR_NON;
Result := false;
if Win95OSR2 then with Registers do begin
EAX := $440D;
EBX := Drive;
ECX := $4868;
EDX := DWord(@Media);
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
if (Flags and FLAG_CARRY) = 0 then Result := true;
end;
if not Result then with Registers do begin
EAX := $440D;
EBX := Drive;
ECX := $0868;
EDX := DWord(@Media);
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
if (Flags and FLAG_CARRY) = 0 then Result := true
else VWIN32Error := AX;
end;
end;
end;
type
TDriveMapInfoBuffer = packed record
AllocationLength : Byte; { length of this structure upon call }
InfoLength : Byte; { number of bytes used in the structure }
DriveMapInfo : TDriveMapInfo;
end;
function GetDriveMapInfo;
{ int 21h, func 440Dh, code 6Fh }
{ in AX = 440Dh }
{ BL = drive number }
{ CH = device category (08h=FAT16, 48h=FAT32) }
{ CL = 6Fh }
{ DS:DX -> address of buffer }
{ out CF set on error }
{ AX = status }
{ out CF clear if successful }
{ buffer = DriveMapInfo }
var
Registers: TDIOC_Registers;
Buffer : TDriveMapInfoBuffer;
begin
VWIN32Error := ERROR_NON;
Result := false;
if Win95OSR2 then with Registers do begin
EAX := $440D;
EBX := Drive;
ECX := $486F;
Buffer.AllocationLength := SizeOf(TDriveMapInfoBuffer);
EDX := DWord(@Buffer);
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
if (Flags and FLAG_CARRY) = 0 then Result := true;
end;
if not Result then with Registers do begin
EAX := $440D;
EBX := Drive;
ECX := $086F;
Buffer.AllocationLength := SizeOf(TDriveMapInfoBuffer);
EDX := DWord(@Buffer);
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
if (Flags and FLAG_CARRY) = 0 then Result := true
else VWIN32Error := AX;
end;
end;
if Result then Info := Buffer.DriveMapInfo;
end;
function GetDeviceParameters;
{ int 21h, func 440Dh, code 60h }
{ in AX = 440Dh }
{ BL = drive number }
{ CH = device category (08h=FAT16, 48h=FAT32) }
{ CL = 60h }
{ DS:DX -> address of buffer }
{ out CF set on error }
{ AX = status }
{ out CF clear if successful }
{ buffer = DeviceParameters }
var
Registers : TDIOC_Registers;
TmpDevPar : PDeviceParameters;
TmpExtDevPar: PExtDeviceParameters;
begin
VWIN32Error := ERROR_NON;
Result := false;
if Win95OSR2 then with Registers do begin
TmpExtDevPar := nil;
EAX := $440D;
EBX := Drive;
ECX := $4860;
if Size = SizeOf(TExtDeviceParameters) then EDX := DWord(Buffer)
else begin
GetMem(TmpExtDevPar,SizeOf(TExtDeviceParameters));
EDX := DWord(TmpExtDevPar)
end;
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
if (Flags and FLAG_CARRY) = 0 then begin
Result := true;
if Size = SizeOf(TDeviceParameters) then begin
PDeviceParameters(Buffer)^ := PDeviceParameters(TmpExtDevPar)^;
with PDeviceParameters(Buffer)^ do begin
FillChar(Fill31Bytes,SizeOf(Fill31Bytes),0);
EntriesInTable := 0;
end;
ReallocMem(TmpExtDevPar,0);
end;
end;
end;
if not Result then with Registers do begin
TmpDevPar := nil;
EAX := $440D;
EBX := Drive;
ECX := $0860;
if Size = SizeOf(TDeviceParameters) then EDX := DWord(Buffer)
else begin
GetMem(TmpDevPar,SizeOf(TExtDeviceParameters));
EDX := DWord(TmpDevPar)
end;
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
if (Flags and FLAG_CARRY) = 0 then begin
Result := true;
if Size = SizeOf(TExtDeviceParameters) then begin
PDeviceParameters(Buffer)^ := PDeviceParameters(TmpDevPar)^;
with PExtDeviceParameters(Buffer)^ do begin
BPB.BigSectorsPerFat := 0;
BPB.ExtFlags := 0;
BPB.FileSysVersion := 0;
BPB.RootDirStartCluster := 0;
BPB.FileSysInfoSector := $FFFF;
BPB.BackupBootSector := $FFFF;
FillChar(BPB.Reserved,SizeOf(BPB.Reserved),0);
FillChar(Reserved,SizeOf(Reserved),0);
end;
ReallocMem(TmpDevPar,0);
end;
end
else VWIN32Error := AX;
end;
end;
end;
function SetDeviceParameters;
{ int 21h, func 440Dh, code 40h }
{ in AX = 440Dh }
{ BL = drive number }
{ CH = device category (08h=FAT16, 48h=FAT32) }
{ CL = 40h }
{ DS:DX -> address of DeviceParameters }
{ out CF set on error }
{ AX = status }
{ out CF clear if successful }
var
Registers : TDIOC_Registers;
TmpDevPar : PDeviceParameters;
TmpExtDevPar: PExtDeviceParameters;
begin
VWIN32Error := ERROR_NON;
Result := false;
if Win95OSR2 and (Size = SizeOf(TExtDeviceParameters)) then with Registers do begin
TmpExtDevPar := nil;
EAX := $440D;
EBX := Drive;
ECX := $4840;
if Size = SizeOf(TExtDeviceParameters) then EDX := DWord(Buffer)
else begin
GetMem(TmpExtDevPar,SizeOf(TExtDeviceParameters)
+SizeOf(TSectorEntry)*PExtDeviceParameters(Buffer)^.EntriesInTable);
PDeviceParameters(TmpExtDevPar)^ := PDeviceParameters(Buffer)^;
with TmpExtDevPar^ do begin
BPB.BigSectorsPerFat := 0;
BPB.ExtFlags := 0;
BPB.FileSysVersion := 0;
BPB.RootDirStartCluster := 0;
BPB.FileSysInfoSector := $FFFF;
BPB.BackupBootSector := $FFFF;
FillChar(BPB.Reserved,SizeOf(BPB.Reserved),0);
FillChar(Reserved,SizeOf(Reserved),0);
end;
with PDeviceParameters(Buffer)^ do begin
TmpExtDevPar^.EntriesInTable := EntriesInTable;
CopyMemory(@TmpExtDevPar^.SectorTable,
@SectorTable,EntriesInTable*SizeOf(TSectorEntry));
end;
EDX := DWord(TmpExtDevPar);
end;
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
if (Flags and FLAG_CARRY) = 0 then Result := true;
if TmpExtDevPar <> nil then ReallocMem(TmpExtDevPar,0);
end;
if not Result then with Registers do begin
TmpDevPar := nil;
EAX := $440D;
EBX := Drive;
ECX := $0840;
if Size = SizeOf(TDeviceParameters) then EDX := DWord(Buffer)
else begin
GetMem(TmpDevPar,SizeOf(TExtDeviceParameters)
+SizeOf(TSectorEntry)*PExtDeviceParameters(Buffer)^.EntriesInTable);
PDeviceParameters(TmpDevPar)^ := PDeviceParameters(Buffer)^;
with PExtDeviceParameters(Buffer)^ do begin
TmpDevPar^.EntriesInTable := EntriesInTable;
CopyMemory(@TmpDevPar^.SectorTable,
@SectorTable,EntriesInTable*SizeOf(TSectorEntry));
end;
EDX := DWord(TmpDevPar);
end;
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
if (Flags and FLAG_CARRY) = 0 then Result := true
else VWIN32Error := AX;
end;
if TmpDevPar <> nil then ReallocMem(TmpDevPar,0);
end;
end;
type
TReadWriteBlock = packed record
SpecFunc : Byte; { must be zero }
Head : Word;
Cylinder : Word;
FirstSector: Word;
Sectors : Word;
Buffer : Pointer;
end;
function ReadTrack;
{ int 21h, func 440Dh, code 61h }
{ in AX = 440Dh }
{ BL = drive number }
{ CH = device category (08h=FAT16, 48h=FAT32) }
{ CL = 61h }
{ DS:DX -> address of ReadWriteBlock }
{ out CF set on error }
{ AX = status }
{ out CF clear if successful }
var
Registers : TDIOC_Registers;
ReadWriteBlock: TReadWriteBlock;
begin
VWIN32Error := ERROR_NON;
Result := false;
if Win95OSR2 then with Registers do begin
EAX := $440D;
EBX := Drive;
ECX := $4861;
ReadWriteBlock.SpecFunc := 0;
ReadWriteBlock.Head := Head;
ReadWriteBlock.Cylinder := Cylinder;
ReadWriteBlock.Firstsector := Sector;
ReadWriteBlock.Sectors := Count;
ReadWriteBlock.Buffer := Buffer;
EDX := DWord(@ReadWriteBlock);
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
if (Flags and FLAG_CARRY) = 0 then Result := true;
end;
if not Result then with Registers do begin
EAX := $440D;
EBX := Drive;
ECX := $0861;
ReadWriteBlock.SpecFunc := 0;
ReadWriteBlock.Head := Head;
ReadWriteBlock.Cylinder := Cylinder;
ReadWriteBlock.Firstsector := Sector;
ReadWriteBlock.Sectors := Count;
ReadWriteBlock.Buffer := Buffer;
EDX := DWord(@ReadWriteBlock);
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
if (Flags and FLAG_CARRY) = 0 then Result := true
else VWIN32Error := AX;
end;
end;
end;
function WriteTrack;
{ int 21h, func 440Dh, code 41h }
{ in AX = 440Dh }
{ BL = drive number }
{ CH = device category (08h=FAT16, 48h=FAT32) }
{ CL = 41h }
{ DS:DX -> address of ReadWriteBlock }
{ out CF set on error }
{ AX = status }
{ out CF clear if successful }
var
Registers : TDIOC_Registers;
ReadWriteBlock: TReadWriteBlock;
begin
VWIN32Error := ERROR_NON;
Result := false;
if Win95OSR2 then with Registers do begin
EAX := $440D;
EBX := Drive;
ECX := $4841;
ReadWriteBlock.SpecFunc := 0;
ReadWriteBlock.Head := Head;
ReadWriteBlock.Cylinder := Cylinder;
ReadWriteBlock.Firstsector := Sector;
ReadWriteBlock.Sectors := Count;
ReadWriteBlock.Buffer := Buffer;
EDX := DWord(@ReadWriteBlock);
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
if (Flags and FLAG_CARRY) = 0 then Result := true;
end;
if not Result then with Registers do begin
EAX := $440D;
EBX := Drive;
ECX := $0841;
ReadWriteBlock.SpecFunc := 0;
ReadWriteBlock.Head := Head;
ReadWriteBlock.Cylinder := Cylinder;
ReadWriteBlock.Firstsector := Sector;
ReadWriteBlock.Sectors := Count;
ReadWriteBlock.Buffer := Buffer;
EDX := DWord(@ReadWriteBlock);
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
if (Flags and FLAG_CARRY) = 0 then Result := true
else VWIN32Error := AX;
end;
end;
end;
type
TFormatVerifyBlock = packed record
SpecFunc: Byte;
Head : Word;
Cylinder: Word;
Tracks : Word;
end;
function FormatTrack;
{ int 21h, func 440Dh, code 42h }
{ in AX = 440Dh }
{ BL = drive number }
{ CH = device category (08h=FAT16, 48h=FAT32) }
{ CL = 42h }
{ DS:DX -> address of FormatVerifyBlock }
{ out CF set on error }
{ AX = status }
{ out CF clear if successful }
var
Registers : TDIOC_Registers;
FormatVerifyBlock: TFormatVerifyBlock;
begin
VWIN32Error := ERROR_NON;
Result := false;
if Win95OSR2 then with Registers do begin
EAX := $440D;
EBX := Drive;
ECX := $4842;
FormatVerifyBlock.SpecFunc := 0;
FormatVerifyBlock.Head := Head;
FormatVerifyBlock.Cylinder := Cylinder;
FormatVerifyBlock.Tracks := 1;
EDX := DWord(@FormatVerifyBlock);
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
if (Flags and FLAG_CARRY) = 0 then Result := true;
end;
if not Result then with Registers do begin
EAX := $440D;
EBX := Drive;
ECX := $0842;
FormatVerifyBlock.SpecFunc := 0;
FormatVerifyBlock.Head := Head;
FormatVerifyBlock.Cylinder := Cylinder;
FormatVerifyBlock.Tracks := 1;
EDX := DWord(@FormatVerifyBlock);
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
if (Flags and FLAG_CARRY) = 0 then Result := true
else VWIN32Error := AX;
end;
end;
end;
function VerifyTrack;
{ int 21h, func 440Dh, code 62h }
{ in AX = 440Dh }
{ BL = drive number }
{ CH = device category (08h=FAT16, 48h=FAT32) }
{ CL = 62h }
{ DS:DX -> address of FormatVerifyBlock }
{ out CF set on error }
{ AX = status }
{ out CF clear if successful }
var
Registers : TDIOC_Registers;
FormatVerifyBlock: TFormatVerifyBlock;
begin
VWIN32Error := ERROR_NON;
Result := false;
if Win95OSR2 then with Registers do begin
EAX := $440D;
EBX := Drive;
ECX := $4862;
FormatVerifyBlock.SpecFunc := 0;
FormatVerifyBlock.Head := Head;
FormatVerifyBlock.Cylinder := Cylinder;
FormatVerifyBlock.Tracks := 1;
EDX := DWord(@FormatVerifyBlock);
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
if (Flags and FLAG_CARRY) = 0 then Result := true;
end;
if not Result then with Registers do begin
EAX := $440D;
EBX := Drive;
ECX := $0862;
FormatVerifyBlock.SpecFunc := 0;
FormatVerifyBlock.Head := Head;
FormatVerifyBlock.Cylinder := Cylinder;
FormatVerifyBlock.Tracks := 1;
EDX := DWord(@FormatVerifyBlock);
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
if (Flags and FLAG_CARRY) = 0 then Result := true
else VWIN32Error := AX;
end;
end;
end;
type
TReadWritePacket = packed record
StartSector: DWord;
Sectors : Word;
Buffer : Pointer;
end;
function ReadSector;
{ int 21h, func 7305h }
{ in AX = 7305h }
{ DS:BX -> address of ReadWritePacket }
{ CX = must be -1 (FFFFh) }
{ DL = drive number }
{ SI = 0000h (read) }
{ out CF set on error }
{ AX = status }
{ out CF clear if successful }
{ }
{ int 25h }
{ in AL = drive number (0-based) }
{ DS:BX -> address of ReadWritePacket }
{ CX = FFFFh (large hard disk partition) }
{ out CF set on error }
{ AX = status }
{ out CF clear if successful }
var
Registers : TDIOC_Registers;
ReadWritePacket: TReadWritePacket;
begin
VWIN32Error := ERROR_NON;
Result := false;
if Win95OSR2 then with Registers do begin
EAX := $7305;
ReadWritePacket.StartSector := Sector;
ReadWritePacket.Sectors := Count;
ReadWritePacket.Buffer := Buffer;
EBX := DWord(@ReadWritePacket);
ECX := $FFFFFFFF;
EDX := Drive;
ESI := $0000;
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_DRIVEINFO,@Registers) then
if (Flags and FLAG_CARRY) = 0 then Result := true;
end;
if not Result then with Registers do begin
EAX := Drive-1;
ReadWritePacket.StartSector := Sector;
ReadWritePacket.Sectors := Count;
ReadWritePacket.Buffer := Buffer;
EBX := DWord(@ReadWritePacket);
ECX := $FFFFFFFF;
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_INT25,@Registers) then begin
if (Flags and FLAG_CARRY) = 0 then Result := true
else VWIN32Error := $10000 or (AX and $00FF);
end;
end;
end;
function WriteSector;
{ int 21h, func 7305h }
{ in AX = 7305h }
{ DS:BX -> address of ReadWritePacket }
{ CX = must be -1 (FFFFh) }
{ DL = drive number }
{ SI = 0001h (write) or write mode }
{ out CF set on error }
{ AX = status }
{ out CF clear if successful }
{ }
{ int 26h }
{ in AL = drive number (0-based) }
{ DS:BX -> address of ReadWritePacket }
{ CX = FFFFh (large hard disk partition) }
{ out CF set on error }
{ AX = status }
{ out CF clear if successful }
var
Registers : TDIOC_Registers;
ReadWritePacket: TReadWritePacket;
begin
VWIN32Error := ERROR_NON;
Result := false;
if Win95OSR2 then with Registers do begin
EAX := $7305;
ReadWritePacket.StartSector := Sector;
ReadWritePacket.Sectors := Count;
ReadWritePacket.Buffer := Buffer;
EBX := DWord(@ReadWritePacket);
ECX := $FFFFFFFF;
EDX := Drive;
ESI := $0001 or (Mode and $6000);
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_DRIVEINFO,@Registers) then
if (Flags and FLAG_CARRY) = 0 then Result := true;
end;
if not Result then with Registers do begin
EAX := Drive-1;
ReadWritePacket.StartSector := Sector;
ReadWritePacket.Sectors := Count;
ReadWritePacket.Buffer := Buffer;
EBX := DWord(@ReadWritePacket);
ECX := $FFFFFFFF;
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_INT26,@Registers) then begin
if (Flags and FLAG_CARRY) = 0 then Result := true
else VWIN32Error := $10000 or (AX and $00FF);
end;
end;
end;
function GetFirstCluster;
{ int 21h, func 440Dh, code 71h }
{ in AX = 440Dh }
{ BX = character set (0=ANSI, 1=OEM, 2=UNICODE) }
{ CH = device category (08h=FAT16, 48h=FAT32) }
{ CL = 71h }
{ DS:DX -> address of path }
{ out CF set on error }
{ AX = status }
{ out CF clear if successful }
{ DX:AX = cluster number }
var
Registers: TDIOC_Registers;
begin
VWIN32Error := ERROR_NON;
Result := false;
if Win95OSR2 then with Registers do begin
EAX := $440D;
EBX := 0;
ECX := $4871;
EDX := DWord(PChar(Path));
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
if (Flags and FLAG_CARRY) = 0 then Result := true;
end;
if not Result then with Registers do begin
EAX := $440D;
EBX := 0;
ECX := $0871;
EDX := DWord(PChar(Path));
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
if (Flags and FLAG_CARRY) = 0 then Result := true
else VWIN32Error := AX;
end;
end;
if Result then with Registers do Cluster := EAX;
{?: if Result then with Registers do Cluster := (DX shl 16) or AX;}
end;
function MakeSerialNumber;
var
SystemTime: TSystemTime;
FileTime : TFileTime;
DateTime : array[0..1] of Word;
begin
GetSystemTime(SystemTime);
SystemTimeToFileTime(SystemTime,FileTime);
FileTimeToDosDateTime(FileTime,DateTime[1],DateTime[0]);
Result := DWord(DateTime);
end;
{==============================================================================}
Initialization
VWIN32Error := ERROR_NON;
VWIN32Device := INVALID_HANDLE_VALUE;
OSVersionInfo.dwOSVersionInfoSize := SizeOf(OSVersionInfo);
GetVersionEx(OSVersionInfo);
Win95OSR2 := WindowsVersion(0,0,1081,VER_PLATFORM_WIN32_WINDOWS);
finalization
VWIN32DIOC(VWIN32_DIOC_CLOSE,nil);
end.