Lazarus

Free Pascal => Unix => Topic started by: bjlockie1 on November 19, 2020, 10:39:50 pm

Title: list Windows drive Letters (compile on Linux)
Post by: bjlockie1 on November 19, 2020, 10:39:50 pm
I am writing a file manager type app on Linux that also needs to run on Windows.
It is ok on Linux but I don't account for drive letters on Windows.
Is there a way to list available drive letters (instead of hard coding A: to Z:)?

I am using ChDir, is that going to change the drive?
Title: Re: list Windows drive Letters (compile on Linux)
Post by: Leledumbo on November 19, 2020, 10:45:58 pm
Guess you have to ifdef since drive letters is a Windows only concept. Windows API has GetLogicalDrives function that you can call, it will return a single LongWord / DWord value whose bits indicate whether the corresponding drive letter is assigned or not, i.e. bit 0 = drive A, bit 1 = drive B and so on.
Title: Re: list Windows drive Letters (compile on Linux)
Post by: Bart on November 19, 2020, 10:47:07 pm
Maybe take a look at TShellTreeView and see how the root node is populated?

Bart
Title: Re: list Windows drive Letters (compile on Linux)
Post by: Aidex on November 19, 2020, 10:57:56 pm
And if it is of interest what type each drive is, I recommend Windows.GetDriveType()

https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getdrivetypea
Title: Re: list Windows drive Letters (compile on Linux)
Post by: Remy Lebeau on November 20, 2020, 06:08:58 pm
Windows API has GetLogicalDrives function that you can call, it will return a single LongWord / DWord value whose bits indicate whether the corresponding drive letter is assigned or not

The API also has a GetLogicalDriveStrings() (https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getlogicaldrivestringsw) function, which returns each assigned drive letter in a '<letter>:\' string format, which can be passed as-is to any API that takes a drive root as input, including GetDriveType().
Title: Re: list Windows drive Letters (compile on Linux)
Post by: Bart on November 20, 2020, 06:22:35 pm
From one of my units:
Code: Pascal  [Select][+][-]
  1. function DiskInDrive(Drive: Char): Boolean;
  2. var
  3.   ErrorMode: word;
  4. begin
  5.   { maak er een hoofdletter van }
  6.   Drive := UpCase(Drive);
  7.   if not (Drive in ['A'..'Z']) then
  8.     raise EConvertError.Create('Geen geldige stationsaanduiding: '+Drive+':');
  9.   { schakel kritieke fouten uit }
  10.   ErrorMode := SetErrorMode(SEM_FailCriticalErrors);
  11.   try
  12.     { drive 1 = a, 2 = b, 3 = c, etc. }
  13.     if DiskSize(Ord(Drive) - Ord('A') + 1) = -1 then
  14.       Result := False
  15.     else
  16.       Result := True;
  17.   finally
  18.     { restore old error mode }
  19.     SetErrorMode(ErrorMode);
  20.   end;
  21. end;
  22.  
  23. function GetAvailableDrives(DiskMustBeInDrive: Boolean = False): TSysCharSet;
  24. var
  25.   D, Mask: DWORD;
  26.   C: Char;
  27. begin
  28.   Result := [];
  29.   D := GetLogicalDrives;
  30.   for C := 'A' to 'Z' do
  31.   begin
  32.     Mask := (1 shl (Ord(C) - Ord('A')));
  33.     if (Mask and D) = Mask then
  34.     begin
  35.       if (not DiskMustBeInDrive) or DiskInDrive(C) then
  36.       Include(Result, C);
  37.     end;
  38.   end;
  39. end;
  40.  

And from a unit that imlements a DriveCombobox:

