delphidrive-letter

Get valid drive letter and is occupied


I want scan all available drive letter that exist on my computer, and get detail with it (chk if occupied, chk for type and size).

I have no problem about how to get size by using the codes bellow

var
  FreeAvail, totalSpace: Int64;
begin
  if SysUtils.GetDiskFreeSpaceEx(PChar('F:\'), FreeAvail, totalSpace, nil) = True
  then
  begin
    F1.Liner('Drive F total space ');
    F1.pBold(IntToStr(totalSpace div (1024 * 1024 * 1024)) + ' GB ,');
    F1.Liner(' available free space ');
    F1.pBold(IntToStr(FreeAvail div (1024 * 1024 * 1024)) + ' GB.');
  end;
end;

But if the drive is unoccupied, i don't like this situation.

error message if no media

Question: How to get available ALL drive(s) - CDROM, USB Stick, etc. To be more specific, i want the display result like this example;

Drive E [Local Disk] - TotalSpace 500 GB - FreeSpace 200 GB

Drive F [CD Drive] - Unoccupied - FreeSpace 0

Drive G [Removable] - TotalSpace 8 GB - FreeSpace 2 GB


Solution

  • I've provided a couple of functions that might help. The first uses the Win32 API function GetLogicalDriveStrings to retrieve a list of the assigned drive letters on the computer. The second queries a drive to see if it's ready for use (has a disk in it). (There's also a utility function that converts a drive letter to the integer value needed for DiskSize, the old Pascal I/O function.)

    The code has worked since Win95 days, and was just tested on Win7 64-bit in a Delphi 2007 console application. There's a console test application included below.

    program Project2;
    
    {$APPTYPE CONSOLE}
    
    uses
      SysUtils, Windows, Types;
    
    // Returns an array filled wit the assigned
    // drive letters on the current computer.
    function  GetDriveList: TStringDynArray;
    var
      Buff: array[0..128] of Char;
      ptr: PChar;
      Idx: Integer;
    begin
      if (GetLogicalDriveStrings(Length(Buff), Buff) = 0) then
        RaiseLastOSError;
      // There can't be more than 26 lettered drives (A..Z).
      SetLength(Result, 26);      
    
      Idx := 0;
      ptr := @Buff;
      while StrLen(ptr) > 0 do
      begin
        Result[Idx] := ptr;
        ptr := StrEnd(ptr);
        Inc(ptr);
        Inc(Idx);
      end;
      SetLength(Result, Idx);
    end;
    
    // Converts a drive letter into the integer drive #
    // required by DiskSize().
    function DOSDrive( const sDrive: String ): Integer;
    begin
      if (Length(sDrive) < 1) then
        Result := -1
      else
        Result := (Ord(UpCase(sDrive[1])) - 64);
    end;
    
    // Tests the status of a drive to see if it's ready
    // to access. 
    function DriveReady(const sDrive: String): Boolean;
    var
      ErrMode: Word;
    begin
      ErrMode := SetErrorMode(0);
      SetErrorMode(ErrMode or SEM_FAILCRITICALERRORS);
      try
        Result := (DiskSize(DOSDrive(sDrive)) > -1);
      finally
        SetErrorMode(ErrMode);
      end;
    end;
    
    // Demonstrates using the above functions.
    var
      DrivesArray: TStringDynArray;
      Drive: string;
    const
      StatusStr = 'Drive %s is ready: %s';
    begin
      DrivesArray := GetDriveList;
      for Drive in  DrivesArray do
        WriteLn(Format(StatusStr, [Drive, BoolToStr(DriveReady(Drive), True)]));
      ReadLn;
    end.
    

    Sample output when run on my system (Win7 64, two physical hard drives (C: and D:), an ISO device with no image mounted (E:), and a DVD drive (Z:).

    Drive C:\ is ready: True 
    Drive D:\ is ready: True 
    Drive E:\ is ready: False
    Drive Z:\ is ready: True