unit Drives; { see TEST program below !! } { Unit Drives, written by Salvatore Besso } { mc8505@mclink.it } { This unit is freeware and is donated to } { the SWAG archival group. } { Finally, a Drives unit that correctly } { works in both real and protected mode, } { in a Windows 95 DOS box, and that doesn't } { require a media to be present in the } { removable drive. } { This unit is still not able to correctly } { recognize Iomega Zip drives in a Windows } { 95 DOS box for now (they are recognized } { as removable media). As soon as new } { informations will be available from the } { interrupt list of Ralph Brown, the unit } { will be modified. Actually informations } { about Iomega interrupt are very scarce. } { A new Dpmi unit is beyond the end of this } { unit } { Test program is beyond the end of the } { Drives and Dpmi units } { If you have any feedback, feel free to } { e-mail me } interface uses {$IFDEF DPMI} Dpmi, {$ENDIF} Dos; const { dtXXXX constants - Drive Type } dtInvalid = $0; dtUnknown = $1; { Floppy disk } dt8Single = $2; dt8Double = $4; dt360 = $8; dt1200 = $10; dt720 = $20; dt1440 = $40; dt2880 = $80; dtAnyFloppy = $FE; { Other media } dtTape = $100; dtFloptical = $200; dtRamDisk = $400; dtCdRom = $800; dtIomegaZip = $1000; dtHardDisk = $80000; { Other attributes } dtRemovable = $100000; dtRemote = $200000; type PParamBlock = ^TParamBlock; TParamBlock = record SpecialFunctions: Byte; { Special functions } DeviceType : Byte; { Device type } DeviceAttributes: Word; { Device attributes } MaxCylinders : Word; { Number of cylinders } MediaType : Byte; { Media type } { Beginning of BIOS parameter block (BPB) } BytesPerSector : Word; { Bytes per sector } SectPerCluster : Byte; { Sectors per cluster } ReservedSectors : Word; { Number of reserved sectors } NumberFats : Byte; { Number of FATs } RootDirEntries : Word; { Number of root-directory entries } TotalSectors : Word; { Total number of sectors } MediaDescriptor : Byte; { Media descriptor } SectorsPerFat : Word; { Number of sectors per FAT } SectorsPerTrack : Word; { Number of sectors per track } NumberHeads : Word; { Number of heads } HiddenSectors : LongInt; { Number of hidden sectors } HugeSectors : LongInt { Number of sectors if TotalSectors = 0 } { End of BIOS parameter block (BPB) } end; PtrRec = record { replicated from OBJECTS.PAS to avoid using the unit } Ofs,Seg: Word end; DriveLetters = 'A'..'Z'; DriveSet = Set of DriveLetters; { returns all available drives in a DriveSet type variable } procedure GetDrives (var Drive: DriveSet); { returns drive type } function GetDriveType (Drive: Char): LongInt; implementation procedure GetDrives (var Drive: DriveSet); var DriveName: array[1..2] of Char; FCB : array[0..43] of Char; Dr : LongInt; begin asm PUSH SI PUSH DI PUSH ES PUSH DS MOV SI,SS { Stack points to local variables } MOV DS,SI { also DS ... } PUSH DS POP ES { ...and ES } MOV BYTE PTR [DriveName],'A' MOV BYTE PTR [DriveName + 1],':' MOV WORD PTR [Dr],0 MOV WORD PTR [Dr + 2],0 MOV DX,1 XOR CX,CX @@1: LEA SI,DriveName LEA DI,FCB MOV AX,290EH { Function 29H - Parse Filename - AL = options } INT 21H CMP AL,0FFH JE @@2 PUSH DX PUSH CX MOV AX,4409H { SUBST drives are ignored } MOV BL,BYTE PTR [DriveName] SUB BL,'@' INT 21H JC @@2 TEST DH,10000000B POP CX POP DX JNZ @@2 OR WORD PTR [Dr],DX OR WORD PTR [Dr + 2],CX @@2: SHL DX,1 RCL CX,1 INC BYTE PTR [DriveName] CMP BYTE PTR [DriveName],'Z' JBE @@1 SHL WORD PTR [Dr],1 RCL WORD PTR [Dr + 2],1 POP DS POP ES POP DI POP SI end; Drive := DriveSet (Dr) end; function GetDriveType (Drive: Char): LongInt; var DPB : PParamBlock; SegInfo: Word; Regs : Registers; Temp : Byte; Result : LongInt; {$IFDEF DPMI} Size : LongInt; {$ENDIF} function GetDevParms (Drive: Char; var DPB: PParamBlock; Segm: Word): Boolean; var Regs: Registers; begin GetDevParms := False; FillChar (Regs,SizeOf (Registers),0); Regs.AX := $440D; Regs.BL := Byte (Drive) - 64; Regs.CH := $08; { category: disk drive } Regs.CL := $60; { device parameters } {$IFNDEF DPMI} Regs.DS := PtrRec (DPB).Seg; Regs.DX := PtrRec (DPB).Ofs; MsDos (Regs); {$ELSE} Regs.DS := Segm; Regs.DX := 0; if NOT DpmiMsDos (Regs) then Exit; {$ENDIF} GetDevParms := Regs.Flags and fCarry = 0 end; function IsDriveRemote (Drive: Char): Boolean; assembler; asm MOV AX,4409H { IOCTL - Check if block device remote } MOV BL,Drive { BL = drive } SUB BL,'@' { 1 = A:, 2 = B:, etc... } INT 21H XOR AX,AX JC @@1 AND DH,00010000B JZ @@1 INC AX @@1: end; function IsCDRomDrive (Drive: Char): Boolean; assembler; asm MOV AX,150BH { MSCDEX.EXE installation test } XOR CH,CH { CX = drive } MOV CL,Drive SUB CL,'A' { 0 = A:, 1 = B:, etc... } INT 2FH PUSH AX POP CX XOR AX,AX JCXZ @@1 TEST BX,0ADADH JZ @@1 INC AX @@1: end; function IsIomegaZip: Boolean; var Regs : Registers; Result: Boolean; begin { Find first GUEST.EXE... } FillChar (Regs,SizeOf (Registers),0); Regs.AX := $5700; { GUEST.EXE installation test } Regs.BX := $0201; { Iomega ID ??? } Regs.DX := $496F; { 'Io' } {$IFNDEF DPMI} Intr ($2F,Regs); {$ELSE} if NOT DpmiIntr ($2F,Regs) then Exit; {$ENDIF} Result := Regs.AL = $FF; if NOT Result then begin { ...GUEST.EXE not found: Find GUEST95.EXE... } { Interrupt informations for GUEST95.EXE still } { not available } end; IsIomegaZip := Result end; begin { GetDriveType } GetDriveType := dtInvalid; {$IFNDEF DPMI} New (DPB); SegInfo := 0; {$ELSE} Size := SizeOf (TParamBlock); if NOT DpmiGetMem (Pointer (DPB),SegInfo,Size) then Exit; {$ENDIF} FillChar (DPB^,SizeOf (TParamBlock),0); FillChar (Regs,SizeOf (Regs),0); Regs.AX := $4408; { removable media ? } Regs.BL := Byte (Drive) - 64; {$IFNDEF DPMI} MsDos (Regs); {$ELSE} if NOT DpmiMsDos (Regs) then begin DpmiFreeMem (Pointer (DPB)); Exit end; {$ENDIF} Temp := 0; if Regs.Flags and fCarry <> 0 then { error, check error code in AX } begin { Driver does NOT support this call, so guess as a hard disk } if Regs.AX = 1 then Temp := 3 end else begin if Regs.AX = 0 then Temp := 2 { removable media, floppy, WORM, Floptical, ZIP } else Temp := 3 { or hard disk, ramdisk or CD-ROM } end; Result := dtInvalid; case Temp of { Removable } 2: if GetDevParms (Drive,DPB,SegInfo) then begin case DPB^.DeviceType of 0: Result := dt360; 1: Result := dt1200; 2: Result := dt720; 3: Result := dt8Single; 4: Result := dt8Double; 5: if IsIomegaZip then Result := dtIomegaZip else Result := dtHardDisk; 6: Result := dtTape; 7: Result := dt1440; 8: Result := dtFloptical; 9: begin if (DPB^.MaxCylinders = 80) and (DPB^.NumberHeads = 2) then Result := dt2880 else if IsIomegaZip then Result := dtIomegaZip else Result := dtUnknown end else Result := dtUnknown end; if Result > dtUnknown then Result := Result or dtRemovable end; { Fixed } 3: if GetDevParms (Drive,DPB,SegInfo) then if DPB^.DeviceType = 5 then Result := dtHardDisk else Result := dtUnknown else Result := dtRamDisk end; if IsDriveRemote (Drive) then if IsCDRomDrive (Drive) then Result := dtCdRom or dtRemovable else Result := Result or dtRemote; {$IFNDEF DPMI} Dispose (DPB); {$ELSE} if NOT DpmiFreeMem (Pointer (DPB)) then Exit; {$ENDIF} GetDriveType := Result end; end. (* unit Dpmi; {$IFNDEF DPMI} Error ! this code works in Protected Mode only {$ENDIF} {$G+,S-} interface uses Dos; { Virtual interrupt state values for use with the SetInterruptState and GetInterruptState functions. } const intDisabled = False; intEnabled = True; { Return values for MemInitSwapFile and MemCloseSwapFile } const rtmOK = $0; rtmNoMemory = $1; rtmFileIOError = $22; { TRealModeRegs is a real mode registers data structure for use with the RealModeInt, RealModeCall, RealModeIntCall, and AllocRealCallback functions. } type PRealModeRegs = ^TRealModeRegs; TRealModeRegs = record case Integer of 0: ( EDI,ESI,EBP,EXX,EBX,EDX,ECX,EAX: LongInt; Flags,ES,DS,FS,GS,IP,CS,SP,SS : Word ); 1: ( DI,DIH,SI,SIH,BP,BPH,XX,XXH: Word; case Integer of 0: ( BX,BXH,DX,DXH,CX,CXH,AX,AXH: Word ); 1: ( BL,BH,BLH,BHH,DL,DH,DLH,DHH,CL,CH,CLH,CHH,AL,AH,ALH,AHH: Byte ) ) end; { TDescriptor is an 8-byte structure for use with the GetDescriptor and SetDescriptor procedures. } type PDescriptor = ^TDescriptor; TDescriptor = array[0..7] of Byte; { TVersionInfo is a DPMI version information structure for use with the GetVersionInfo procedure. } type PVersionInfo = ^TVersionInfo; TVersionInfo = record MinorVersion : Byte; { AL } MajorVersion : Byte; { AH } Flags : Word; { BX } ProcessorType: Byte; { CL } Reserved : Byte; { CH } SlaveBaseInt : Byte; { DL } MasterBaseInt: Byte { DH } end; { Corresponds to procedure Intr but uses Registers instead of TRealModeRegs } function DpmiIntr (IntNo: Byte; var Regs: Registers): Boolean; { Corresponds to procedure MsDos but uses Registers instead of TRealModeRegs } function DpmiMsDos (var Regs: Registers): Boolean; { Corresponds to procedure GetMem; allocates memory in the first } { megabyte, accessible in both protected - through P - and real } { mode - through Segment:$0000 } function DpmiGetMem (var P: Pointer; var Segment: Word; var Size: Longint): Boolean; { Corresponds to procedure FreeMem; you must use it to deallocate } { memory allocated with DpmiGetMem } function DpmiFreeMem (var P: Pointer): Boolean; { IncSelector returns the value to add to the first selector, and to } { the next ones, to access the descriptor array allocated by DpmiGetMem } { when blocks greater than 64 K are requested } procedure IncSelector (var Selector: Word); { AllocSelectors allocates one or more selectors using Dpmi function } { 0000H. The return value is the base selector of the allocated block } { of selectors, or zero if the function is unsuccessful } function AllocSelectors (Count: Word): Word; { FreeSelector frees a selector using Dpmi function 0001H. } function FreeSelector (Selector: Word): Boolean; { SegmentToSelector maps a real mode segment onto a selector using Dpmi } { function 0002H. The return value is a selector, or zero if the function } { is unsuccessful. Selectors allocated with this function are permanent } { and can never be freed. If you need a temporary selector or pointer, use } { the AllocRealSelector or AllocRealPtr functions instead } function SegmentToSelector (Segment: Word): Word; { SelectorToSegment returns the real mode segment address (paragraph) that } { corresponds to the base address of the given selector. The selector is } { assumed to be a valid selector that references real mode memory. If this } { is not the case, the return value is undefined } function SelectorToSegment (Selector: Word): Word; { GetSelectorBase returns the 32-bit linear base address of a selector } { using Dpmi function 0006H. The return value is zero if the function } { is unsuccessful } function GetSelectorBase (Selector: Word): LongInt; { SetSelectorBase sets the 32-bit linear base address of a selector } { using Dpmi function 0007H } function SetSelectorBase (Selector: Word; Base: LongInt): Boolean; { GetSelectorLimit returns the limit of the specified selector. The } { return value is zero if the selector is invalid } function GetSelectorLimit (Selector: Word): LongInt; { SetSelectorLimit sets the limit of a selector using Dpmi function 0008H } function SetSelectorLimit (Selector: Word; Limit: LongInt): Boolean; { GetAccessRights returns the access rights for a selector. The return } { value is zero if the selector is invalid } function GetAccessRights (Selector: Word): Word; { SetAccessRights sets the access rights for a selector using Dpmi } { function 0009H } function SetAccessRights (Selector: Word; AccessRights: Word): Boolean; { AllocSelectorAlias creates an aliased selector using Dpmi function } { 000AH. The return value is a selector, or zero if the function is } { unsuccessful } function AllocSelectorAlias (Selector: Word): Word; { GetDescriptor copies the LDT entry for the given selector into the } { given descriptor record using Dpmi function 000BH } function GetDescriptor (Selector: Word; var Descriptor: TDescriptor): Boolean; { SetDescriptor copies the given descriptor record into the LDT entry } { for the given selector using Dpmi function 000CH } function SetDescriptor (Selector: Word; var Descriptor: TDescriptor): Boolean; { AllocSpecificSelector allocates a specific selector using Dpmi function } { 000DH. The return value is True if the selector was allocated. Otherwise } { the return value is False } function AllocSpecificSelector (Selector: Word): Boolean; { GetRealModeInt returns the contents of the given real mode interrupt } { vector using Dpmi function 0200H } function GetRealModeInt (Int: Byte): Pointer; { SetRealModeInt sets the interrupt vector for the specified real mode } { interrupt using Dpmi function 0201H } function SetRealModeInt (Int: Byte; Vector: Pointer): Boolean; { GetException returns the contents of the given exception vector using } { Dpmi function 0202H } function GetException (Exception: Byte): Pointer; { SetException sets the exception vector for the specified exception } { using Dpmi function 0203H } function SetException (Exception: Byte; Vector: Pointer): Boolean; { GetProtModeInt returns the contents of the given protected mode } { interrupt vector using Dpmi function 0204H } function GetProtModeInt (Int: Byte): Pointer; { SetProtModeInt sets the interrupt vector for the specified protected } { mode interrupt using Dpmi function 0205H } function SetProtModeInt (Int: Byte; Vector: Pointer): Boolean; { RealModeInt simulates a software interrupt instruction in real mode } { using Dpmi function 0300H } function RealModeInt (Int: Byte; var Regs: TRealModeRegs): Boolean; { RealModeCall calls a real mode procedure with a far return frame using } { Dpmi function 0301H } function RealModeCall (Proc: Pointer; var Regs: TRealModeRegs): Boolean; { RealModeIntCall calls a real mode procedure with an interrupt return } { frame using Dpmi function 0302H } function RealModeIntCall (Proc: Pointer; var Regs: TRealModeRegs): Boolean; { AllocCallback allocates a real mode callback using Dpmi function 0303H. } { The return value is the real mode address of the callback, or zero if } { the function is unsuccessful } function AllocCallback (Proc: Pointer; var Regs: TRealModeRegs): Pointer; { FreeCallback frees a real mode callback using DPMI function 0304H } function FreeCallback (Callback: Pointer): Boolean; { GetVersionInfo returns Dpmi version information in the specified version } { information record using Dpmi function 0400H } procedure GetVersionInfo (var Info: TVersionInfo); { SetInterruptState sets the virtual interrupt state to the specified } { value and returns the previous virtual interrupt state, corresponding } { to Dpmi functions 0900H and 0901H } function SetInterruptState (Enable: Boolean): Boolean; { GetInterruptState returns the current virtual interrupt state using } { Dpmi function 0902H } function GetInterruptState: Boolean; { AllocRealSelector allocates a new selector and maps it onto the given } { real mode segment address. The return value is a selector, or zero if } { the function is unsuccessful. This function corresponds to Dpmi function } { 0002H, except that the resulting selector can be freed (using Dpmi } { function 0001H) if required } function AllocRealSelector (Segment: Word): Word; { AllocRealPtr corresponds to AllocRealSelector, except that it works on } { pointers instead of segments and selectors. The return value is a } { protected mode pointer that points to the same physical memory location } { as the specified real mode pointer. If the function is unsuccessful the } { return value is NIL } function AllocRealPtr (RealAddr: Pointer): Pointer; { FreeRealPtr frees the selector used in a pointer that was allocated by } { AllocRealPtr } function FreeRealPtr (RealPtr: Pointer): Boolean; { MemInitSwapFile opens a swapfile of size FileSize. If file exists and } { new size is larger, this function will grow the swap file, otherwise } { the call has no effect. File size is limited to 2 gigabytes. } { } { } { Returns: } { rtmOK - Successful } { rtmNoMemory - Not enough disk space } { rtmFileIOError - Could not open/grow file } function MemInitSwapFile (FileName: PChar; FileSize: LongInt): Integer; { MemCloseSwapFile closes the swapfile if it was created by the current } { task. If Delete is non 0, the swap file is deleted. } { } { } { Returns: } { rtmOK - Successful } { rtmNoMemory - Not enough physical memory to run without } { swap file } { rtmFileIOError - Could not close/delete the file } function MemCloseSwapFile (Delete: Integer): Integer; implementation var VersionInfo : TVersionInfo; Regs : Registers; RealModeRegs: TRealModeRegs; DPMIBits : Integer; SelIncr : Integer; function DpmiIntr (IntNo: Byte; var Regs: Registers): Boolean; var Err: Integer; begin FillChar (RealModeRegs,SizeOf (TRealModeRegs),0); RealModeRegs.AX := Regs.AX; RealModeRegs.BX := Regs.BX; RealModeRegs.CX := Regs.CX; RealModeRegs.DX := Regs.DX; RealModeRegs.DI := Regs.DI; RealModeRegs.SI := Regs.SI; RealModeRegs.BP := Regs.BP; RealModeRegs.DS := Regs.DS; RealModeRegs.ES := Regs.ES; asm MOV AX,SEG RealModeRegs MOV ES,AX CMP DPMIBits,16 JE @@1 DB 66H MOV DI,OFFSET RealModeRegs DW 0000H JMP @@2 @@1: MOV DI,OFFSET RealModeRegs @@2: MOV BL,IntNo XOR BH,BH XOR CX,CX MOV AX,0300H INT 31H XOR AX,AX JNC @@3 MOV AX,-31 @@3: MOV Err,AX end; if Err = 0 then begin Regs.AX := RealModeRegs.AX; Regs.BX := RealModeRegs.BX; Regs.CX := RealModeRegs.CX; Regs.DX := RealModeRegs.DX; Regs.DI := RealModeRegs.DI; Regs.SI := RealModeRegs.SI; Regs.BP := RealModeRegs.BP; Regs.DS := RealModeRegs.DS; Regs.ES := RealModeRegs.ES; Regs.Flags := RealModeRegs.Flags end; DpmiIntr := Err = 0 end; function DpmiMsDos (var Regs: Registers): Boolean; begin DpmiMsDos := DpmiIntr ($21,Regs) end; function DpmiGetMem (var P: Pointer; var Segment: Word; var Size: Longint): Boolean; begin Regs.AX := $0100; Regs.BX := (Size + 15) div 16; if Regs.BX = 0 then Regs.BX := $FFFF; { Size > $000FFFF0 } Size := Regs.BX; { calculates memory } Size := Size * 16; { effectively allocated } Intr ($31,Regs); DpmiGetMem := Regs.Flags and fCarry = 0; if Regs.Flags and fCarry = 0 then begin P := Ptr (Regs.DX,0); { selector:offset pointer } Segment := Regs.AX { segment for real mode } end else begin Size := Regs.BX; { size of the largest } Size := Size * 16 { available block } end end; function DpmiFreeMem (var P: Pointer): Boolean; begin Regs.AX := $0101; Regs.DX := Seg (P^); Intr ($31,Regs); P := NIL; DpmiFreeMem := Regs.Flags and fCarry = 0 end; procedure IncSelector (var Selector: Word); begin Inc (Selector,SelIncr) end; function AllocSelectors (Count: Word): Word; assembler; asm MOV CX,Count MOV AX,0000H INT 31H JNC @@1 XOR AX,AX @@1: end; function FreeSelector (Selector: Word): Boolean; assembler; asm MOV BX,Selector MOV AX,0001H INT 31H SBB AX, AX INC AX end; function SegmentToSelector (Segment: Word): Word; assembler; asm MOV BX,Segment MOV AX,0002H INT 31H JNC @@1 XOR AX,AX @@1: end; function SelectorToSegment (Selector: Word): Word; assembler; asm MOV BX,Selector MOV AX,0006H INT 31H MOV AX,DX OR AX,CX ROR AX,4 end; function GetSelectorBase (Selector: Word): LongInt; assembler; asm MOV BX,Selector MOV AX,0006H INT 31H JNC @@1 XCHG AX,CX XCHG AX,DX JNC @@1 XOR AX,AX CWD @@1: end; function SetSelectorBase (Selector: Word; Base: LongInt): Boolean; assembler; asm MOV BX,Selector MOV DX,Base.Word[0] MOV CX,Base.Word[2] MOV AX,0007H INT 31H SBB AX,AX INC AX end; function GetSelectorLimit (Selector: Word): LongInt; assembler; asm XOR AX,AX LSL AX,Selector XOR DX,DX end; function SetSelectorLimit (Selector: Word; Limit: LongInt): Boolean; assembler; asm MOV BX,Selector MOV DX,Limit.Word[0] MOV CX,Limit.Word[2] MOV AX,0008H INT 31H SBB AX,AX INC AX end; function GetAccessRights (Selector: Word): Word; assembler; asm XOR AX,AX LAR AX,Selector XCHG AL,AH end; function SetAccessRights (Selector: Word; AccessRights: Word): Boolean; assembler; asm MOV BX,Selector MOV CX,AccessRights MOV AX,0009H INT 31H SBB AX,AX INC AX end; function AllocSelectorAlias (Selector: Word): Word; assembler; asm MOV BX,Selector MOV AX,000AH INT 31H JNC @@1 XOR AX,AX @@1: end; function GetDescriptor (Selector: Word; var Descriptor: TDescriptor): Boolean; assembler; asm MOV BX,Selector LES DI,Descriptor MOV AX,000BH INT 31H SBB AX,AX INC AX end; function SetDescriptor (Selector: Word; var Descriptor: TDescriptor): Boolean; assembler; asm MOV BX,Selector LES DI,Descriptor MOV AX,000CH INT 31H SBB AX,AX INC AX end; function AllocSpecificSelector (Selector: Word): Boolean; assembler; asm MOV BX,Selector MOV AX,000DH INT 31H SBB AX,AX INC AX end; function GetRealModeInt (Int: Byte): Pointer; assembler; asm MOV BL,Int MOV AX,0200H INT 31H XCHG AX,CX XCHG AX,DX JNC @@1 XOR AX,AX CWD @@1: end; function SetRealModeInt (Int: Byte; Vector: Pointer): Boolean; assembler; asm MOV BL,Int MOV DX,Vector.Word[0] MOV CX,Vector.Word[2] MOV AX,0201H INT 31H SBB AX,AX INC AX end; function GetException (Exception: Byte): Pointer; assembler; asm MOV BL,Exception MOV AX,0202H INT 31H XCHG AX,CX XCHG AX,DX JNC @@1 XOR AX,AX CWD @@1: end; function SetException (Exception: Byte; Vector: Pointer): Boolean; assembler; asm MOV BL,Exception MOV DX,Vector.Word[0] MOV CX,Vector.Word[2] MOV AX,0203H INT 31H SBB AX,AX INC AX end; function GetProtModeInt (Int: Byte): Pointer; assembler; asm MOV BL,Int MOV AX,0204H INT 31H MOV AX,DX MOV DX,CX end; function SetProtModeInt (Int: Byte; Vector: Pointer): Boolean; assembler; asm MOV BL,Int MOV DX,Vector.Word[0] MOV CX,Vector.Word[2] MOV AX,0205H INT 31H SBB AX,AX INC AX end; function RealModeInt (Int: Byte; var Regs: TRealModeRegs): Boolean; assembler; asm MOV BL,Int XOR BH,BH XOR CX,CX LES DI,Regs MOV AX,0300H INT 31H SBB AX,AX INC AX end; function RealModeCall (Proc: Pointer; var Regs: TRealModeRegs): Boolean; assembler; asm XOR BH,BH XOR CX,CX LES DI,Regs MOV AX,Proc.Word[0] MOV ES:[DI].TRealModeRegs.&IP,AX MOV AX,Proc.Word[2] MOV ES:[DI].TRealModeRegs.&CS,AX MOV AX,0301H INT 31H SBB AX,AX INC AX end; function RealModeIntCall (Proc: Pointer; var Regs: TRealModeRegs): Boolean; assembler; asm XOR BH,BH XOR CX,CX LES DI,Regs MOV AX,Proc.Word[0] MOV ES:[DI].TRealModeRegs.&IP,AX MOV AX,Proc.Word[2] MOV ES:[DI].TRealModeRegs.&CS,AX MOV AX,0302H INT 31H SBB AX,AX INC AX end; function AllocCallback (Proc: Pointer; var Regs: TRealModeRegs): Pointer; assembler; asm PUSH DS LDS SI,Proc LES DI,Regs MOV AX,0303H INT 31H POP DS XCHG AX,CX XCHG AX,DX JNC @@1 XOR AX,AX CWD @@1: end; function FreeCallback (Callback: Pointer): Boolean; assembler; asm MOV DX,Callback.Word[0] MOV CX,Callback.Word[2] MOV AX,0304H INT 31H SBB AX,AX INC AX end; procedure GetVersionInfo (var Info: TVersionInfo); assembler; asm MOV AX,0400H INT 31H LES DI,Info CLD STOSW XCHG AX,BX STOSW XCHG AX,CX STOSW XCHG AX,DX STOSW end; function SetInterruptState (Enable: Boolean): Boolean; assembler; asm MOV AL,Enable MOV AH,09H INT 31H end; function GetInterruptState: Boolean; assembler; asm MOV AX,0902H INT 31H end; function AllocRealSelector (Segment: Word): Word; assembler; asm XOR BX,BX MOV AX,0000H MOV CX,1 INT 31H JC @@1 MOV BX,AX MOV DX,Segment ROL DX,4 MOV CX,DX AND DL,0F0H AND CX,0FH MOV AX,0007H INT 31H MOV DX,0FFFFH XOR CX,CX MOV AX,0008H INT 31H @@1: MOV AX,BX end; function AllocRealPtr (RealAddr: Pointer): Pointer; assembler; asm PUSH RealAddr.Word[2] CALL AllocRealSelector MOV DX,AX OR AX,AX JE @@1 MOV AX,RealAddr.Word[0] @@1: end; function FreeRealPtr (RealPtr: Pointer): Boolean; assembler; asm PUSH RealPtr.Word[2] CALL FreeSelector end; function MemInitSwapFile; external 'RTM' index 35; function MemCloseSwapFile; external 'RTM' index 36; begin GetVersionInfo (VersionInfo); { info on Dpmi services } if VersionInfo.Flags and 1 <> 0 then { 16 or 32 bit implementation } DPMIBits := 32 else DPMIBits := 16; Regs.AX := $0003; { calculates the value to add to a } Intr ($31,Regs); { selector if memory allocation is } SelIncr := Regs.AX { greater than 64 K } end. *) { ---------------------------- } { Test program for Drives unit } { ---------------------------- } (* program Test; uses Dos, Drives; var AllDrives: DriveSet; D : DriveLetters; DriveType: LongInt; S : String; function GetVolumeLabel (Drive: Char): String; var SR: SearchRec; begin GetVolumeLabel := ''; FindFirst (Drive + ':\*.*',VolumeID,SR); if DosError = 0 then GetVolumeLabel := SR.Name end; begin GetDrives (AllDrives); for D := 'A' to 'Z' do begin if NOT (D in AllDrives) then Continue; DriveType := GetDriveType (D); if DriveType = dtInvalid then Continue; if DriveType and dtUnknown = dtUnknown then begin S := 'unknown drive'; if DriveType and dtRemote = dtRemote then S := 'remote ' + S else S := 'local ' + S end else if DriveType and dtAnyFloppy <> 0 then begin S := ' floppy disk'; case DriveType and dtAnyFloppy of dt8Single: S := '8" single density' + S; dt8Double: S := '8" double density' + S; dt360 : S := '320/360 KB' + S; dt720 : S := '720 KB' + S; dt1200 : S := '1.2 MB' + S; dt1440 : S := '1.44 MB' + S; dt2880 : S := '2.88 MB' + S end end else if DriveType and dtTape = dtTape then begin S := ' tape drive'; if DriveType and dtRemote = dtRemote then S := 'remote' + S else S := 'local' + S end else if DriveType and dtFloptical = dtFloptical then begin S := ' floptical drive'; if DriveType and dtRemote = dtRemote then S := 'remote' + S else S := 'local' + S end else if DriveType and dtCDRom = dtCDRom then begin S := ' CD-ROM drive'; if DriveType and dtRemote = dtRemote then S := 'remote' + S else S := 'local' + S end else if DriveType and dtIomegaZip = dtIomegaZip then begin S := ' Iomega Zip drive'; if DriveType and dtRemote = dtRemote then S := 'remote' + S else S := 'local' + S end else begin if DriveType and dtRemovable = dtRemovable then begin S := ' removable media'; if DriveType and dtRemote = dtRemote then S := 'remote' + S else S := 'local' + S end else begin S := 'volume ' + GetVolumeLabel (D) + ' ('; if DriveType and dtRemote = dtRemote then S := S + 'remote ' else S := S + 'local '; if DriveType and dtRamDisk = dtRamDisk then begin S := S + 'ram'; if Pos ('.',S) > 0 then Delete (S,Pos ('.',S),1) end else S := S + 'hard'; S := S + ' disk)' end end; S := D + ': ' + S; WriteLn (S) end end. *)