Contributor: K. CAMPBELL


{ ###################################################################

	Extends the Windows function GetDriveType()
	and provides the same function for Dos...

	This code by: K Campbell CompuServe [100064,1751]

	Some sections hacked out of code by:

		Dr. Peter Below CIS [100113.1101]

	&

		Extended GetDriveType for Windows 3.0/3.1.
		Code ported from the C in Microsoft PSS document Q105922.
		by	Doug Wegscheid 3/22/94.

	No warrenties given! (Don't blame them, blame me.)

	Note:

	1)		this uses the convention: Drive 1 = A and not Drive 0 = A
			which the original GetDriveType() uses!!!

	2)		works OK with CDRoms and RAMDisks, but I can't test on a
			network (as I'm not on one!) If you use it on a networked
			drive or a removable drive, let me know if it works!

	This code is released to the public domain!
################################################################### }

unit TestDrive;

interface

{$IFDEF WINDOWS}
uses	WinProcs, WinDos, Strings;

{$ELSE}
uses	Dos, Strings;

{$ENDIF}

const	dt_NotFound		= 0; 			{ Not detected }
		dt_Removable	= 1;        { Unknown removable type }
		dt_HardDisk    = 2;        { Standard hard disk }
		dt_Networked	= 3;        { Remote drive on a network }
		dt_CDRom		 	= 4;        { CD Rom drive }
		dt_Floppy     	= 5;        { Floppy drive }
		dt_RAMDisk    	= 6;        { RAM disk }

type	DeviceParams = 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 }
												{ End of BIOS parameter block (BPB) }
		end;

function GetDeviceParameters(Drive : word ; var dp : DeviceParams) : boolean;
function GetDriveTypeEx(D : byte) : byte;
function IsCDRomDrive(D : Byte) : boolean;

implementation


function GetDeviceParameters(Drive : word ; var dp : DeviceParams) : boolean;

{$IFDEF WINDOWS}
var Reg : TRegisters;

{$ELSE}
var Reg : Registers;

{$ENDIF}

begin
	FillChar(Reg, SizeOf(Reg), #0);			{ clean up registers to avoid GPF }
	Reg.ax := $440D;								{ IOCTL }
	Reg.ch := $08;									{ block device }
	Reg.cl := $60;									{ get device parameters }
	Reg.bx := Drive;								{ 1 = A:, 2 = B:, etc... }
	Reg.ds := seg(dp);
	Reg.dx := ofs(dp);
	MSDos(Reg);
	GetDeviceParameters := (Reg.flags and fCarry) = 0
end;


function GetDriveTypeEx(D : byte) : byte;

{$IFNDEF WINDOWS}
var	Reg : Registers;

{$ENDIF}

var   Result, uType : byte;
		dp	: DeviceParams;

begin
	Result := dt_NotFound;
	FillChar (dp, SizeOf(dp), #0);	{ clear the DPB }

{$IFDEF WINDOWS}
	uType := GetDriveType(D - 1);		{ make a rough guess }

{$ELSE}
	uType := 0;
	FillChar(Reg, SizeOf(Reg), #0);
	Reg.ax := $4408;          					{ IOCTL is drive changeable function }
	Reg.bl := D;
	MSDos(Reg);
	if (fCarry and Reg.Flags) <> 0 then
	{ error, check error code in ax }
	begin
		{ Driver does not support this call, so guess as a hard disk }
		if Reg.ax = 1 then uType := 3;
	end
	else
	begin
		if Reg.ax = 0 then						{ media changeable, floppy, WORM or MO }
			uType := 2
		else              						{ else hard disk, ramdisk or CD-ROM }
			uType := 3;
	end;
	{ check if drive is remote }
	Reg.ax := $4409;  							{ IOCTL is redirected device function }
	Reg.bl := D;
	MSDos(Reg);
	if (not ((fCarry and Reg.Flags) <> 0)) and (Reg.dx = $1000) then uType := 4;

{$ENDIF}
	case uType of
		2 :	{ Removable }
			{	0=320/360kb floppy, 1=1.2Mb, 2=720kb, 3=8" single density,
				4=8" double density, 7=1.44Mb, 8=optical, 9=2.88Mb.}
			if GetDeviceParameters(D, dp) and (dp.bDevType in [0..4,7,9]) then
				Result := dt_Floppy
			else
				Result := dt_Removable;
		3 :	{ Fixed }
			if GetDeviceParameters(D, dp) and (dp.bDevType = 5) then
				Result := dt_HardDisk
			else
				Result := dt_RAMDisk;
		4 :   { Remote }
			if IsCDRomDrive(D) then
				Result := dt_CDRom
			else
				Result := dt_Networked;
	end;
	GetDriveTypeEx := Result;
end;


{ Returns TRUE if Drive is a CD-ROM drive, FALSE if it isn't.}
function IsCDRomDrive(D : Byte) : boolean;

{$IFDEF WINDOWS}
var Reg : TRegisters;

{$ELSE}
var Reg : Registers;

{$ENDIF}

begin
	FillChar(Reg, SizeOf(Reg), #0);
	Reg.ax := $150B;			{ MSCDEX installation check }
	Reg.cx := (D - 1);		{ D: 1 = A:, 2 = B:, etc... }
	Intr ($2F, Reg);			{ do it }
	IsCDRomDrive := (Reg.bx = $ADAD) and (Reg.ax <> 0);
end;


end.