Get Internal Drives Using Windows.Storage Namespace in UWP

538 Views Asked by At

Having spent some time reading up on the Windows.Storage classes and methods, I'm a bit shocked to find that there is no simple way to retrieve a list of the internal drives on a machine using UWP. I've found examples such as this: How to get logical drives names in Windows 10?, but this provides the removable drives only (Flash drives, DVD drive, etc).

I know I can allow the user to select a folder and that'll provide me with the handle to the selected drive, but it seems clunky as I want the user to be able to run my software and scan the internal disks on the PC without having to re-select the drives every time.

I've added the broadFileSystemAccess attribute to the manifest so have access to the disks, I just can't call a method to get the internal drives. As a workaround, I've written the following method.

public List<StorageFolder> GetInternalDrives()
{
    string driveLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    int driveLettersLen = driveLetters.Length;
    string removableDriveLetters = "";
    string driveLetter;

    List<StorageFolder> drives = new List<StorageFolder>();
    StorageFolder removableDevices = KnownFolders.RemovableDevices;
    IReadOnlyList<StorageFolder> folders = Task.Run<IReadOnlyList<StorageFolder>>(async () => await removableDevices.GetFoldersAsync()).Result;

    foreach (StorageFolder removableDevice in folders)
    {
        if (string.IsNullOrEmpty(removableDevice.Path)) continue;
        driveLetter = removableDevice.Path.Substring(0, 1).ToUpper();
        if (driveLetters.IndexOf(driveLetter) > -1) removableDriveLetters += driveLetter;
    }

    for (int curDrive = 0; curDrive < driveLettersLen; curDrive++)
    {
        driveLetter = driveLetters.Substring(curDrive, 1);
        if (removableDriveLetters.IndexOf(driveLetter) > -1) continue;

        try
        {
            StorageFolder drive = Task.Run<StorageFolder>(async () => await StorageFolder.GetFolderFromPathAsync(driveLetter + ":")).Result;
            drives.Add(drive);
        }
        catch (System.AggregateException) { }

    }

    return drives;
}

And here's an example of GetInternalDrives being called:

List<StorageFolder> drives = GetInternalDrives();
panScanParams.Children.Clear();
foreach (StorageFolder drive in drives)
{
    CheckBox cb = new CheckBox();
    cb.Content = drive.DisplayName;
    cb.IsChecked = true;
    panScanParams.Children.Add(cb);
}

Whilst the code is only invoked once for an instance of the app, I'm not at all happy with the code. As it calls StorageFolder.GetFolderFromPathAsync for every letter of the alphabet, it crashes over 20 times on my machine. Writing code which you expect to fail and handling the exception just seems bad practice. But with the lack of a suitable alternative, I don't know what other options I have.

Has anyone tackled the same problem, and if so, what did you do to resolve it?

1

There are 1 best solutions below

1
On BEST ANSWER

Or you can try this code var driveLetters = DriveInfo.GetDrives().Select(x => x.RootDirectory.Root).ToList().OrderBy(x => x.Root.FullName).ToList(); to get drives instead of using StorageFolder method to exclude one by one. After that, traversing the resulting list and convert to StorageFolder. Below code I haven't removed removable drives.

var driveLetters = DriveInfo.GetDrives().Select(x => x.RootDirectory.Root).ToList().OrderBy(x => x.Root.FullName).ToList();
List<StorageFolder> drives = new List<StorageFolder>();
foreach (var driveInfo in driveLetters)
{
    String a = driveInfo.ToString();
    StorageFolder drive = Task.Run<StorageFolder>(async () => await StorageFolder.GetFolderFromPathAsync(a)).Result;
    drives.Add(drive);
}