[Back to DRIVES SWAG index] [Back to Main SWAG index] [Original]
unit Drives;
{
Drives Unit for:
Getting and setting drive labels.
Getting and setting drive serial number.
Testing if a drive is ready.
Determining the type of drive (hard/3.5/5.25...)
Return last DOS error status.
All procedures and functions are protected from DOS critical errors.
Author: William R. Florac
Company: FITCO, Verona, WI (wee little company from my house)
Copyright 1996, FITCO. All rights reserved.
1) Users of Drives.pas must accept this disclaimer of warranty:
This Unit is supplied as is. The Fitco disclaims all
warranties, expressed or implied, including, without limitation,
the warranties of merchantability and of fitness for any purpose.
Fitco assumes no liability for damages, direct or conse-
quential, which may result from the use of this Unit."
2) This Unit is donated to the public as public domain except as
noted below.
3) You must copy all Software without modification and must include
all pages, if the Software is distributed without inclusion in your
software product. If you are incorporating the Software in
conjunction with and as a part of your software product which adds
substantial value, you may modify and include portions of the
Software.
4) Fitco retains the copyright for this Unit. You may not distribute
the source code (PAS) or its compiled unit (DCU) for profit.
5) If you do find this Unit handy and you feel guilty
for using such a great product without paying someone,
please feel free to send a few bucks ($25) to support further
development.
6) This file was formated with tabs set to 2.
Please forward any comments or suggestions to Bill Florac at:
email: flash@etcconnect.com
www: http://sumac.etcconnect.com/~fitco/
mail: FITCO
209 Jenna Dr
Verona, WI 53593
Revision History
2/28/96
1.0 released
}
interface
uses
SysUtils, WinProcs, WinTypes;
type
TDriveStyle = (tUnknown, tNoDrive, t3Floppy, t5Floppy, tFixed, tRFixed,
tNetwork, tCDROM, tTape);
PDeviceParams = ^TDeviceParams;
TDeviceParams = record
bSpecFunc: byte; {Special functions}
bDevType: byte; {Device type}
wDevAttr: word; {Device attributes}
wCylinders: word; {Number of cylinders}
bMediaType: byte; {Media type}
{ Beginning of BIOS parameter block (BPB)}
wBytesPerSec: word; {Bytes per sector}
bSecPerClust: byte; {Sectors per cluster}
wResSectors: word; {Number of reserved sectors}
bFATs: byte; {Number of FATs}
wRootDirEnts: word; {Number of root-directory entries}
wSectors: word; {Total number of sectors}
bMedia: byte; {Media descriptor}
wFATsecs: word; {Number of sectors per FAT}
wSecPerTrack: word; {Number of sectors per track}
wHeads: word; {Number of heads}
dwHiddenSecs: longInt; {Number of hidden sectors}
dwHugeSectors: longInt; {Number of sectors if wSectors == 0}
reserved: array[0..10] of char;
{ End of BIOS parameter block (BPB)}
end;
{parameter block for getting serial number}
PSerialNumberParams = ^TSerialNumberParams;
TSerialNumberParams = record
wInfoLevel: word;
dwDiskSerialNumber: longint;
caLabel: array[0..10] of char;
baFileSystem: array[0..7] of char;
end;
{parameter block to get extened error codes}
PExtErrorParams = ^TExtErrorParams;
TExtErrorParams = record
eCode: word;
eClass: word;
eAction: word;
eLocus: word;
eVolume: String;
end;
{structure for FCB}
TEFCB = record
Flag: byte;
Reserved: array [0..4] of char;
Attribute: byte;
Drive: byte;
Name: array [0..7] of char;
Extension: array [0..2] of char;
Misc: array [0..24] of char;
end;
DriveLabel = string[11];
{my exception class}
EDriveException = Class(Exception);
const
{$I strings} { can be found at the END of this module !}
{standard calls}
function DriveReady(wDrive: word): boolean;
{Tests to see if a drive is ready. (floppy there and door closed)}
function GetDriveLabel(wDrive: word): string;
function SetDriveLabel(wDrive: word; s: string): boolean;
{Gets and sets drive label}
function GetDriveSerialNumber(wDrive: word): LongInt;
function SetDriveSerialNumber(wDrive: word; SerialNumber: LongInt): boolean;
{Gets and sets drive serial number}
function GetDefaultDrive: word;
{Returns current default drive}
function GetDriveStyle(wDrive: word): TDriveStyle;
{Returns the drive style (hard, 3-1/2, 5-1/4...)}
procedure GetExtendedErrorInfo(ep: PExtErrorParams);
{Gets the parameters for the last DOS error. Useful after a DriveReady failure.}
{other calls}
function IsCDROMDrive(wDrive: word): boolean;
function WriteDriveSNParam(wDrive: word; psnp: PSerialNumberParams): boolean;
function ReadDriveSNParam(wDrive: word; psnp: PSerialNumberParams): boolean;
function GetDeviceParameters(wDrive: word; var dp: TDeviceParams): boolean;
implementation
{determins if the drive is ready w/o critical errors enabled}
function DriveReady(wDrive: word): boolean;
var
OldErrorMode: Word;
begin
{turn off errors}
OldErrorMode := SetErrorMode(SEM_FAILCRITICALERRORS);
try
if DiskSize(wDrive) = -1
then result := false
else result := true;
finally
{turn on errors}
SetErrorMode(OldErrorMode);
end;
end;
{get drive parameters w/o drive access}
function GetDeviceParameters(wDrive: word; var dp: TDeviceParams): boolean;
begin
result := TRUE; {Assume success}
asm
push ds
mov bx, wDrive
mov ch, 08h {Device category--must be 08h}
mov cl, 60h {MS-DOS IOCTL Get Device Parameters}
lds dx, dp
mov ax, 440Dh
int 21h
jnc @gdp_done {CF SET if error}
mov result, FALSE
@gdp_done:
pop ds
end;
end;
{gets last error message from DOS}
procedure GetExtendedErrorInfo(ep: PExtErrorParams);
var
tCode: word;
tClass: byte;
tAction: byte;
tLocus: byte;
begin
asm
push ds
push bp
mov bx, 0
mov ah, 59h
int 21h
mov tCode, ax
mov tClass, bh
mov tAction, bl
mov tLocus, ch
pop bp
pop ds
end;
ep^.eCode := tCode;
ep^.eClass := tClass;
ep^.eAction := tAction;
ep^.eLocus := tLocus;
ep^.eVolume := '?'; {don't support this for now}
end;
{get volume serial number for a drive: 0=default, 1=A...}
{returns -1 if unable to read}
function GetDriveSerialNumber(wDrive: word): LongInt;
var
snp: TSerialNumberParams;
begin
snp.dwDiskSerialNumber := 0;
if ReadDriveSNParam(wDrive, @snp)
then Result := snp.dwDiskSerialNumber
else Result := -1;
end;
{set volume serial number for a drive: 0=default, 1=A... }
{returns true if it was sucessful}
function SetDriveSerialNumber(wDrive: word; SerialNumber: LongInt): boolean;
var
snp: TSerialNumberParams;
begin
result := false;
{get current parameters}
if ReadDriveSNParam(wDrive, @snp) then begin
{change serial number}
snp.dwDiskSerialNumber := SerialNumber;
{and write back out}
if WriteDriveSNParam(wDrive, @snp) then result := true;
end;
end;
{Write Drive parameters: 0=default, 1=A...}
{Note: wDrive and psnp are treate as var with assembler directive}
{This interupt does NOT generate a critical error!}
function WriteDriveSNParam(wDrive: word; psnp: PSerialNumberParams): boolean; assembler;
asm
push ds {ds might get changed so save it}
mov bx, wDrive
mov al, 01h
mov ah, 69h
lds dx, psnp
int 21h
jnc @no_error {CF SET if error}
xor ax,ax {set false}
jmp @exit
@no_error:
mov ax, 1 {set true}
@exit:
pop ds {restore ds}
end;
{Read Drive parameters: 0=default, 1=A...}
{Note: wDrive and psnp are treate as var with assembler directive}
{This interupt does NOT generate a critical error!}
function ReadDriveSNParam(wDrive: word; psnp: PSerialNumberParams): boolean; assembler;
asm
push ds
mov bx, wDrive
mov al, 00h
mov ah, 69h
lds dx, psnp
int 21h
jnc @no_error {CF SET if error}
xor ax,ax {set false}
jmp @exit
@no_error:
mov ax, 1 {set true}
@exit:
pop ds
end;
{sets the label of the drive specified: wDrive: 0=default 1=A...}
{returns true if it was sucessful}
function SetDriveLabel(wDrive: word; s: string): boolean;
const
EFCB: TEFCB = (
Flag: $FF; { Extended FCB Flag }
Reserved: (#0,#0,#0,#0,#0); { Reserved}
Attribute: $08; { Volume Label Attribute}
Drive: 2; { Drive Identifier}
Name: '????????'; { File Name}
Extension: '???'; { File Extension}
Misc: (#0, #0, #0, #0, #0, { Misc. Info filled by DOS}
' ',' ',' ',' ',' ',' ',' ',' ', { Misc. Info filled by DOS}
' ',' ',' ', { Misc. Info filled by DOS}
#0, #0, #0, #0, #0, #0, #0, #0, #0 { Misc. Info filled by DOS}
)
);
var
Ps: pchar;
err: integer;
x: integer;
begin
{abort if drive not ready}
if not DriveReady(wDrive) then begin
result := false;
exit;
end;
{assume ok}
result := true;
{default things that change in constant varaiable}
EFCB.Name := '????????';
EFCB.Extension := '???';
EFCB.Drive := wDrive;
{See if it exist using a FCB}
asm
{Check to see; if the volume label exists}
{point DTA to ourself}
mov dx,offset EFCB
mov ah,1Ah
int 21h
{point to default FCB}
mov dx, offset EFCB
mov ah, 11h
int 21h
{Exit if label is not present}
cmp al, 0
jne @exit
{Else delete the volume label}
mov dx, offset EFCB
mov ah, 013h
int 21h
or al,al
jz @exit
mov result, 0
@exit:
end;
if not result then exit;
{if string is empty, then just erase}
if length(s) = 0 then exit;
{format string}
for x := length(s) + 1 to 11 do s[x] := ' ';
s[0] := char(11);
{add drive letter!}
if wdrive = 0
then s := '\' + s + #0
else s := chr(64+wdrive) + ':\' + s + #0;
ps := @s[1];
{on now make new one it!}
asm
push ds
lds dx, ps
mov cx, faVolumeID
mov ah,3Ch
int 21h
{CF set if error}
jnc @noerror
mov result, FALSE
jmp @exit
@noerror:
{close file ax = handle}
mov bx,ax
mov ah,3Eh
int 21h
@exit:
pop ds
end
end;
{Get label from drive. 0=default, 1=A...}
{return string of 11 character or "NO NAME" if not found}
function GetDriveLabel(wDrive: word): string;
const
pattern: string[6] = 'c:\*.*';
var
sr: TsearchRec;
OldErrorMode: Word;
DotPos: Byte;
begin
{get default drive}
if wDrive = 0
then wDrive := GetDefaultDrive
else dec(wDrive);
{switch out drive letter}
pattern[1] := char(65 + wDrive);
{stop errors and try}
OldErrorMode := SetErrorMode(SEM_FAILCRITICALERRORS);
try
if FindFirst(Pattern, faVolumeID, sr) = 0 then begin
Result := sr.Name;
DotPos := Pos('.', Result);
if DotPos <> 0 then Delete(Result, DotPos, 1);
end
else result := 'NO NAME'
finally
{restore errorsa}
SetErrorMode(OldErrorMode);
end;
end;
function GetDefaultDrive: word; assembler;
asm
mov ah, 19h {convert default to real}
int 21h
xor ah, ah {clear hi byte}
end;
{Determine id drive is a CDROM, 0=default, 1=A ...}
function IsCDROMDrive(wDrive: word): boolean; assembler;
var
wTempDrive: word;
asm
mov ax, wDrive
or ax, ax
jnz @not_default
mov ah, 19h {convert default to drive}
int 21h
xor ah, ah
mov wTempDrive, ax
jmp @test_it
@not_default: {zero base it}
dec ax
mov wTempDrive, ax
@test_it:
mov ax, 1500h {first test for presence of MSCDEX}
xor bx, bx
int 2fh
mov ax, bx {MSCDEX is not there if bx is zero}
or ax, ax {so return FALSE}
jz @no_mscdex
mov ax, 150bh {MSCDEX driver check API}
mov cx, wTempDrive {...cx is drive index}
int 2fh
or ax, ax
@no_mscdex:
end;
{returns drive type}
{read BOIS not drive so floppy does not have to be in drive}
{I don't have all types of drive so not all could be tested}
function GetDriveStyle(wDrive: word): TDriveStyle;
var
x: word;
wTempDrive: word;
dp: TDeviceParams;
begin
{convert default to drive}
if wDrive = 0
then wTempDrive := GetDefaultDrive
else wTempDrive := wDrive - 1;
x := GetDriveType(wTempDrive);
{get types}
case x of
drive_Removable: begin
dp.bSpecFunc := 0; {need to clear this}
if GetDeviceParameters(wDrive,dp) then begin
case dp.bDevType of
0,1: result := t5floppy; {320K/360K/1.2M}
2,7,9: result := t3floppy; {720K/1.44M/2.88M}
5: result := tRFixed; {yes a removable fixed drive!}
6: result := tTape; {tape}
else result := tUnknown;
end;
end
else result := tUnknown;
end;
drive_Fixed:
if IsCDROMDrive(wDrive)
then result := tCDROM
else result := tFixed;
drive_Remote:
if IsCDROMDrive(wDrive) {I think this is possible on a network!}
then result := tCDROM
else result := tNetWork;
else result := tUnknown;
end;
end;
end. {of unit}
{ ---------------- STRINGS.PAS ---------------------------------}
{ CUT }
{string constants for drives.pas}
{The error class may be one of the following}
eClassStr: array[0..$0D] of string = (
{OK }'OK',
{ERRCLASS_OUTRES (01h) }'Out of resource, such as storage.',
{ERRCLASS_TEMPSIT (02h) }'Not an error, temporary situation (file or record lock)',
{ERRCLASS_AUTH (03h) }'Authorization problem.',
{ERRCLASS_INTRN (04h) }'Internal error in system.',
{ERRCLASS_HRDFAIL (05h) }'Hardware failure.',
{ERRCLASS_SYSFAIL (06h) }'System software failure (missing or incorrect configuration files).',
{ERRCLASS_APPERR (07h) }'Application error.',
{ERRCLASS_NOTFND (08h) }'File or item not found.',
{ERRCLASS_BADFMT (09h) }'File or item with an invalid format or type.',
{ERRCLASS_LOCKED (0Ah) }'Interlocked file or item.',
{ERRCLASS_MEDIA (0Bh) }'Wrong disk in drive, bad spot on disk, or other storage-medium problem.',
{ERRCLASS_ALREADY (0Ch) }'Existing file or item.',
{ERRCLASS_UNK (0Dh) }'Unknown.');
{*The suggested action may be one of the following:}
eActionStr: array[0..$07] of string = (
{OK }'OK',
{ERRACT_RETRY (01h) }'Retry immediately.',
{ERRACT_DLYRET (02h) }'Delay and retry.',
{ERRACT_USER (03h) }'Bad user input, get new values.',
{ERRACT_ABORT (04h) }'Terminate in an orderly manner.',
{ERRACT_PANIC (05h) }'Terminate immediately.',
{ERRACT_IGNORE (06h) }'Ignore the error.',
{ERRACT_INTRET (07h) }'Remove the cause of the error (to change disks, for example) and then retry.');
{The error location may be one of the following:}
eLocusStr: array[0..$05] of string = (
{OK }'OK',
{ERRLOC_UNK (01h) }'Unknown',
{ERRLOC_DISK (02h) }'Random-access device, such as a disk drive',
{ERRLOC_NET (03h) }'Network',
{ERRLOC_SERDEV (04h) }'Serial device',
{ERRLOC_MEM (05h) }'Memory');
{MS DOS error codes}
eDosErrorStr: array[0..$5A] of string = (
{0000h non error} 'OK',
{0001h} 'ERROR_INVALID_FUNCTION',
{0002h} 'ERROR_FILE_NOT_FOUND',
{0003h} 'ERROR_PATH_NOT_FOUND',
{0004h} 'ERROR_TOO_MANY_OPEN_FILES',
{0005h} 'ERROR_ACCESS_DENIED',
{0006h} 'ERROR_INVALID_HANDLE',
{0007h} 'ERROR_ARENA_TRASHED',
{0008h} 'ERROR_NOT_ENOUGH_MEMORY',
{0009h} 'ERROR_INVALID_BLOCK',
{000Ah} 'ERROR_BAD_ENVIRONMENT',
{000Bh} 'ERROR_BAD_FORMAT',
{000Ch} 'ERROR_INVALID_ACCESS',
{000Dh} 'ERROR_INVALID_DATA',
{000Eh} 'Reserved',
{000Fh} 'ERROR_INVALID_DRIVE',
{0010h} 'ERROR_CURRENT_DIRECTORY',
{0011h} 'ERROR_NOT_SAME_DEVICE',
{0012h} 'ERROR_NO_MORE_FILES',
{0013h} 'ERROR_WRITE_PROTECT',
{0014h} 'ERROR_BAD_UNIT',
{0015h} 'ERROR_NOT_READY',
{0016h} 'ERROR_BAD_COMMAND',
{0017h} 'ERROR_CRC',
{0018h} 'ERROR_BAD_LENGTH',
{0019h} 'ERROR_SEEK',
{001Ah} 'ERROR_NOT_DOS_DISK',
{001Bh} 'ERROR_SECTOR_NOT_FOUND',
{001Ch} 'ERROR_OUT_OF_PAPER',
{001Dh} 'ERROR_WRITE_FAULT',
{001Eh} 'ERROR_READ_FAULT',
{001Fh} 'ERROR_GEN_FAILURE',
{0020h} 'ERROR_SHARING_VIOLATION',
{0021h} 'ERROR_LOCK_VIOLATION',
{0022h} 'ERROR_WRONG_DISK',
{0023h} 'ERROR_FCB_UNAVAILABLE',
{0024h} 'ERROR_SHARING_BUFFER_EXCEEDED',
{0025h} 'ERROR_CODE_PAGE_MISMATCHED',
{0026h} 'ERROR_HANDLE_EOF',
{0027h} 'ERROR_HANDLE_DISK_FULL',
{0028h} 'Reserved',
{0029h} 'Reserved',
{002Ah} 'Reserved',
{002Bh} 'Reserved',
{002Ch} 'Reserved',
{002Dh} 'Reserved',
{002Eh} 'Reserved',
{002Fh} 'Reserved',
{0030h} 'Reserved',
{0031h} 'Reserved',
{0032h} 'ERROR_NOT_SUPPORTED',
{0033h} 'ERROR_REM_NOT_LIST',
{0034h} 'ERROR_DUP_NAME',
{0035h} 'ERROR_BAD_NETPATH',
{0036h} 'ERROR_NETWORK_BUSY',
{0037h} 'ERROR_DEV_NOT_EXIST',
{0038h} 'ERROR_TOO_MANY_CMDS',
{0039h} 'ERROR_ADAP_HDW_ERR',
{003Ah} 'ERROR_BAD_NET_RESP',
{003Bh} 'ERROR_UNEXP_NET_ERR',
{003Ch} 'ERROR_BAD_REM_ADAP',
{003Dh} 'ERROR_PRINTQ _FULL',
{003Eh} 'ERROR_NO_SPOOL_SPACE',
{003Fh} 'ERROR_PRINT_CANCELLED',
{0040h} 'ERROR_NETNAME_DELETED',
{0041h} 'ERROR_NETWORK_ACCESS_DENIED',
{0042h} 'ERROR_BAD_DEV_TYPE',
{0043h} 'ERROR_BAD_NET_NAME',
{0044h} 'ERROR_TOO_MANY_NAMES',
{0045h} 'ERROR_TOO_MANY_SESS',
{0046h} 'ERROR_SHARING_PAUSED',
{0047h} 'ERROR_ERROR_REQ _NOT_ACCEP',
{0048h} 'ERROR_REDIR_PAUSED',
{0049h} 'Reserved',
{004Ah} 'Reserved',
{004Bh} 'Reserved',
{004Ch} 'Reserved',
{004Dh} 'Reserved',
{004Eh} 'Reserved',
{004Fh} 'Reserved',
{0050h} 'ERROR_FILE_EXISTS',
{0051h} 'ERROR_DUP_FCB',
{0052h} 'ERROR_CANNOT_MAKE',
{0053h} 'ERROR_FAIL_I24',
{0054h} 'ERROR_OUT_OF_STRUCTURES',
{0055h} 'ERROR_ALREADY_ASSIGNED',
{0056h} 'ERROR_INVALID_PASSWORD',
{0057h} 'ERROR_INVALID_PARAMETER',
{0058h} 'ERROR_NET_WRITE_FAULT',
{0059h} 'Function not supported on Network',
{005Ah} 'ERROR_SYS_COMP_NOT_LOADED');
cDriveStr: array[0..8] of string = (
'Unknown',
'NoDrive',
'3-1/2" floppy',
'5-1/4" floppy',
'hard',
'removable hard',
'network',
'CD ROM',
'tape');
[Back to DRIVES SWAG index] [Back to Main SWAG index] [Original]