2025-05-12 10:07:51 +03:00

962 lines
50 KiB
ObjectPascal

unit Ioctl;
interface
uses
Windows;
type
USHORT = Word;
DEVICE_TYPE = ULONG;
//=============================================================
// Define the various device type values.
// Note that values used by Microsoft Corporation are in the range 0-32767,
// and 32768-65535 are reserved for use by customers.
const
MAX_IDE_DRIVES = 8;
NUM_ATTRIBUTE_STRUCTS = 30;
FILE_DEVICE_BEEP = $00000001;
FILE_DEVICE_CD_ROM = $00000002;
FILE_DEVICE_CD_ROM_FILE_SYSTEM = $00000003;
FILE_DEVICE_CONTROLLER = $00000004;
FILE_DEVICE_DATALINK = $00000005;
FILE_DEVICE_DFS = $00000006;
FILE_DEVICE_DISK = $00000007;
FILE_DEVICE_DISK_FILE_SYSTEM = $00000008;
FILE_DEVICE_FILE_SYSTEM = $00000009;
FILE_DEVICE_INPORT_PORT = $0000000a;
FILE_DEVICE_KEYBOARD = $0000000b;
FILE_DEVICE_MAILSLOT = $0000000c;
FILE_DEVICE_MIDI_IN = $0000000d;
FILE_DEVICE_MIDI_OUT = $0000000e;
FILE_DEVICE_MOUSE = $0000000f;
FILE_DEVICE_MULTI_UNC_PROVIDER = $00000010;
FILE_DEVICE_NAMED_PIPE = $00000011;
FILE_DEVICE_NETWORK = $00000012;
FILE_DEVICE_NETWORK_BROWSER = $00000013;
FILE_DEVICE_NETWORK_FILE_SYSTEM = $00000014;
FILE_DEVICE_NULL = $00000015;
FILE_DEVICE_PARALLEL_PORT = $00000016;
FILE_DEVICE_PHYSICAL_NETCARD = $00000017;
FILE_DEVICE_PRINTER = $00000018;
FILE_DEVICE_SCANNER = $00000019;
FILE_DEVICE_SERIAL_MOUSE_PORT = $0000001a;
FILE_DEVICE_SERIAL_PORT = $0000001b;
FILE_DEVICE_SCREEN = $0000001c;
FILE_DEVICE_SOUND = $0000001d;
FILE_DEVICE_STREAMS = $0000001e;
FILE_DEVICE_TAPE = $0000001f;
FILE_DEVICE_TAPE_FILE_SYSTEM = $00000020;
FILE_DEVICE_TRANSPORT = $00000021;
FILE_DEVICE_UNKNOWN = $00000022;
FILE_DEVICE_VIDEO = $00000023;
FILE_DEVICE_VIRTUAL_DISK = $00000024;
FILE_DEVICE_WAVE_IN = $00000025;
FILE_DEVICE_WAVE_OUT = $00000026;
FILE_DEVICE_8042_PORT = $00000027;
FILE_DEVICE_NETWORK_REDIRECTOR = $00000028;
FILE_DEVICE_BATTERY = $00000029;
FILE_DEVICE_BUS_EXTENDER = $0000002a;
FILE_DEVICE_MODEM = $0000002b;
FILE_DEVICE_VDM = $0000002c;
FILE_DEVICE_MASS_STORAGE = $0000002d;
FILE_DEVICE_SMB = $0000002e;
FILE_DEVICE_KS = $0000002f;
FILE_DEVICE_CHANGER = $00000030;
FILE_DEVICE_SMARTCARD = $00000031;
FILE_DEVICE_ACPI = $00000032;
FILE_DEVICE_DVD = $00000033;
FILE_DEVICE_FULLSCREEN_VIDEO = $00000034;
FILE_DEVICE_DFS_FILE_SYSTEM = $00000035;
FILE_DEVICE_DFS_VOLUME = $00000036;
FILE_DEVICE_SERENUM = $00000037;
FILE_DEVICE_TERMSRV = $00000038;
FILE_DEVICE_KSEC = $00000039;
const
READ_ATTRIBUTE_BUFFER_SIZE = 512;
IDENTIFY_BUFFER_SIZE = 512;
READ_THRESHOLD_BUFFER_SIZE = 512;
const
// SMART IOCTL commands
DFP_GET_VERSION = $00074080;
DFP_SEND_DRIVE_COMMAND = $0007c084;
DFP_RECEIVE_DRIVE_DATA = $0007c088;
const
IOCTL_STORAGE_BASE = FILE_DEVICE_MASS_STORAGE;
IOCTL_SCSI_BASE = FILE_DEVICE_CONTROLLER;
// Define the method codes for how buffers are passed for I/O and FS controls
METHOD_BUFFERED = 0;
METHOD_IN_DIRECT = 1;
METHOD_OUT_DIRECT = 2;
METHOD_NEITHER = 3;
// Define the access check value for any access
FILE_ANY_ACCESS = 0;
FILE_SPECIAL_ACCESS = FILE_ANY_ACCESS;
FILE_READ_ACCESS = $0001; // file & pipe
FILE_WRITE_ACCESS = $0002; // file & pipe
//#define IOCTL_STORAGE_GET_MEDIA_TYPES CTL_CODE(IOCTL_STORAGE_BASE, 0x0300, METHOD_BUFFERED, FILE_ANY_ACCESS)
IOCTL_STORAGE_GET_MEDIA_TYPES = (IOCTL_STORAGE_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0300 shl 2) or (METHOD_BUFFERED);
//#define IOCTL_STORAGE_GET_MEDIA_TYPES_EX CTL_CODE(IOCTL_STORAGE_BASE, 0x0301, METHOD_BUFFERED, FILE_ANY_ACCESS)
IOCTL_STORAGE_GET_MEDIA_TYPES_EX = (IOCTL_STORAGE_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0301 shl 2) or (METHOD_BUFFERED);
//#define IOCTL_STORAGE_GET_DEVICE_NUMBER CTL_CODE(IOCTL_STORAGE_BASE, 0x0420, METHOD_BUFFERED, FILE_ANY_ACCESS)
IOCTL_STORAGE_GET_DEVICE_NUMBER = (IOCTL_STORAGE_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0420 shl 2) or (METHOD_BUFFERED);
//#define IOCTL_SCSI_PASS_THROUGH CTL_CODE(IOCTL_SCSI_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
IOCTL_SCSI_PASS_THROUGH = (IOCTL_SCSI_BASE shl 16) or ((FILE_READ_ACCESS or FILE_WRITE_ACCESS) shl 14) or ($0401 shl 2) or (METHOD_BUFFERED);
//#define IOCTL_SCSI_MINIPORT CTL_CODE(IOCTL_SCSI_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
IOCTL_SCSI_MINIPORT = (IOCTL_SCSI_BASE shl 16) or ((FILE_READ_ACCESS or FILE_WRITE_ACCESS) shl 14) or ($0402 shl 2) or (METHOD_BUFFERED);
//#define IOCTL_SCSI_GET_INQUIRY_DATA CTL_CODE(IOCTL_SCSI_BASE, 0x0403, METHOD_BUFFERED, FILE_ANY_ACCESS)
IOCTL_SCSI_GET_INQUIRY_DATA = (IOCTL_SCSI_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0403 shl 2) or (METHOD_BUFFERED);
//#define IOCTL_SCSI_GET_CAPABILITIES CTL_CODE(IOCTL_SCSI_BASE, 0x0404, METHOD_BUFFERED, FILE_ANY_ACCESS)
IOCTL_SCSI_GET_CAPABILITIES = (IOCTL_SCSI_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0404 shl 2) or (METHOD_BUFFERED);
//#define IOCTL_SCSI_PASS_THROUGH_DIRECT CTL_CODE(IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
IOCTL_SCSI_PASS_THROUGH_DIRECT = (IOCTL_SCSI_BASE shl 16) or ((FILE_READ_ACCESS or FILE_WRITE_ACCESS) shl 14) or ($0405 shl 2) or (METHOD_BUFFERED);
//#define IOCTL_SCSI_GET_ADDRESS CTL_CODE(IOCTL_SCSI_BASE, 0x0406, METHOD_BUFFERED, FILE_ANY_ACCESS)
IOCTL_SCSI_GET_ADDRESS = (IOCTL_SCSI_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0406 shl 2) or (METHOD_BUFFERED);
//#define IOCTL_SCSI_RESCAN_BUS CTL_CODE(IOCTL_SCSI_BASE, 0x0407, METHOD_BUFFERED, FILE_ANY_ACCESS)
IOCTL_SCSI_RESCAN_BUS = (IOCTL_SCSI_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0407 shl 2) or (METHOD_BUFFERED);
//#define IOCTL_SCSI_GET_DUMP_POINTERS CTL_CODE(IOCTL_SCSI_BASE, 0x0408, METHOD_BUFFERED, FILE_ANY_ACCESS)
IOCTL_SCSI_GET_DUMP_POINTERS = (IOCTL_SCSI_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0408 shl 2) or (METHOD_BUFFERED);
//#define IOCTL_SCSI_FREE_DUMP_POINTERS CTL_CODE(IOCTL_SCSI_BASE, 0x0409, METHOD_BUFFERED, FILE_ANY_ACCESS)
IOCTL_SCSI_GET_FREE_DUMP_POINTERS = (IOCTL_SCSI_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0409 shl 2) or (METHOD_BUFFERED);
//#define IOCTL_IDE_PASS_THROUGH CTL_CODE(IOCTL_SCSI_BASE, 0x040a, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
IOCTL_IDE_PASS_THROUGH = (IOCTL_SCSI_BASE shl 16) or ((FILE_READ_ACCESS or FILE_WRITE_ACCESS) shl 14) or ($040a shl 2) or (METHOD_BUFFERED);
//-------------------------------------------------------------
// GETVERSIONOUTPARAMS contains the data returned from the
// Get Driver Version function.
//-------------------------------------------------------------
type
TGetVersionOutParams = packed record
bVersion : BYTE; // Binary driver version.
bRevision : BYTE; // Binary driver revision.
bReserved : BYTE; // Not used.
bIDEDeviceMap : BYTE; // Bit map of IDE devices.
fCapabilities : DWORD; // Bit mask of driver capabilities.
dwReserved : Array[0..3] of DWORD; // For future use.
end;
GETVERSIONOUTPARAMS = TGetVersionOutParams;
GETVERSIONINPARAMS = TGetVersionOutParams;
PGetVersionOutParams = ^TGetVersionOutParams;
LPGetVersionOutParams = ^TGetVersionOutParams;
// Bits returned in the fCapabilities member of GETVERSIONOUTPARAMS
// ATA ID command supported
const
CAP_IDE_ID_FUNCTION = 1; // ATAPI ID command supported
CAP_IDE_ATAPI_ID = 2; // SMART commannds supported
CAP_IDE_EXECUTE_SMART_FUNCTION = 4;
//---------------------------------------------------------------------
// IDE registers
//---------------------------------------------------------------------
type
TIDERegs = packed record
bFeaturesReg : BYTE; // Used for specifying SMART "commands".
bSectorCountReg : BYTE; // IDE sector count register
bSectorNumberReg : BYTE; // IDE sector number register
bCylLowReg : BYTE; // IDE low order cylinder value
bCylHighReg : BYTE; // IDE high order cylinder value
bDriveHeadReg : BYTE; // IDE drive/head register
bCommandReg : BYTE; // Actual IDE command.
bReserved : BYTE; // reserved for future use. Must be zero.
end;
IDEREGS = TIDERegs;
PIDERegs = ^TIDERegs;
LPIDERegs = PIDERegs;
_IDEREGS = TIDERegs;
// Valid values for the bCommandReg member of IDEREGS.
const
IDE_ATAPI_ID = $A1; // Returns ID sector for ATAPI.
IDE_ID_FUNCTION = $EC; // Returns ID sector for ATA.
IDE_EXECUTE_SMART_FUNCTION = $B0; // Performs SMART cmd. Requires valid bFeaturesReg, bCylLowReg, and bCylHighReg
// Cylinder register values required when issuing SMART command
SMART_CYL_LOW = $4F;
SMART_CYL_HI = $C2;
//---------------------------------------------------------------------
// SENDCMDINPARAMS contains the input parameters for the
// Send Command to Drive function.
//---------------------------------------------------------------------
type
TSendCmdInParams = packed record
cBufferSize : DWORD; // Buffer size in bytes
irDriveRegs : TIDERegs; // Structure with drive register values.
bDriveNumber : BYTE; // Physical drive number to send command to (0,1,2,3).
bReserved : Array[0..2] of Byte; // Reserved for future expansion.
dwReserved : Array[0..3] of DWORD; // For future use.
bBuffer : Array[0..0] of Byte; // Input buffer.
end;
SENDCMDINPARAMS = TSendCmdInParams;
PSendCmdInParams = ^TSendCmdInParams;
LPSendCmdInParams = PSendCmdInParams;
_SENDCMDINPARAMS = TSendCmdInParams;
//---------------------------------------------------------------------
// Status returned from driver
//---------------------------------------------------------------------
type
TDriverStatus = packed record
bDriverError : Byte; // Error code from driver, or 0 if no error.
bIDEStatus : Byte; // Contents of IDE Error register. Only valid when bDriverError is SMART_IDE_ERROR.
bReserved : Array[0..1] of Byte; // Reserved for future expansion.
dwReserved : Array[0..1] of DWORD; // Reserved for future expansion.
end;
DRIVERSTATUS = TDriverStatus;
PDriverStatus = ^TDriverStatus;
LPDriverStatus = TDriverStatus;
_DRIVERSTATUS = TDriverStatus;
// bDriverError values
const
SMART_NO_ERROR = 0; // No error
SMART_IDE_ERROR = 1; // Error from IDE controller
SMART_INVALID_FLAG = 2; // Invalid command flag
SMART_INVALID_COMMAND = 3; // Invalid command byte
SMART_INVALID_BUFFER = 4; // Bad buffer (null, invalid addr..)
SMART_INVALID_DRIVE = 5; // Drive number not valid
SMART_INVALID_IOCTL = 6; // Invalid IOCTL
SMART_ERROR_NO_MEM = 7; // Could not lock user's buffer
SMART_INVALID_REGISTER = 8; // Some IDE Register not valid
SMART_NOT_SUPPORTED = 9; // Invalid cmd flag set
SMART_NO_IDE_DEVICE =10; // Cmd issued to device not present although drive number is valid
// 11-255 reserved
//---------------------------------------------------------------------
// Structure returned by SMART IOCTL for several commands
//---------------------------------------------------------------------
type
TSendCmdOutParams = packed record
cBufferSize : DWORD; // Size of bBuffer in bytes
DriverStatus : TDriverStatus; // Driver status structure.
bBuffer : Array[0..0] of BYTE; // Buffer of arbitrary length in which to store the data read from the drive.
end;
SENDCMDOUTPARAMS = TSendCmdOutParams;
PSendCmdOutParams = ^TSendCmdOutParams;
LPSendCmdOutParams = PSendCmdOutParams;
_SENDCMDOUTPARAMS = TSendCmdOutParams;
//---------------------------------------------------------------------
// Feature register defines for SMART "sub commands"
//---------------------------------------------------------------------
const
SMART_READ_ATTRIBUTE_VALUES = $D0; // ATA4: Renamed
// SMART READ DATA
SMART_READ_ATTRIBUTE_THRESHOLDS = $D1; // Obsoleted in ATA4!
SMART_ENABLE_DISABLE_ATTRIBUTE_AUTOSAVE = $D2;
SMART_SAVE_ATTRIBUTE_VALUES = $D3;
SMART_EXECUTE_OFFLINE_IMMEDIATE = $D4; // ATA4
// Vendor specific commands:
SMART_ENABLE_SMART_OPERATIONS = $D8;
SMART_DISABLE_SMART_OPERATIONS = $D9;
SMART_RETURN_SMART_STATUS = $DA;
//---------------------------------------------------------------------
// The following structure defines the structure of a Drive Attribute
//---------------------------------------------------------------------
type
TDriveAttribute = packed record
bAttrID : BYTE; // Identifies which attribute
wStatusFlags : WORD; // see bit definitions below
bAttrValue : BYTE; // Current normalized value
bWorstValue : BYTE; // How bad has it ever been?
bRawValue : Array[0..6] of BYTE; // Un-normalized value
bReserved : BYTE; // ...
end;
DRIVEATTRIBUTE = TDriveAttribute;
PDriveAttribute = ^TDriveAttribute;
LPDriveAttribute = PDriveAttribute;
//---------------------------------------------------------------------
// The following structure defines the structure of a Warranty Threshold
// Obsoleted in ATA4!
//---------------------------------------------------------------------
TAttrThreshold = packed record
bAttrID : BYTE; // Identifies which attribute
bWarrantyThreshold : BYTE; // Triggering value
bReserved : Array[0..9] of BYTE; // ...
end;
ATTRTHRESHOLD = TAttrThreshold;
PAttrThreshold = ^TAttrThreshold;
LPAttrThreshold = PAttrThreshold;
//---------------------------------------------------------------------
// The following struct defines the interesting part of the IDENTIFY buffer:
//---------------------------------------------------------------------
TIdSector = packed record
wGenConfig : USHORT;
wNumCyls : USHORT;
wReserved : USHORT;
wNumHeads : USHORT;
wBytesPerTrack : USHORT;
wBytesPerSector : USHORT;
wSectorsPerTrack : USHORT;
wVendorUnique : Array[0..2] of USHORT;
sSerialNumber : Array[0..19] of CHAR;
wBufferType : USHORT;
wBufferSize : USHORT;
wECCSize : USHORT;
sFirmwareRev : Array[0..7] of CHAR;
sModelNumber : Array[0..39] of CHAR;
wMoreVendorUnique : USHORT;
wDoubleWordIO : USHORT;
wCapabilities : USHORT;
wReserved1 : USHORT;
wPIOTiming : USHORT;
wDMATiming : USHORT;
wBS : USHORT;
wNumCurrentCyls : USHORT;
wNumCurrentHeads : USHORT;
wNumCurrentSectorsPerTrack : USHORT;
ulCurrentSectorCapacity : ULONG;
wMultSectorStuff : USHORT;
ulTotalAddressableSectors : ULONG;
wSingleWordDMA : USHORT;
wMultiWordDMA : USHORT;
bReserved : Array[0..127] of BYTE;
end;
PIdSector = ^TIdSector;
IDSECTOR = TIdSector;
_IDSECTOR = TIdSector;
//---------------------------------------------------------------------
// Valid Attribute IDs
//---------------------------------------------------------------------
const
ATTR_INVALID = 0;
ATTR_READ_ERROR_RATE = 1;
ATTR_THROUGHPUT_PERF = 2;
ATTR_SPIN_UP_TIME = 3;
ATTR_START_STOP_COUNT = 4;
ATTR_REALLOC_SECTOR_COUNT = 5;
ATTR_READ_CHANNEL_MARGIN = 6;
ATTR_SEEK_ERROR_RATE = 7;
ATTR_SEEK_TIME_PERF = 8;
ATTR_POWER_ON_HRS_COUNT = 9;
ATTR_SPIN_RETRY_COUNT = 10;
ATTR_CALIBRATION_RETRY_COUNT = 11;
ATTR_POWER_CYCLE_COUNT = 12;
//---------------------------------------------------------------------
// Status Flags Values
//---------------------------------------------------------------------
PRE_FAILURE_WARRANTY = $1;
ON_LINE_COLLECTION = $2;
PERFORMANCE_ATTRIBUTE = $4;
ERROR_RATE_ATTRIBUTE = $8;
EVENT_COUNT_ATTRIBUTE = $10;
SELF_PRESERVING_ATTRIBUTE = $20;
//=============================================================
// IOCTL_STORAGE_GET_DEVICE_NUMBER
//
// input - none
//
// output - STORAGE_DEVICE_NUMBER structure
// The values in the STORAGE_DEVICE_NUMBER structure are guaranteed
// to remain unchanged until the system is rebooted. They are not
// guaranteed to be persistant across boots.
type
TStorageDeviceNumber = packed record
// The FILE_DEVICE_XXX type for this device.
DeviceType : DEVICE_TYPE;
// The number of this device
DeviceNumber : ULONG;
// If the device is partitionable, the partition number of the device.
// Otherwise -1
PartitionNumber : ULONG;
end;
STORAGE_DEVICE_NUMBER = TStorageDeviceNumber;
PStorageDeviceNumber = ^TStorageDeviceNumber;
//=============================================================
// IOCTL_STORAGE_GET_MEDIA_TYPES_EX will return an array of DEVICE_MEDIA_INFO
// structures, one per supported type, embedded in the GET_MEDIA_TYPES struct.
type
STORAGE_MEDIA_TYPE = DWORD;
const
// Following are defined in ntdddisk.h in the MEDIA_TYPE enum
Unknown = 0; // Format is unknown
F5_1Pt2_512 = 1; // 5.25", 1.2MB, 512 bytes/sector
F3_1Pt44_512 = 2; // 3.5", 1.44MB, 512 bytes/sector
F3_2Pt88_512 = 3; // 3.5", 2.88MB, 512 bytes/sector
F3_20Pt8_512 = 4; // 3.5", 20.8MB, 512 bytes/sector
F3_720_512 = 5; // 3.5", 720KB, 512 bytes/sector
F5_360_512 = 6; // 5.25", 360KB, 512 bytes/sector
F5_320_512 = 7; // 5.25", 320KB, 512 bytes/sector
F5_320_1024 = 8; // 5.25", 320KB, 1024 bytes/sector
F5_180_512 = 9; // 5.25", 180KB, 512 bytes/sector
F5_160_512 = 10; // 5.25", 160KB, 512 bytes/sector
RemovableMedia = 11; // Removable media other than floppy
FixedMedia = 12; // Fixed hard disk media
F3_120M_512 = 13; // 3.5", 120M Floppy
F3_640_512 = 14; // 3.5" , 640KB, 512 bytes/sector
F5_640_512 = 15; // 5.25", 640KB, 512 bytes/sector
F5_720_512 = 16; // 5.25", 720KB, 512 bytes/sector
F3_1Pt2_512 = 17; // 3.5" , 1.2Mb, 512 bytes/sector
F3_1Pt23_1024 = 18; // 3.5" , 1.23Mb, 1024 bytes/sector
F5_1Pt23_1024 = 19; // 5.25", 1.23MB, 1024 bytes/sector
F3_128Mb_512 = 20; // 3.5" MO 128Mb 512 bytes/sector
F3_230Mb_512 = 21; // 3.5" MO 230Mb 512 bytes/sector
F8_256_128 = 22; // 8", 256KB, 128 bytes/sector
// STORAGE_MEDIA_TYPE
DDS_4mm = 32; // Tape - DAT DDS1,2,... (all vendors)
MiniQic = 33; // Tape - miniQIC Tape
Travan = 34; // Tape - Travan TR-1,2,3,...
QIC = 35; // Tape - QIC
MP_8mm = 36; // Tape - 8mm Exabyte Metal Particle
AME_8mm = 37; // Tape - 8mm Exabyte Advanced Metal Evap
AIT1_8mm = 38; // Tape - 8mm Sony AIT1
DLT = 39; // Tape - DLT Compact IIIxt, IV
NCTP = 40; // Tape - Philips NCTP
IBM_3480 = 41; // Tape - IBM 3480
IBM_3490E = 42; // Tape - IBM 3490E
IBM_Magstar_3590 = 43; // Tape - IBM Magstar 3590
IBM_Magstar_MP = 44; // Tape - IBM Magstar MP
STK_DATA_D3 = 45; // Tape - STK Data D3
SONY_DTF = 46; // Tape - Sony DTF
DV_6mm = 47; // Tape - 6mm Digital Video
DMI = 48; // Tape - Exabyte DMI and compatibles
SONY_D2 = 49; // Tape - Sony D2S and D2L
CLEANER_CARTRIDGE = 50; // Cleaner - All Drive types that support Drive Cleaners
CD_ROM = 51; // Opt_Disk - CD
CD_R = 52; // Opt_Disk - CD-Recordable (Write Once)
CD_RW = 53; // Opt_Disk - CD-Rewriteable
DVD_ROM = 54; // Opt_Disk - DVD-ROM
DVD_R = 55; // Opt_Disk - DVD-Recordable (Write Once)
DVD_RW = 56; // Opt_Disk - DVD-Rewriteable
MO_3_RW = 57; // Opt_Disk - 3.5" Rewriteable MO Disk
MO_5_WO = 58; // Opt_Disk - MO 5.25" Write Once
MO_5_RW = 59; // Opt_Disk - MO 5.25" Rewriteable (not LIMDOW)
MO_5_LIMDOW = 60; // Opt_Disk - MO 5.25" Rewriteable (LIMDOW)
PC_5_WO = 61; // Opt_Disk - Phase Change 5.25" Write Once Optical
PC_5_RW = 62; // Opt_Disk - Phase Change 5.25" Rewriteable
PD_5_RW = 63; // Opt_Disk - PhaseChange Dual Rewriteable
ABL_5_WO = 64; // Opt_Disk - Ablative 5.25" Write Once Optical
PINNACLE_APEX_5_RW = 65; // Opt_Disk - Pinnacle Apex 4.6GB Rewriteable Optical
SONY_12_WO = 66; // Opt_Disk - Sony 12" Write Once
PHILIPS_12_WO = 67; // Opt_Disk - Philips/LMS 12" Write Once
HITACHI_12_WO = 68; // Opt_Disk - Hitachi 12" Write Once
CYGNET_12_WO = 69; // Opt_Disk - Cygnet/ATG 12" Write Once
KODAK_14_WO = 70; // Opt_Disk - Kodak 14" Write Once
MO_NFR_525 = 71; // Opt_Disk - Near Field Recording (Terastor)
NIKON_12_RW = 72; // Opt_Disk - Nikon 12" Rewriteable
IOMEGA_ZIP = 73; // Mag_Disk - Iomega Zip
IOMEGA_JAZ = 74; // Mag_Disk - Iomega Jaz
SYQUEST_EZ135 = 75; // Mag_Disk - Syquest EZ135
SYQUEST_EZFLYER = 76; // Mag_Disk - Syquest EzFlyer
SYQUEST_SYJET = 77; // Mag_Disk - Syquest SyJet
AVATAR_F2 = 78; // Mag_Disk - 2.5" Floppy
MP2_8mm = 79; // Tape - 8mm Hitachi
DST_S = 80; // Ampex DST Small Tapes
DST_M = 81; // Ampex DST Medium Tapes
DST_L = 82; // Ampex DST Large Tapes
VXATape_1 = 83; // Ecrix 8mm Tape
VXATape_2 = 84; // Ecrix 8mm Tape
STK_EAGLE = 85; // STK Eagle
LTO_Ultrium = 86; // IBM, HP, Seagate LTO Ultrium
LTO_Accelis = 87; // IBM, HP, Seagate LTO Accelis
//-------------------------------------------------------------
MEDIA_ERASEABLE = $00000001;
MEDIA_WRITE_ONCE = $00000002;
MEDIA_READ_ONLY = $00000004;
MEDIA_READ_WRITE = $00000008;
MEDIA_WRITE_PROTECTED = $00000100;
MEDIA_CURRENTLY_MOUNTED = $80000000;
//-------------------------------------------------------------
// Define the different storage bus types
// Bus types below 128 (0x80) are reserved for Microsoft use
type
TStorageBusType = ( BusTypeUnknown, BusTypeScsi, BusTypeAtapi, BusTypeAta,
BusType1394, BusTypeSsa, BusTypeFibre, BusTypeUsb, BusTypeRAID );
// BusTypeMaxReserved = 0x7F
STORAGE_BUS_TYPE = TStorageBusType;
PStorageBusType = ^TStorageBusType;
TDeviceMediaInfo = packed record
DeviceSpecific : packed record
case byte of
0 :
( DiskInfo : packed record
Cylinders : LARGE_INTEGER;
MediaType : STORAGE_MEDIA_TYPE;
TracksPerCylinder : ULONG;
SectorsPerTrack : ULONG;
BytesPerSector : ULONG;
NumberMediaSides : ULONG;
MediaCharacteristics : ULONG; // Bitmask of MEDIA_XXX values.
end );
1 :
( RemovableDiskInfo : packed record
Cylinders : LARGE_INTEGER;
MediaType : STORAGE_MEDIA_TYPE;
TracksPerCylinder : ULONG;
SectorsPerTrack : ULONG;
BytesPerSector : ULONG;
NumberMediaSides : ULONG;
MediaCharacteristics : ULONG; // Bitmask of MEDIA_XXX values.
end );
2 :
( TapeInfo : packed record
MediaType : STORAGE_MEDIA_TYPE;
MediaCharacteristics : ULONG; // Bitmask of MEDIA_XXX values.
CurrentBlockSize : ULONG;
BusType : STORAGE_BUS_TYPE;
BusSpecificData : packed record // Bus specific information describing the medium supported.
case longint of
0 :
( ScsiInformation : packed record
MediumType : UCHAR;
DensityCode : UCHAR;
end );
end;
end );
end;
end;
DEVICE_MEDIA_INFO = TDeviceMediaInfo;
PDeviceMediaInfo = ^TDeviceMediaInfo;
TGetMediaTypes = packed record
DeviceType : DEVICE_TYPE; // FILE_DEVICE_XXX values
MediaInfoCount : ULONG;
MediaInfo : Array[0..0] of DEVICE_MEDIA_INFO;
end;
GET_MEDIA_TYPES = TGetMediaTypes;
PGetMediaTypes = ^TGetMediaTypes;
//=============================================================
// IOCTL_SCSI_MINIPORT
// Define header for I/O control SRB. }
type
TSrbIoControl = packed record
HeaderLength : ULONG; // Is sizeof(SRB_IO_CONTROL).
// Identifies the application-dedicated, target HBA for this request.
// This signature is used to prevent conflicts in ControlCode values between vendors.
// It should be a string of ASCII characters.
// If a miniport driver does not recognize the input Signature value,
// it must complete the request with a status of SRB_STATUS_INVALID_REQUEST.
Signature : Array[0..7] of Char;
// Indicates the interval in seconds that the request can execute
// before the OS-specific port driver might consider it timed out.
// Miniport drivers are not required to time requests because the port driver does.
Timeout : ULONG;
// Indicates the operation to be performed. There are no system-defined operations.
// Values must be defined by the driver as a set of private I/O control codes
// with which the application can make requests by calling the Win32R DeviceIoControl function.
ControlCode : ULONG;
// Returns a status code for examination by the requesting application.
ReturnCode : ULONG;
// Indicates the size in bytes of the immediately following data area.
// This area can be divided for the particular operation into input and output areas.
// For input requests, the contents of the DataBuffer will be copied
// to the requestor up to the returned value of DataTransferLength.
Length : ULONG;
end;
SRB_IO_CONTROL = TSrbIoControl;
PSrbIoControl = ^TSrbIoControl;
// SCSI IO Device Control Codes
const
FILE_DEVICE_SCSI = $0000001b;
IOCTL_SCSI_EXECUTE_IN = (FILE_DEVICE_SCSI shl 16) or $0011;
IOCTL_SCSI_EXECUTE_OUT = (FILE_DEVICE_SCSI shl 16) or $0012;
IOCTL_SCSI_EXECUTE_NONE = (FILE_DEVICE_SCSI shl 16) or $0013;
// SMART support in atapi
IOCTL_SCSI_MINIPORT_SMART_VERSION = (FILE_DEVICE_SCSI shl 16) or $0500;
IOCTL_SCSI_MINIPORT_IDENTIFY = (FILE_DEVICE_SCSI shl 16) or $0501;
IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS = (FILE_DEVICE_SCSI shl 16) or $0502;
IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS = (FILE_DEVICE_SCSI shl 16) or $0503;
IOCTL_SCSI_MINIPORT_ENABLE_SMART = (FILE_DEVICE_SCSI shl 16) or $0504;
IOCTL_SCSI_MINIPORT_DISABLE_SMART = (FILE_DEVICE_SCSI shl 16) or $0505;
IOCTL_SCSI_MINIPORT_RETURN_STATUS = (FILE_DEVICE_SCSI shl 16) or $0506;
IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE = (FILE_DEVICE_SCSI shl 16) or $0507;
IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES = (FILE_DEVICE_SCSI shl 16) or $0508;
IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS = (FILE_DEVICE_SCSI shl 16) or $0509;
IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE = (FILE_DEVICE_SCSI shl 16) or $050a;
//=============================================================
// Used with the IOCTL_SCSI_GET_INQUIRY_DATA IOCTL.
type
// Define SCSI adapter bus information.
{$ALIGN ON}
TScsiBusData = record // warning! dword alignment
NumberOfLogicalUnits : Byte;
InitiatorBusId : Byte;
InquiryDataOffset : ULONG;
end;
SCSI_BUS_DATA = TScsiBusData;
PScsiBusData = ^TScsiBusData;
// Define SCSI adapter bus information structure..
TScsiAdapterBusInfo = record // warning! dword alignment
NumberOfBuses : Byte;
BusData : Array[0..0] of SCSI_BUS_DATA;
end;
SCSI_ADAPTER_BUS_INFO = TScsiAdapterBusInfo;
PScsiAdapterBusInfo = ^TScsiAdapterBusInfo;
TScsiInquiryData = record // warning! dword alignment
PathId : Byte;
TargetId : Byte;
Lun : Byte;
DeviceClaimed : Boolean;
InquiryDataLength : ULONG;
NextInquiryDataOffset : ULONG;
InquiryData : Array[0..0] of Byte;
end;
SCSI_INQUIRY_DATA = TScsiInquiryData;
PScsiInquiryData = ^TScsiInquiryData;
{$ALIGN OFF}
//=============================================================
// Open device to allow DeviceIoControl communications.
function GetPhysicalDriveHandle( DriveNum : Byte; DesireAccess : ACCESS_MASK ) : THandle;
// Get SCSI/IDE port handle.
function GetScsiPortHandle( PortNum : Byte; DesireAccess : ACCESS_MASK ) : THandle;
function GetScsiInquiryData( hDevice : THandle; var InquiryData : TScsiAdapterBusInfo; var dwSize : DWORD ) : BOOL;
function GetMediaType( hDevice : THandle ) : DEVICE_TYPE;
function GetMediaTypes( hDevice : THandle; var MediaTypes : TGetMediaTypes; var dwSize : DWORD ) : BOOL;
// Send an IDENTIFY command to the drive bDriveNum = 0-3
// bIDCmd = IDE_ID_FUNCTION or IDE_ATAPI_ID
function SmartIdentifyDirect(hDevice: THandle; bDriveNum: Byte;
bIDCmd: Byte; var IdSector: TIdSector; SCIP: TSendCmdInParams;
SCOP: TSendCmdOutParams; var IdSectorSize: LongInt; var dwBytesReturned: DWORD): BOOL;
function SmartIdentifyMiniport( hDevice : THandle; bTargetId : Byte; bIDCmd : Byte; var IdSector : TIdSector; var IdSectorSize : LongInt ) : BOOL;
// Send a SMART_ENABLE_SMART_OPERATIONS command to the drive bDriveNum = 0-3
function DoEnableSMART( hDevice : THandle; bDriveNum : Byte; var SCOP : TSendCmdOutParams; var dwBytesReturned : DWORD ) : BOOL;
// Send a SMART_READ_ATTRIBUTE_VALUES command to the drive bDriveNum = 0-3
function DoReadAttributesCmd(hDevice: THandle; SCIP: TSendCmdInParams;
var SCOP: TSendCmdOutParams; bDriveNum: Byte): BOOL;
function DoReadThresholdsCmd(hDevice: THandle; SCIP: TSendCmdInParams;
var SCOP: TSendCmdOutParams; bDriveNum: Byte): BOOL;
var dwBytesReturned : DWORD;
// Change the WORD array to a BYTE array
procedure ChangeByteOrder( var Data; Size : Integer );
//=============================================================
implementation
var OSVersionInfo: TOSVersionInfo;
//---------------------------------------------------------------------
// Return INVALID_HANDLE_VALUE on error.
// Note: under NT/2000 Administrative priveleges are required
function GetPhysicalDriveHandle( DriveNum : Byte; DesireAccess : ACCESS_MASK ) : THandle;
var s : String;
begin
OSVersionInfo.dwOSVersionInfoSize := SizeOf(OSVersionInfo);
GetVersionEx(OSVersionInfo);
if OSVersionInfo.dwPlatformId=VER_PLATFORM_WIN32_NT then // Windows NT, Windows 2000
begin
Str(DriveNum,s); // avoid SysUtils
Result := CreateFile( PChar('\\.\PhysicalDrive'+s), DesireAccess, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0 );
end
else // Windows 95 OSR2, Windows 98
Result := CreateFile( '\\.\SMARTVSD', 0, 0, nil, CREATE_NEW, 0, 0 );
end;
//-------------------------------------------------------------
// Get SCSI/IDE port handle.
// Windows NT/2000 only.
// Note: Administrative priveleges are NOT required
function GetScsiPortHandle( PortNum : Byte; DesireAccess : ACCESS_MASK ) : THandle;
var s : String;
begin
Str(PortNum,s); // avoid SysUtils
Result := CreateFile( PChar('\\.\Scsi'+s+':'), DesireAccess, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0 );
end;
//-------------------------------------------------------------
function GetScsiInquiryData( hDevice : THandle; var InquiryData : TScsiAdapterBusInfo; var dwSize : DWORD ) : BOOL;
begin
FillChar(InquiryData,dwSize,#0);
Result := DeviceIoControl( hDevice, IOCTL_SCSI_GET_INQUIRY_DATA, nil, 0, @InquiryData, dwSize, dwSize, nil );
end;
//-------------------------------------------------------------
function GetMediaTypes( hDevice : THandle; var MediaTypes : TGetMediaTypes; var dwSize : DWORD ) : BOOL;
begin
FillChar(MediaTypes,dwSize,#0);
Result := DeviceIoControl( hDevice, IOCTL_STORAGE_GET_MEDIA_TYPES_EX, nil, 0, @MediaTypes, dwSize, dwSize, nil );
end;
//-------------------------------------------------------------
function GetMediaType( hDevice : THandle ) : STORAGE_MEDIA_TYPE;
const Size = 1024;
var dwBytesReturned : DWORD;
bMediaTypes : Array[0..Size-1] of Byte;
rMediaTypes : TGetMediaTypes absolute bMediaTypes;
begin
FillChar(bMediaTypes,Size,#0);
Result := 0;
if DeviceIoControl( hDevice, IOCTL_STORAGE_GET_MEDIA_TYPES_EX, nil, 0, @bMediaTypes, Size, dwBytesReturned, nil ) then with rMediaTypes do
if MediaInfoCount>0 then with MediaInfo[0].DeviceSpecific do
case DeviceType of
FILE_DEVICE_CD_ROM,
FILE_DEVICE_DVD:
Result := RemovableDiskInfo.MediaType;
FILE_DEVICE_DISK:
Result := DiskInfo.MediaType;
FILE_DEVICE_TAPE:
Result := TapeInfo.MediaType;
end;
end;
//-------------------------------------------------------------
// SmartIdentifyDirect
//
// FUNCTION: Send an IDENTIFY command to the drive bDriveNum = 0-3
// bIDCmd = IDE_ID_FUNCTION or IDE_ATAPI_ID
//
// Note: work only with IDE device handle.
function SmartIdentifyDirect(hDevice: THandle; bDriveNum: Byte;
bIDCmd: Byte; var IdSector: TIdSector; SCIP: TSendCmdInParams;
SCOP: TSendCmdOutParams; var IdSectorSize: LongInt; var dwBytesReturned: DWORD): BOOL;
const
BufferSize = SizeOf(TSendCmdOutParams) + IDENTIFY_BUFFER_SIZE - 1;
var
Buffer: Array [0..BufferSize-1] of Byte;
MCOP: TSendCmdOutParams absolute Buffer;
//dwBytesReturned: DWORD;
begin
FillChar(SCIP,SizeOf(TSendCmdInParams)-1,#0);
FillChar(Buffer,BufferSize,#0);
dwBytesReturned := 0;
IdSectorSize := 0;
// Set up data structures for IDENTIFY command.
with SCIP do
begin
cBufferSize := IDENTIFY_BUFFER_SIZE;
bDriveNumber := bDriveNum;
with irDriveRegs do
begin
bFeaturesReg := 0;
bSectorCountReg := 1;
bSectorNumberReg := 1;
bCylLowReg := 0;
bCylHighReg := 0;
bDriveHeadReg := $A0 or ((bDriveNum and 1) shl 4);
bCommandReg := bIDCmd; // The command can either be IDE identify or ATAPI identify.
end;
end;
Result:= DeviceIoControl(hDevice, DFP_RECEIVE_DRIVE_DATA, @SCIP,
SizeOf(TSendCmdInParams)-1, @MCOP, BufferSize, dwBytesReturned, nil);
if Result then
begin
IdSectorSize:= dwBytesReturned-SizeOf(TSendCmdOutParams)+1;
if (IdSectorSize <= 0) then
IdSectorSize:= 0
else
System.Move(MCOP.bBuffer, IdSector, IdSectorSize);
end;
SCOP:= MCOP;
end;
//-------------------------------------------------------------
// Same as above but
// - work only NT;
// - work with cotroller or device handle.
// Note: Administrator priveleges are not required to open controller handle.
function SmartIdentifyMiniport( hDevice : THandle; bTargetId : Byte; bIDCmd : Byte; var IdSector : TIdSector; var IdSectorSize : LongInt ) : BOOL;
const
DataLength = sizeof(TSendCmdInParams)-1+IDENTIFY_BUFFER_SIZE;
BufferLength = SizeOf(SRB_IO_CONTROL)+DataLength;
var cbBytesReturned : DWORD;
pData : PSendCmdInParams;
Buffer : Array[0..BufferLength] of Byte;
srbControl : TSrbIoControl absolute Buffer;
begin
// fill in srbControl fields
FillChar(Buffer,BufferLength,#0);
srbControl.HeaderLength := SizeOf(SRB_IO_CONTROL);
System.Move('SCSIDISK',srbControl.Signature,8);
srbControl.Timeout := 2;
srbControl.Length := DataLength;
srbControl.ControlCode := IOCTL_SCSI_MINIPORT_IDENTIFY;
pData := PSendCmdInParams(PChar(@Buffer)+SizeOf(SRB_IO_CONTROL));
with pData^ do
begin
cBufferSize := IDENTIFY_BUFFER_SIZE;
bDriveNumber := bTargetId;
with irDriveRegs do
begin
bFeaturesReg := 0;
bSectorCountReg := 1;
bSectorNumberReg := 1;
bCylLowReg := 0;
bCylHighReg := 0;
bDriveHeadReg := $A0 or ((bTargetId and 1) shl 4);
bCommandReg := bIDCmd; // The command can either be IDE identify or ATAPI identify.
end;
end;
Result := DeviceIoControl( hDevice, IOCTL_SCSI_MINIPORT, @Buffer, BufferLength, @Buffer, BufferLength, cbBytesReturned, nil );
if Result then
begin
IdSectorSize := cbBytesReturned-SizeOf(SRB_IO_CONTROL)-SizeOf(TSendCmdOutParams)+1;
if IdSectorSize<=0 then IdSectorSize := 0
else
begin
if IdSectorSize>IDENTIFY_BUFFER_SIZE then IdSectorSize := IDENTIFY_BUFFER_SIZE;
System.Move( PSendCmdOutParams(pData)^.bBuffer,IdSector,IdSectorSize);
end;
end;
end;
//-------------------------------------------------------------
// DoEnableSMART
//
// FUNCTION: Send a SMART_ENABLE_SMART_OPERATIONS command to the drive bDriveNum = 0-3
//
function DoEnableSMART(hDevice: THandle; bDriveNum : Byte; var SCOP : TSendCmdOutParams; var dwBytesReturned : DWORD ) : BOOL;
var SCIP : TSendCmdInParams;
begin
FillChar(SCIP,SizeOf(TSendCmdInParams)-1,#0);
FillChar(SCOP,SizeOf(TSendCmdOutParams)-1,#0);
dwBytesReturned := 0;
// Set up data structures for Enable SMART Command.
with SCIP do
begin
cBufferSize := 0;
bDriveNumber := bDriveNum;
with irDriveRegs do
begin
bFeaturesReg := SMART_ENABLE_SMART_OPERATIONS;
bSectorCountReg := 1;
bSectorNumberReg := 1;
bCylLowReg := SMART_CYL_LOW;
bCylHighReg := SMART_CYL_HI;
bDriveHeadReg := $A0 or ((bDriveNum and 1) shl 4); // Compute the drive number.
bCommandReg := IDE_EXECUTE_SMART_FUNCTION;
end;
end;
Result := DeviceIoControl( hDevice, DFP_SEND_DRIVE_COMMAND, @SCIP, SizeOf(TSendCmdInParams)-1,
@SCOP, SizeOf(TSendCmdOutParams)-1, dwBytesReturned, nil );
end;
//-------------------------------------------------------------
// DoReadAttributesCmd
//
// FUNCTION: Send a SMART_READ_ATTRIBUTE_VALUES command to the drive bDriveNum = 0-3
//
function DoReadAttributesCmd(hDevice : THandle;
SCIP: TSendCmdInParams; var SCOP: TSendCmdOutParams;
bDriveNum: Byte): BOOL;
var
dwBytesReturned: DWORD;
begin
// Set up data structures for Read Attributes SMART Command.
with SCIP do
begin
cBufferSize:= READ_ATTRIBUTE_BUFFER_SIZE;
bDriveNumber:= bDriveNum;
with irDriveRegs do
begin
bFeaturesReg:= SMART_READ_ATTRIBUTE_VALUES;
bSectorCountReg:= 1;
bSectorNumberReg:= 1;
bCylLowReg:= SMART_CYL_LOW;
bCylHighReg:= SMART_CYL_HI;
bDriveHeadReg:= $A0 or ((bDriveNum and 1) shl 4); // Compute the drive number.
bCommandReg:= IDE_EXECUTE_SMART_FUNCTION;
end;
end;
Result:= DeviceIoControl(hDevice, DFP_RECEIVE_DRIVE_DATA,
@SCIP, SizeOf(TSendCmdInParams)-1, @SCOP,
SizeOf(TSendCmdOutParams) + READ_ATTRIBUTE_BUFFER_SIZE-1,
dwBytesReturned, nil);
end;
//-------------------------------------------------------------
// DoReadThresholdsCmd
//
// FUNCTION: Send a SMART_READ_ATTRIBUTE_THRESHOLDS command to the drive bDriveNum = 0-3
//
function DoReadThresholdsCmd( hDevice: THandle; SCIP: TSendCmdInParams;
var SCOP: TSendCmdOutParams; bDriveNum: Byte): BOOL;
var
dwBytesReturned: DWORD;
begin
// Set up data structures for Read Thresholds SMART Command.
with SCIP do
begin
cBufferSize:= READ_THRESHOLD_BUFFER_SIZE;
bDriveNumber:= bDriveNum;
with irDriveRegs do
begin
bFeaturesReg := SMART_READ_ATTRIBUTE_THRESHOLDS;
bSectorCountReg := 1;
bSectorNumberReg := 1;
bCylLowReg := SMART_CYL_LOW;
bCylHighReg := SMART_CYL_HI;
bDriveHeadReg := $A0 or ((bDriveNum and 1) shl 4); // Compute the drive number.
bCommandReg := IDE_EXECUTE_SMART_FUNCTION;
end;
end;
Result := DeviceIoControl(hDevice, DFP_RECEIVE_DRIVE_DATA, @SCIP,
SizeOf(TSendCmdInParams)-1, @SCOP, SizeOf(TSendCmdOutParams) +
READ_THRESHOLD_BUFFER_SIZE - 1, dwBytesReturned, nil );
end;
//---------------------------------------------------------------------
// Change the WORD array to a BYTE array
//---------------------------------------------------------------------
procedure ChangeByteOrder( var Data; Size : Integer );
var ptr : PChar;
i : Integer;
c : Char;
begin
ptr := @Data;
for i := 0 to (Size shr 1)-1 do
begin
c := ptr^;
ptr^ := (ptr+1)^;
(ptr+1)^ := c;
Inc(ptr,2);
end;
end;
end.