home *** CD-ROM | disk | FTP | other *** search
/ C!T ROM 5 / ctrom5b.zip / ctrom5b / PROGRAM / PASCAL / DRIVEI2 / DRIVES.PAS < prev    next >
Pascal/Delphi Source File  |  1995-02-28  |  28KB  |  856 lines

  1. {+------------------------------------------------------------
  2.  | Unit Drives
  3.  |
  4.  | Version: 2.0  Last modified: 02/27/95, 21:49:56
  5.  | Author : P. Below  CIS [100113,1101]
  6.  | Project: Common utilities
  7.  | Units required (only for the Implementation section):
  8.  |   DOS: Dos (Borland)
  9.  |     Windows: Win31 (Borland), WinDOS (Borland), Wintypes (Borland),
  10.  |            WinProcs (Borland), DMPI (own);
  11.  | Description:
  12.  |   This Unit collects routines to gather information about
  13.  |     the disk drives on a system in both DOS and Windows. You can
  14.  |     build a drive map with a single procedure call. In addition
  15.  |     to drive type checking the volume name, serial number, and
  16.  |     FAT type for local fixed disks or the netshare name for 
  17.  |     networked drives are also retrieved.
  18.  |     Low-level routines for all the subfunctions involved in 
  19.  |     building the drive map are exported, too. You can thus get
  20.  |     the media info or disk paramter block for floppy disk or other
  21.  |     removable media drives "by hand", if necessary. 
  22.  |     Most of the low level stuff uses DOS IOCTL functions, even
  23.  |     for the Windows version ( GetDriveType is just to limited ).
  24.  |     CD-ROM identification uses the MSCDEX int 2Fh interface.
  25.  |
  26.  |     This Unit has been checked under real mode DOS and Windows
  27.  |     (Win 3.1, WfWg 3.11, Win NT 3.5 ) but _not_ under protected
  28.  |        mode DOS (DPMI)!
  29.  | Copyright (C) 1994,1995 by Peter Below 
  30.  |   This code is released to the public domain, use it as you see fit
  31.  |     in your own programs (at your own risk, of course) but you should
  32.  |     include a note of the origin of this code in your program.
  33.  +------------------------------------------------------------}
  34. Unit Drives;
  35.  
  36. Interface
  37.  
  38. Const
  39.   DRIVE_CDROM = 5;
  40.   DRIVE_RAM   = 6;
  41.  
  42.   Min_DriveNums = 1;  (* drive a: *)
  43.   Max_DriveNums = 26; (* drive z: *) 
  44. Type
  45.   TDriveTypes = ( FLOPPY, HARDDISK, REMAPPED, REMOTE, CD_ROM,
  46.                   RAMDISK, INVALID );
  47.   TDTypeSet   = SET OF TDriveTypes;
  48.   TDriveNums  = Min_DriveNums..Max_DriveNums;
  49.                 (* range A: To Z: of drive letters *)
  50.   TDriveSet   = SET OF TDriveNums; 
  51.   TDeviceName = ARRAY [0..127] OF CHAR;
  52.   TDiskInfo   = Record (* this is a DOS structure used by GetMediaID
  53.                           but modified to allow for asciiz strings *)
  54.                   InfoLevel: WORD;
  55.                   serialNo: LongInt;
  56.                   volName : ARRAY [0..11] OF CHAR;
  57.                   FATType : ARRAY [0..8] OF CHAR;
  58.                 End;
  59.   TDriveInfo  = Record
  60.                   Flags: TDTypeSet;
  61.                   Case Boolean OF
  62.                     TRUE:  (* For network drives *)
  63.                       (DevName: TDeviceName);
  64.                     FALSE: (* For all other drives *)
  65.                       (Info: TDiskInfo);
  66.                 End;
  67.   TDriveMap   = ARRAY [TDriveNums] OF TDriveInfo;
  68.   PDriveMap   = ^TDriveMap;
  69.  
  70.   LP_DPB = ^DPB;  
  71.   DPB = Record  (* Disk Parameter Block as per MSDOS Programmer's Reference *)
  72.     dpbDrive       : BYTE;
  73.     dpbUnit        : BYTE;
  74.     dpbSectorSize  : WORD;
  75.     dpbClusterMask : BYTE;
  76.     dpbClusterShift: BYTE;
  77.     dpbFirstFAT    : WORD;
  78.     dpbFATCount    : BYTE;
  79.     dpbRootEntries : WORD;
  80.     dpbFirstSector : WORD;
  81.     dpbMaxCluster  : WORD;
  82.     dpbFATSize     : WORD;
  83.     dpbDirSector   : WORD;
  84.     dpbDriverAddr  : Pointer;
  85.     dpbMedia       : BYTE;
  86.     dpbFirstAccess : BYTE;
  87.     dpbNextDPB     : LP_DPB;
  88.     dpbNextFree    : WORD;
  89.     dpbFreeCnt     : WORD;
  90.   End;
  91.  
  92. Procedure MyGetDriveType( n: TDriveNums; Var f: TDTypeSet );
  93. Procedure GetDriveInfo( n: TDriveNums; Var di: TDriveInfo );
  94. Procedure BuildDriveMap( Var DMap: TDriveMap    );
  95.  
  96. Function MSCDexIsloaded: Boolean;
  97. Function DriveIsCDROM( n: TDriveNums ): Boolean;
  98. Function DriveIsRamdisk( n: TDriveNums ): Boolean;
  99. Function GetDiskParameterBlock( drive: TDriveNums ): LP_DPB;
  100. Function GetLastdrive: TDriveNums;
  101.  
  102. { the following functions map directly to DOS IOCTL calls }
  103. Function MediumIsRemovable( n: TDriveNums ): TDriveTypes;
  104. Function DriveIsRemote( n: TDriveNums ): Boolean;
  105. Function DriveIsRemapped( n: TDriveNums ): Boolean;
  106. Function GetMediaID ( Drive: Word; Var info: TDiskInfo ): Boolean;
  107. Function GetDriveMapping( n: TDriveNums ): TDriveNums;
  108. Procedure MapLogicalDrive( n: TDriveNums );
  109.  
  110. Implementation
  111.  
  112. Uses Strings,
  113. {$IFDEF WINDOWS}
  114.  Win31, WinDOS, Wintypes, WinProcs, DMPI;
  115. {$ELSE}
  116.  DOS;
  117. {$ENDIF}
  118.  
  119. {************************************************************
  120.  * Function MediumIsRemovable
  121.  *
  122.  * Parameters:
  123.  *    n: the drive number to check, 1= A:, 2=B: etc.
  124.  * Returns:
  125.  *    one of the three drive types INVALID, FLOPPY or HARDDISK
  126.  * Description:
  127.  *    This function uses DOS IOCTL function $4408 to check a drive
  128.  *    for removable media. It can also be used to check for a drives
  129.  *    existance.
  130.  *    Should work for DOS, Windows, and DPMI.
  131.  *
  132.  *Created: 02/26/95 20:49:03 by P. Below
  133.  ************************************************************}
  134. Function MediumIsRemovable( n: TDriveNums ): TDriveTypes;
  135.   Var
  136.       res: Word;
  137.   Begin
  138.       asm
  139.           mov ax, $4408      (* IOCTL is drive changeable function *)
  140.             mov bl, n
  141. {$IFDEF WINDOWS}
  142.       call Dos3Call
  143. {$ELSE}
  144.       int $21
  145. {$ENDIF}
  146.             mov res, ax
  147.             { Our handling of the result makes the following asumptions here:
  148.               If the function succeeds (carry flag clear), the return in ax
  149.                 will be 0 for removable and 1 for fixed medium.
  150.                 If the function fails (carry flag set), the error code in ax
  151.                 will be 1, if the device driver does not know how to handle the
  152.                 function (in which case we assume a fixed disk, also ax=1, safe bet 
  153.                 according to MS docs) or it will be $F, if the drive is invalid. 
  154.              }
  155.         End; { asm }
  156.         Case res Of
  157.             0: MediumIsRemovable := FLOPPY;
  158.             1: MediumIsRemovable := HARDDISK
  159.         Else
  160.           MediumIsRemovable := INVALID;
  161.         End; { Case }
  162.   End; (* BasicDriveType *)
  163.  
  164. {************************************************************
  165.  * Function DriveIsRemote
  166.  *
  167.  * Parameters:
  168.  *    n: the drive number to check, 1= A:, 2=B: etc.
  169.  * Returns:
  170.  *    TRUE, if the drive is remote, FALSE if it is local or invalid.
  171.  * Description:
  172.  *    This function uses DOS IOCTL function $4409 to check whether 
  173.  *    a drive is remote or local.
  174.  *    Should work for DOS, Windows, and DPMI.
  175.  *
  176.  *Created: 02/26/95 21:12:32 by P. Below
  177.  ************************************************************}
  178. Function DriveIsRemote( n: TDriveNums ): Boolean; Assembler;
  179.      Asm
  180.       mov ax, $4409      (* IOCTL is drive remote function *)
  181.         mov bl, n
  182. {$IFDEF WINDOWS}
  183.     call Dos3Call
  184. {$ELSE}
  185.     int $21
  186. {$ENDIF}
  187.         mov ax, False   (* assume error, in which case we return false *) 
  188.         jc @error
  189.         and dx, $1000  (* remote drives have bit 12 set *)
  190.         jz @error
  191.         inc ax
  192.     @error:
  193.   End; (* DriveIsRemote *)
  194.  
  195. {************************************************************
  196.  * Function DriveIsRemapped
  197.  *
  198.  * Parameters:
  199.  *    n: the drive number to check, 1= A:, 2=B: etc.
  200.  * Returns:
  201.  *    TRUE, if the drive can be remapped, FALSE if not or if it is invalid.
  202.  * Description:
  203.  *    This function uses DOS IOCTL function $440E to check whether 
  204.  *    a drive can be remapped.
  205.  *    Should work for DOS, Windows, and DPMI.
  206.  *
  207.  *Created: 02/26/95 21:21:46 by P. Below
  208.  ************************************************************}
  209. Function DriveIsRemapped( n: TDriveNums ): Boolean; Assembler;
  210.   Asm
  211.       mov ax, $440E      (* IOCTL get logical drive mapping function *)
  212.         mov bl, n
  213. {$IFDEF WINDOWS}
  214.     call Dos3Call
  215. {$ELSE}
  216.     int $21
  217. {$ENDIF}
  218.         jc @error
  219.         cmp al, 0       (* if carry not set, ax returns last drive number *)
  220.         je @error       (* of the mapped drive, or 0, if the block device has *)
  221.         mov ax, True    (* only one drive assigned to it.  *)
  222.         jmp @done
  223.     @error:
  224.       mov ax, false
  225.     @done:
  226.   End; (* DriveIsRemapped *)
  227.  
  228. {************************************************************
  229.  * Function GetDriveMapping
  230.  *
  231.  * Parameters:
  232.  *    n: the drive number to check, 1= A:, 2=B: etc.
  233.  * Returns:
  234.  *    The logical drive number the drive is mapped to, or the number
  235.  *    passed in n, if the drive is not mapped or is invalid.
  236.  * Description:
  237.  *    This function uses DOS IOCTL function $440E to check whether 
  238.  *    a drive is remapped.
  239.  *    Should work for DOS, Windows, and DPMI.
  240.  * Error Conditions:
  241.  *    none
  242.  *Created: 02/26/95 21:21:46 by P. Below
  243.  ************************************************************}
  244. Function GetDriveMapping( n: TDriveNums ): TDriveNums; Assembler;
  245.   Asm
  246.       mov ax, $440E      (* IOCTL get logical drive mapping function *)
  247.         mov bl, n
  248. {$IFDEF WINDOWS}
  249.     call Dos3Call
  250. {$ELSE}
  251.     int $21
  252. {$ENDIF}
  253.         jc @error                (* if no error *)
  254.         or  al, al      (* check return, 0 means not remapped *)
  255.         jnz @done       (* if remapped, return mapped drive number *)
  256.     @error:
  257.       mov al, n       (* else return original drive number *)
  258.     xor ah, ah
  259.     @done:
  260.   End; (* GetDriveMapping *)
  261.  
  262. {************************************************************
  263.  * Procedure MapLogicalDrive
  264.  *
  265.  * Parameters:
  266.  *    n: the physical drive number to map, 1= A:, 2=B: etc.
  267.  * Description:
  268.  *    Uses DOS IOCTL function $440F to map the physical drive
  269.  *    passed to the next logical drive number the block device
  270.  *    driver supports. Does nothing for drives that are not
  271.  *    mappable or invalid.
  272.  *    Use it with n=1 to map the floppy drive on a single floppy
  273.  *    system between A: and B:, use GetDriveMapping to check the
  274.  *    current mapping.
  275.  *    Should work for DOS, Windows, and DPMI.
  276.  *
  277.  *Created: 02/26/95 21:51:34 by P. Below
  278.  ************************************************************}
  279. Procedure MapLogicalDrive( n: TDriveNums ); assembler;
  280.   Asm
  281.      mov AX, $440F
  282.      mov BL, n
  283. {$IFDEF WINDOWS}
  284.      call Dos3Call
  285. {$ELSE}
  286.      int $21
  287. {$ENDIF}
  288.   End ;
  289.  
  290. Type
  291.   TMediaID = Record  (* This is the MS-DOS original MediaID structure *)
  292.     wInfoLevel: WORD;
  293.     dwSerialNumber: LongInt;
  294.     VolLabel: ARRAY [0..10] of Char;
  295.     FileSysType: ARRAY [0..7] of Char;
  296.   End;
  297.   PMediaID = ^TMediaID;
  298.  
  299. {************************************************************
  300.  * Function GetMediaID 
  301.  *
  302.  * Parameters:
  303.  *    Drive: 0 = default drive, 1 =A: etc.
  304.  *    Info : Record to receive the media id info, filled with 0
  305.  *           if function fails.
  306.  * Returns:
  307.  *    True if successful, False if error. 
  308.  * Description:
  309.  *    This function uses DOS IOCTL function $440D, subfunction $0866
  310.  *    to read the media ID record from the disks bootsector. For 
  311.  *    Windows, this requires use of DPMI.
  312.  *    Works for DOS and Windows, not tested for DPMI!
  313.  *
  314.  *Created: 02/26/95 21:44:02 by P. Below
  315.  ************************************************************}
  316. {$IFDEF WINDOWS}
  317.  (*************************************************************************
  318.  / GetMediaID() - Windows version
  319.  /
  320.  / Get Media ID by simulating an Int 21h, AX=440Dh, CX=0866h in real mode.
  321.  / Setup RealModeReg To contain a real mode pointer To a MediaID structure
  322.  /************************************************************************)
  323. Function GetMediaID ( Drive: Word; Var info: TDiskInfo ): Boolean;
  324.   Var
  325.     RealModeReg: TRealModeReg;
  326.     dwGlobalDosBuffer: LongInt;
  327.     lpRMMediaID: PMediaID;
  328.   Begin
  329.     GetMediaID := FALSE;
  330.     FillChar( info, Sizeof( info ), 0 );
  331.     { Get a real mode addressable buffer For the MediaID structure }
  332.  
  333.     dwGlobalDosBuffer := GlobalDosAlloc(sizeof(TMediaID));
  334.     If (dwGlobalDosBuffer <> 0) Then Begin
  335.  
  336.       { Now initialize the real mode register structure }
  337.       FillChar(RealModeReg, sizeof(RealModeReg), 0);
  338.       RealModeReg.rmEAX := $440D;           { IOCTL For Block Device }
  339.       RealModeReg.rmEBX := LongInt(Drive);  { 0 = default, 1 = A, 2 = B, etc. }
  340.       RealModeReg.rmECX := $0866;           { Get Media ID }
  341.       RealModeReg.rmDS  := HIWORD(dwGlobalDosBuffer);  { *real mode segment* }
  342.  
  343.       { Now simulate the real mode interrupt }
  344.       If RealInt($21, RealModeReg) and        { int simulation ok?}
  345.          ((RealModeReg.rmCPUFlags and $0001)=0) { carry clear? }
  346.       Then Begin
  347.          lpRMMediaID := PMEDIAID( MakeLong(0, LOWORD(dwGlobalDosBuffer)));
  348.          info.InfoLevel := lpRMMediaID^.wInfoLevel;
  349.          info.serialNo  := lpRMMediaID^.dwSerialNumber;
  350.          StrMove( info.volName, lpRMMediaID^.VolLabel, 11 );
  351.          StrMove( info.FATType, lpRMMediaID^.FileSysType, 8 );
  352.          GetMediaID := TRUE;
  353.       End;
  354.  
  355.       GlobalDosFree(LOWORD(dwGlobalDosBuffer));
  356.     End;
  357.   End;
  358. {$ELSE}
  359.  (*************************************************************************
  360.   | GetMediaID() - DOS version
  361.   |
  362.   |Get Media ID using Int 21h, AX=440Dh, CX=0866h in real mode.
  363.   |WARNING! Assumes DOS-Version > 4.0!
  364.   ************************************************************************)
  365. Function GetMediaID ( Drive: Word; Var info: TDiskInfo ): Boolean;
  366.   Label error;
  367.   Var
  368.     MediaID: TMediaID;
  369.   Begin
  370.     GetMediaID := FALSE;
  371.     FillChar( info, Sizeof( info ), 0 );
  372.         asm
  373.           push ds
  374.           mov ax, $440D;  { IOCTL For Block Device }
  375.             mov bx, Drive;  { 0 = default, 1 = A, 2 = B, etc. }
  376.       mov cx, $0866;  { Get Media ID }
  377.             mov dx, ss      { point ds:dx at MediaID }
  378.             mov ds, dx
  379.             lea dx, MediaID
  380.             int $21
  381.             pop ds
  382.             jc  error
  383.         End;
  384.     info.InfoLevel := MediaID.wInfoLevel;
  385.     info.serialNo  := MediaID.dwSerialNumber;
  386.     StrMove( @info.volName, @MediaID.VolLabel, 11 );
  387.     StrMove( @info.FATType, @MediaID.FileSysType, 8 );
  388.     GetMediaID := TRUE;
  389.     error:
  390.   End;
  391. {$ENDIF}
  392.  
  393.  
  394. {************************************************************
  395.  * Function MSCDExIsLoaded
  396.  *
  397.  * Parameters:
  398.  *    none
  399.  * Returns:
  400.  *    True, if MSCDEX is loaded, False otherwise
  401.  * Description:
  402.  *    Uses the MSCDEX Int $2F interface, function $00.
  403.  *    Should work for DOS, Windows, and DPMI.
  404.  *
  405.  *Created: 02/26/95 21:55:17 by P. Below
  406.  ************************************************************}
  407. Function MSCDExIsLoaded: Boolean; assembler;
  408.   Asm
  409.     mov AX, $1500   (* MSCDEX installed check *)
  410.     xor BX, BX
  411.     int $2F
  412.     xor ax, ax      (* set default return value To false *)
  413.     or  BX, BX      (* returns bx <> 0 If MSCDEX installed *)
  414.     jz  @no_mscdex
  415.     mov al, TRUE
  416.   @no_mscdex:
  417.   End;
  418.  
  419. {************************************************************
  420.  * Function DriveIsCDROM
  421.  *
  422.  * Parameters:
  423.  *    n: the drive number to check, 1= A:, 2=B: etc.
  424.  * Returns:
  425.  *    True, if the drive is a CD-ROM, False otherwise.
  426.  * Description:
  427.  *    Uses the MSCDEX Int $2F interface, function $0B.
  428.  *    It is not necessary to check for the presence of
  429.  *    MSCDEX first.
  430.  *    Should work for DOS, Windows, and DPMI.
  431.  *
  432.  *Created: 02/26/95 21:57:06 by P. Below
  433.  ************************************************************}
  434. Function DriveIsCDROM( n: TDriveNums ): Boolean; assembler;
  435.   Asm
  436.     mov ax, $150B (* MSCDEX check drive Function *)
  437.     mov cl, n
  438.     xor ch, ch
  439.     dec cx        (* 0 = A: etc.*)
  440.         xor bx, bx
  441.     int $2F
  442.         cmp bx, $ADAD (* is MSCDEX present? *) 
  443.         jne @no_cdrom
  444.     or  ax, ax
  445.     jz  @no_cdrom
  446.     mov ax, True
  447.         jmp @done
  448.   @no_cdrom:
  449.       mov ax, False
  450.     @done:
  451.   End;
  452.  
  453. {$IFDEF WINDOWS}
  454. Procedure Beautify( s: PChar );
  455.   (* internal procedure, remove a dot from the volume name,
  456.      padd to 11 chars with blanks *)
  457.   Var
  458.     p: PChar;
  459.     i: Integer;
  460.   Begin
  461.     p := StrScan( s, '.' );
  462.     If p <> nil Then
  463.       StrMove( p, p+1, 4 );
  464.  
  465.     (* padd To 11 chars with blanks *)
  466.     i := StrLen( s );
  467.     While i < 11 Do Begin
  468.       StrCat( s, ' ' );
  469.       INC(i);
  470.     End;
  471.   End ;
  472. {$ELSE}
  473. Procedure Beautify( Var s: string );
  474.   (* internal procedure, remove a dot from the volume name,
  475.      padd to 11 chars with blanks *)
  476.   Var
  477.     i: Integer;
  478.   Begin
  479.     i := Pos( '.', s );
  480.     If i <> 0 Then
  481.       Delete( s, i, 1 );
  482.  
  483.     (* padd To 11 chars with blanks *)
  484.  
  485.     While Length(s) < 11 Do
  486.       s:= s + ' ';
  487.   End ;
  488. {$ENDIF}
  489.  
  490. {************************************************************
  491.  * Procedure GetNetworkShareName  [ NOT EXPORTED! ]
  492.  *
  493.  * Parameters:
  494.  *    n: the drive number, 1= A:, 2=B: etc.,  should be a network drive!
  495.  *    name: array of char to take the device name
  496.  * Description:
  497.  *    This is a internal helper procedure, it does not check its 
  498.  *  parameters. name will return an empty string, if the drive is
  499.  *    not a network drive.
  500.  *
  501.  *Created: 02/26/95 22:07:49 by P. Below
  502.  ************************************************************}
  503. Procedure GetNetworkShareName( n: TDriveNums; Var name: TDeviceName );
  504.   Var
  505.     Param: ARRAY [0..16] OF CHAR;
  506. {$IFNDEF WINDOWS}
  507.     Buf  : ARRAY [0..16] OF CHAR;
  508. {$ENDIF}
  509.     i    : Integer;
  510.   Begin
  511.     Param[0] := Chr( n - 1 + Ord('A'));
  512.     Param[1] := ':';
  513.     Param[2] := #0;
  514.     name [0] := #0;
  515.  
  516. {$IFDEF WINDOWS}
  517.     i := Sizeof( name );
  518.     WNetGetConnection( @Param, @name, @i );
  519. {$ELSE}
  520.     { for plain DOS we need a bit of work, using int 21h, function 5F02h,
  521.       "Get Assign-List Entry". This entails a search thru the list of all
  522.       entries. }
  523.         asm
  524.             push ds
  525.             push es
  526.             push si
  527.             push di
  528.           sub bx, bx           { bx holds the list index, starts with 0 }
  529.             mov ax, ss             { point ds:si at Buf }
  530.             mov ds, ax
  531.             lea si, Buf
  532.             les di, name         { point es:di at name }
  533.         @next:
  534.           sub cx, cx
  535.           mov ax, $5F02      { dos get redirection list entry function }
  536.             push bx            { save current index }
  537.             push bp            { Network Interrupts sez: dx,bp destroyed! }
  538.             int $21
  539.             pop bp
  540.             jc  @error
  541.             { we have an entry, compare its local name in Buf with the drive 
  542.               name in Param, but only if the type returned in bl is 4 (disk drive)}
  543.             cmp bl, 4
  544.             pop bx                    { restore index }
  545.             jne @next_bx      { try next if no disk drive }
  546.             mov ax, [ si ]    { else get drive letter + colon from Buf }
  547.             cmp ax, word ptr Param  { and compare to Param }
  548.             je  @done       { if equal, exit }
  549.         @next_bx:                    { else try next index }
  550.             inc bx
  551.             jmp @next
  552.         @error:
  553.           pop bx         { no match found or network not installed, clean  }
  554.           mov byte ptr es:[di], 0  { saved index from stack and return name='' }
  555.         @done:
  556.           pop di                 { restore all saved registers }
  557.             pop si
  558.             pop es
  559.             pop ds
  560.         End;  { Asm }
  561. {$ENDIF}
  562.   End ;
  563.  
  564. {************************************************************
  565.  * Procedure GetDiskInfo
  566.  *
  567.  * Parameters:
  568.  *    n: the drive number, 1= A:, 2=B: etc.
  569.  *    info: record to take the drive info
  570.  * Description:
  571.  *    Calls GetMediaID to read the info block from the disk boot
  572.  *    sector, then searches for the volume name. Will return with
  573.  *    a serial number of 0, if GetMediaID is not supported or the
  574.  *    drive is invalid or contains no disk.
  575.  *
  576.  *Created: 02/26/95 22:11:35 by P. Below
  577.  ************************************************************}
  578. Procedure GetDiskInfo( n: TDriveNums; Var info: TDiskInfo );
  579.   Var fake: Boolean;
  580. {$IFDEF WINDOWS}
  581.       oldsettings: Word;
  582. {$ENDIF}
  583.   Procedure DoItOldStyle;
  584.     Var
  585. {$IFDEF WINDOWS}
  586.       dinfo: TSearchRec;
  587.       s: ARRAY [0..fsFilename] of Char;
  588. {$ELSE}
  589.       dinfo: SearchRec;
  590.       s: PathStr;
  591. {$ENDIF}
  592.     Begin
  593. {$IFDEF WINDOWS}
  594.       StrCopy(s, '@:\*.*' );
  595.       s[0] := CHR( Ord( s[0] ) + n );
  596.       FindFirst( s, faVolumeID , dinfo );
  597.       If DosError = 0 Then Begin
  598.         Beautify( dinfo.Name );
  599.         StrCopy( info.volName, dinfo.Name );
  600.       End;
  601.       If fake Then Begin
  602.         StrCopy( info.FATType, 'FAT12   ');
  603.         info.serialNo := 0;
  604.       End;
  605. {$ELSE}
  606.       s := '@:\*.*';
  607.       s[1] := CHR( Ord( s[1] ) + n );
  608.       FindFirst( s, VolumeID , dinfo );
  609.       If DosError = 0 Then Begin
  610.         Beautify( dinfo.Name );
  611.         StrPCopy( info.volName, dinfo.Name );
  612.       End;
  613.       If fake Then Begin
  614.         StrPCopy( info.FATType, 'FAT12   ');
  615.         info.serialNo := 0;
  616.       End;
  617. {$ENDIF}
  618.     End ;
  619.   Begin
  620.         FillChar( info, Sizeof( info ), 0 );
  621. {$IFDEF WINDOWS}
  622.     oldsettings := SetErrorMode( SEM_FAILCRITICALERRORS );
  623. {$ENDIF}
  624.     (* check the DOS version  *)
  625.     If Lo( DosVersion ) >= 4 Then
  626.       fake := NOT GetMediaID( n, info )
  627.     Else
  628.       fake := TRUE;
  629.     (* we get the volume label thru the old-style method of directory
  630.        search because pre-DOS 5.x may not have it in the boot sector
  631.        and even later versions may either not have it (If the disk was
  632.        formatted by something other than DOS Format) or it may have been
  633.        changed with LABEL, which does not change the boot sector entry!
  634.     *)
  635.     DoItOldStyle;
  636. {$IFDEF WINDOWS}
  637.     SetErrorMode( oldsettings );
  638. {$ENDIF}
  639.   End ;
  640.  
  641. {************************************************************
  642.  * Procedure GetDriveName
  643.  *
  644.  * Parameters:
  645.  *    n: the drive number, 1= A:, 2=B: etc.
  646.  *    di: a drive info record that MUST have its flags field 
  647.  *        already filled by MyGetDriveType!
  648.  * Description:
  649.  *    Tries to obtain the volume info or netshare name for the
  650.  *    passed drive. Default names are used of the info cannot be
  651.  *    safely obtained because the drive handles removable media.
  652.  *
  653.  *Created: 02/26/95 22:22:28 by P. Below
  654.  ************************************************************}
  655. Procedure GetDriveName( n: TDriveNums; Var di: TDriveInfo );
  656.   Begin
  657.     FillChar( di.Info, SIZEOF( di.Info ), 0 );
  658.     If INVALID IN di.Flags Then
  659.       di.DevName[0] := #0
  660.     Else
  661.       If (FLOPPY IN di.Flags) OR (CD_ROM IN di.Flags) Then
  662.       (* don't try To get the volume name For removable media *)
  663.         If (REMOTE IN di.Flags) Then
  664.           StrCopy(di.DevName, ' -UNKNOWN- ')
  665.         Else
  666.           StrCopy(di.Info.volName,' -UNKNOWN- ')
  667.  
  668.       Else
  669.        If (REMOTE IN di.Flags) Then Begin
  670.          GetNetworkShareName( n, di.DevName );
  671.          If di.DevName[0] = #0 Then
  672.            StrCopy(di.DevName, ' -NETWORK- ')
  673.  
  674.        End
  675.        Else
  676.          GetDiskInfo( n, di.Info )
  677.   End;
  678.  
  679. {************************************************************
  680.  * Function GetDiskParameterBlock
  681.  *
  682.  * Parameters:
  683.  *    n: the drive number, 1= A:, 2=B: etc.
  684.  * Returns:
  685.  *    a pointer to the disk parameter bloc, or Nil, if the function
  686.  *    fails.
  687.  * Description:
  688.  *    Uses DOS int $21, function $32. This function fails in network
  689.  *    drives and it tries to actually read the disk. So If you try to
  690.  *    use it on drive that handles removable media, make preparations
  691.  *    to trap critical errors! 
  692.  *
  693.  *Created: 02/26/95 22:33:14 by P. Below
  694.  ************************************************************}
  695. Function GetDiskParameterBlock( drive: TDriveNums ): LP_DPB; Assembler;
  696.   (* return a far pointer to the requested drives disk parameter block.
  697.      This call is appearendly supported by the windows dos extender,
  698.      we get a valid selector back in ds. *)
  699.   Asm
  700.       push ds
  701.       mov DL, drive
  702.       mov AH, $32
  703. {$IFDEF WINDOWS}
  704.       call Dos3Call
  705. {$ELSE}
  706.       int $21
  707. {$ENDIF}
  708.       cmp AL, $0FF
  709.       jne @valid
  710.       (* run into an error somewhere, return nil *)
  711.       xor ax, ax
  712.             mov dx, ax
  713.       jmp @done
  714.     @valid:
  715.       mov ax, bx
  716.       mov dx, ds
  717.     @done:
  718.       pop ds
  719.   End;
  720.  
  721. {************************************************************
  722.  * Function DriveIsRamdisk
  723.  *
  724.  * Parameters:
  725.  *    n: the drive number, 1= A:, 2=B: etc. MUST be a fixed disk!
  726.  * Returns:
  727.  *    True, if the disk in question has only one FAT copy, False
  728.  *    otherwise.
  729.  * Description:
  730.  *    Tries to read the disks parameter block and checks the number
  731.  *    of FATs present. One FAT is taken to be a sign for a RAM disk.
  732.  *    This check is not bomb-proof! 
  733.  * Error Conditions:
  734.  *    If you call this function for a drive handling removable media,
  735.  *    be prepared to trap critical errors!
  736.  *
  737.  *Created: 02/26/95 22:35:42 by P. Below
  738.  ************************************************************}
  739. Function DriveIsRamdisk( n: TDriveNums ): Boolean;
  740.   Var
  741.     pDPB: LP_DPB;
  742.   Begin
  743.     DriveIsRamdisk := FALSE;
  744.     pDPB := GetDiskParameterBlock( n );
  745.     If pDPB <> NIL Then
  746.       If pDPB^.dpbFATCount = 1 Then
  747.         DriveIsRamdisk := TRUE;
  748.   End;
  749.  
  750. {************************************************************
  751.  * Procedure MyGetDriveType
  752.  *
  753.  * Parameters:
  754.  *    n: the drive number, 1= A:, 2=B: etc. 
  755.  *    f: set of flags that describes the drive filled by this procedure
  756.  * Description:
  757.  *    Tries to determine for the specified drive, whether it is valid,
  758.  *    holds removable media, is remote, remapped, a CD-ROM or RAM-disk.
  759.  *
  760.  *Created: 02/26/95 22:48:32 by P. Below
  761.  ************************************************************}
  762. Procedure MyGetDriveType( n: TDriveNums; Var f: TDTypeSet );
  763.   Var
  764.     dt: word;
  765.   Begin
  766.     f := [];
  767.     Include( f, MediumIsRemovable( n ));
  768.         If ( n=2 ) and DriveIsRemapped( 1 ) Then Begin
  769.           Include( f, REMAPPED );
  770.         End; { If }
  771.         If not ( INVALID In f ) Then Begin
  772.           If DriveIsRemote( n ) Then
  773.               Include( f, REMOTE );
  774.         If (REMOTE IN f) and DriveIsCDROM( n ) Then
  775.           Include( f, CD_ROM );
  776.         If ([HARDDISK, CD_ROM, REMOTE] * f)= [HARDDISK] Then
  777.           If DriveIsRamdisk( n ) Then
  778.           Include( f, RAMDISK );
  779.         End; { If }
  780.   End;
  781.  
  782. {************************************************************
  783.  * Procedure GetDriveInfo
  784.  *
  785.  * Parameters:
  786.  *    n: the drive number, 1= A:, 2=B: etc. 
  787.  *    di: record to take the drive type and volume/netshare info
  788.  * Description:
  789.  *    Uses other routines in this Unit do obtain info on the drive
  790.  *    in question. 
  791.  *
  792.  *Created: 02/26/95 22:53:43 by P. Below
  793.  ************************************************************}
  794. Procedure GetDriveInfo( n: TDriveNums; Var di: TDriveInfo );
  795.   Begin
  796.     MyGetDriveType( n, di.Flags );
  797.     GetDriveName( n, di );
  798.   End;
  799.  
  800. {************************************************************
  801.  * Procedure BuildDriveMap
  802.  *
  803.  * Parameters:
  804.  *    DMap: array of TDriveInfo records to take the info on all
  805.  *          drives on the system.
  806.  * Description:
  807.  *    Uses other routines from this Unit to build a map of all
  808.  *    drives on the system with drive letters in the range 
  809.  *    A..Z ( logical drives 1..26 ). The map contains for each
  810.  *    drive a set of flags describing the drive type and also,
  811.  *  if the drive is valid and does not handle removable media,
  812.  *    the media id info ( volume name, serial number, FAT type ) or
  813.  *    netshare name.
  814.  *
  815.  *Created: 02/26/95 22:55:50 by P. Below
  816.  ************************************************************}
  817. Procedure BuildDriveMap( Var DMap: TDriveMap );
  818.   Var
  819.     n : TDriveNums;
  820.   Begin
  821.     (* build a drive properties map For all possible drives.
  822.        CAVEAT! DR-DOS 6.x has a bug that will fail IOCTL calls For
  823.                drive letters > P:! (Thank's To Ray Tackett [76416,276]
  824.                For this info) *)
  825.     For n := Min_DriveNums To Max_DriveNums Do Begin
  826.       MyGetDriveType( n, DMap[n].Flags );
  827.       GetDriveName( n, DMap[n] );
  828.         End;
  829.   End ;
  830.  
  831. {************************************************************
  832.  * Function GetLastdrive
  833.  *
  834.  * Parameters:
  835.  *    none
  836.  * Returns:
  837.  *    the logical drive number ( 1=A: etc. ) for the last valid
  838.  *    drive on the system.
  839.  * Description:
  840.  *    Uses DOS int $21, function $0E. On some systems this may just
  841.  *    return the LASTDRIVE setting in CONFIG.SYS!
  842.  *
  843.  *Created: 02/26/95 22:59:12 by P. Below
  844.  ************************************************************}
  845. Function GetLastdrive: TDriveNums; assembler;
  846.     asm
  847.       mov ah, $19   (* get current drive *)
  848.         int $21
  849.       mov ah, $E    (* set current To same *)
  850.         mov dl, al
  851.         int $21       (* al returns highest valid drivenumber, 1=A: etc. *)
  852.         sub ah, ah
  853.   End;
  854.  
  855. End.
  856.