Code: Pascal  [Select][+][-]
  1. type
  2.  
  3.   TDriveType = (dtUnknown, dtNoRootDir, dtRemovable, dtFixed, dtRemote, dtCdrom, dtRamDisk);
  4.   TDriveTypes = set of TDriveType;
  5.  
  6. function GetDriveType(ADrive: Char): TDriveType;
  7. var
  8.   WinDriveType: UINT;
  9. begin
  10.   WinDriveType := Windows.GetDriveType(PChar(LowerCase(ADrive+':\')));
  11.   case WinDriveType of
  12.     DRIVE_UNKNOWN: Result := dtUnknown;
  13.     DRIVE_NO_ROOT_DIR: Result := dtNoRootDir;
  14.     DRIVE_REMOVABLE: Result := dtRemovable;
  15.     DRIVE_FIXED: Result := dtFixed;
  16.     DRIVE_REMOTE: Result := dtRemote;
  17.     DRIVE_CDROM: Result := dtCdrom;
  18.     DRIVE_RAMDISK: Result := dtRamDisk;
  19.     else Result := dtUnknown;
  20.   end; //case
  21. end;
  22. //refreshs the drive list
  23. //FMountedDrivesOnly: if True then disk must be in drive
  24. //DriveTypes: a set of drivetypes you want in the list, so you can e.g. filter for only removable drives
  25.  
  26. procedure TFSICustomDriveComboBox.RefreshDriveList;
  27. var
  28.   C: Char;
  29.   ADriveType: TDriveType;
  30. begin
  31.   if (csDesigning in ComponentState) then
  32.     Exit;
  33.   Items.Clear;
  34.   for C in GetAvailableDrives(FMountedDrivesOnly) do
  35.   begin
  36.     ADriveType := GetDriveType(C);
  37.     if ADriveType in DriveTypes then
  38.       Items.Add(C + ':\');
  39.   end;
  40.   if FSelectFirstDriveOnRefreshDriveList and (not DroppedDown) and (Items.Count > -1) then
  41.     ItemIndex := 0;
  42. end;
  43.  

Bart
Title: Re: list Windows drive Letters (compile on Linux)
Post by: Sieben on November 20, 2020, 06:48:24 pm
Code: Pascal  [Select][+][-]
  1. ... and (Items.Count > -1)

?
Title: Re: list Windows drive Letters (compile on Linux)
Post by: Bart on November 20, 2020, 07:19:21 pm
Code: Pascal  [Select][+][-]
  1. ... and (Items.Count > -1)

?

Oops, must be > 0 of course.
Must have been confused with ItemIndex. Count of course can never be < 0.

Thanks.
Fixed in trunk.

Files reside here: https://svn.code.sf.net/p/flyingsheep/code/trunk/MijnLib
Units fsiwinutils and fsiwincontrols.

Bart
Title: Re: list Windows drive Letters (compile on Linux)
Post by: Sieben on November 20, 2020, 08:06:17 pm
Thanks for sharing. And Flying Sheep is one of my absolute favourites as well...  :)
Title: Re: list Windows drive Letters (compile on Linux)
Post by: Remy Lebeau on November 20, 2020, 09:17:25 pm
Code: Pascal  [Select][+][-]
  1. ErrorMode := SetErrorMode(SEM_FailCriticalErrors);

Just to point out that SetErrorMode() is global to the whole process and changing its mode introduces a race condition in multi-threaded code.  You really should be using SetThreadErrorMode() (https://docs.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-setthreaderrormode) instead.
Title: Re: list Windows drive Letters (compile on Linux)
Post by: bjlockie1 on November 20, 2020, 10:15:44 pm
Guess you have to ifdef since drive letters is a Windows only concept. Windows API has GetLogicalDrives function that you can call, it will return a single LongWord / DWord value whose bits indicate whether the corresponding drive letter is assigned or not, i.e. bit 0 = drive A, bit 1 = drive B and so on.

Thanks.
I have it compiling but it can't ChDir to drive D:\
C:\ and Z:\ work fine.

I'm going to post in the Windows forum.
I could wrap it in a try but I don't think drive D: should be listed.
Title: Re: list Windows drive Letters (compile on Linux)
Post by: lucamar on November 21, 2020, 12:33:23 am
I have it compiling but it can't ChDir to drive D:\
C:\ and Z:\ work fine.

That might be normal if drive D: is a CD-ROM but there is no CD in it, or a card-reader without card (or an unmounted card), or similar.
Title: Re: list Windows drive Letters (compile on Linux)
Post by: winni on November 21, 2020, 12:39:25 am
I have it compiling but it can't ChDir to drive D:\
C:\ and Z:\ work fine.

That might be normal if drive D: is a CD-ROM but there is no CD in it, or a card-reader without card (or an unmounted card), or similar.

Or D: is a Linux partition
Or D: is a not formatted partition
Or on D:  the filesystem is broken - Windows gives up very quick
Or D: is an external drive and you pulled the plug
Or or or ...

Winni
Title: Re: list Windows drive Letters (compile on Linux)
Post by: lucamar on November 21, 2020, 12:57:42 am
Or D: is a Linux partition
Or D: is a not formatted partition
...
Or D: is an external drive and you pulled the plug

In none of those cases (except maybe the "broken FS" one) do my Windows machines ever bother to assign a letter.

The general case I was thinking about is a removable-media drive which gets a letter assigned but fails if no media is loaded, like a CD/DVD drive or a card-reader; in that case and unless you have auto-run set on Windows frequently doesn't bother to ascertain whether there is any media at all until you try to access it (which caused me endless headaches with a 7-slot flash card reader: one never knew which letter Window assigned to each slot so I had to try all 7 until one deigned to respond  %)).

But I left Windows (except punctually 2K, XP, 7 and 10) on Vista times so I might be missing something :-[
Title: Re: list Windows drive Letters (compile on Linux)
Post by: winni on November 21, 2020, 02:03:03 am

In none of those cases (except maybe the "broken FS" one) do my Windows machines ever bother to assign a letter.


Hey,hey, hey - you lucky boy!

* Win7 asked me often, if it should format my Linux Partition !!! Somewhere in the Win-Jungle I disabled the partition.
Too long ago, don't know, where it was exactly.
* If you just pull the plug of an external drive and you don't inform the OS to "eject" it, you got a valid  drive letter - until you try the first time to read or write from/to that drive.
* If a network drive (Samba) does not react, but it was alive at boot times, Win is really insistent. It retries in an endless loop to reconnect. It shows a drive letter and the hourglass but not the directory. Until the end of all days. Or a reboot.

And so on.

Winni



Title: Re: list Windows drive Letters (compile on Linux)
Post by: lucamar on November 21, 2020, 05:28:26 am
Well, I don't know about the Samba one but neither of the other situations have ever happened to me: Win 7 leaves non-win partitions alone (as it should!) and if you just disconnect a device (say, a USB disk) it sometimes, as do Win10, complains about your lack of manners but is otherwise notified and frees up the volume letter.

I'm not much on Windows (and less each year, thank the gods) but some of my customers do and I've never heard about such problems. But then, again, that's not very representative: most of us as well as our customers are on Linux or other *nixen ... or on very ancient systems, but that's another story ;)
TinyPortal © 2005-2018