Get a list of physical disks and the partitions on them in VB.NET the easy way
Use DeviceIoControl, QueryDosDevice and WNetOpenEnum to get information about your system.
Introduction
Have you ever needed to know how many hard disks there are in the computer your app is running on? Which partitions are on which hard disks?
Which drives are network drives, and what their UNC paths may be? What the dos name and number of the CD/DVDRoms in the system may be?
In this example project you will find the class clsDiskInfoEx
- which is a compilation of code I use to accomplish these ends.
This code runs correctly on Windows 7, Vista, 2003 and XP.
Background
Recently I've been working on code to accomplish faster file copies in Windows. There are some 3rd party utilities, I know - but I wanted to be able to integrate this into my code. Eventually I found myself trying to figure out why concurrent reading and writing sometimes slowed things down. A little searching revealed the ugly truth - that reading and writing to the same hard drive concurrently was the problem. I set about trying to figure out which partitions were on the same hard drive to compensate, and this class was the result.
This code was not entirely written by me - jo0l's .NET stuff and pinvoke.net were great starting points, and if you haven't already you should check them out.
Using the code
clsDiskInfoEx
does quite a bit behind the scene, and has several useful methods. Instantiate it with new the way you normally would with any class.GetNetworkComputers
- Returns alist(Of String)
of the available computers in your network.GetNetworkDrives
- Returns alist(Of String)
of network drives and their UNC paths, separated by "=".GetUncPathOfMappedDrive
- I think this is self explanatory.GetPhysicalDisks
- returns alist(Of String)
of all the drives in the system and their respective parent device, be it an Physical disk, UNC path or dos CD Rom number formatted as follows: "C:=\\.\PhysicalDisk0"GetPhysicalDiskParentFor(logicalDisk As String) As String
- This is the one that gets all the use in this example project. When you instantiate the class, it fills an internal list with information about all the drives in your system. Feed this method the root directory of a drive (i.e.: "c:\") and it gives you the parent drive for that partition. To update the disk information (i.e.: someone plugged in a flash drive or inserted a CD), use theRefresh()
method.
Here's a quick look at the code that adds the drive information into a listview in the example project's main form:
Private Sub GetDriveInfo()
Dim count As Int32 = 0
Dim driveInfoEx As New clsDiskInfoEx
Dim multipleParents() As String = Nothing
Dim parentDrives As String = Nothing
lvDriveInfo.Items.Clear()
For Each drive As System.IO.DriveInfo In System.IO.DriveInfo.GetDrives
parentDrives = driveInfoEx.GetPhysicalDiskParentFor(drive.RootDirectory.ToString)
If parentDrives.Contains(", ") Then
' We have multiple parent drives:
multipleParents = Split(parentDrives, ", ")
' Enumerate them backwards so the lowest numbered drives are reported 1st
For more As Int32 = (multipleParents.Length - 1) To 0 Step -1
If more = (multipleParents.Length - 1) Then
lvDriveInfo.Items.Add("")
lvDriveInfo.Items(count).SubItems.Add(drive.RootDirectory.ToString.Replace("\", ""))
lvDriveInfo.Items(count).SubItems.Add(multipleParents(more)) ' Parent drive
lvDriveInfo.Items(count).SubItems.Add(drive.DriveType.ToString)
If drive.IsReady Then
lvDriveInfo.Items(count).SubItems.Add(drive.DriveFormat)
lvDriveInfo.Items(count).SubItems.Add((drive.TotalSize / 1000000).ToString("N0") & " MB")
lvDriveInfo.Items(count).SubItems.Add((drive.AvailableFreeSpace / 1000000).ToString("N0") & " MB")
Else
lvDriveInfo.Items(count).SubItems.Add("No Disc")
lvDriveInfo.Items(count).SubItems.Add("-")
lvDriveInfo.Items(count).SubItems.Add("-")
End If
Else
count += 1
lvDriveInfo.Items.Add("")
lvDriveInfo.Items(count).SubItems.Add(drive.RootDirectory.ToString.Replace("\", ""))
lvDriveInfo.Items(count).SubItems.Add(multipleParents(more)) ' Parent drive
lvDriveInfo.Items(count).SubItems.Add("Mirror or Span")
If drive.IsReady Then
lvDriveInfo.Items(count).SubItems.Add(drive.DriveFormat)
Else
lvDriveInfo.Items(count).SubItems.Add("")
End If
lvDriveInfo.Items(count).SubItems.Add("-")
lvDriveInfo.Items(count).SubItems.Add("-")
End If
Next
count += 1
Else
' Just one parent drive for this partition.
lvDriveInfo.Items.Add("")
lvDriveInfo.Items(count).SubItems.Add(drive.RootDirectory.ToString.Replace("\", ""))
lvDriveInfo.Items(count).SubItems.Add(parentDrives) ' Parent drive
lvDriveInfo.Items(count).SubItems.Add(drive.DriveType.ToString)
If drive.IsReady Then
lvDriveInfo.Items(count).SubItems.Add(drive.DriveFormat)
lvDriveInfo.Items(count).SubItems.Add((drive.TotalSize / 1000000).ToString("N0") & " MB")
lvDriveInfo.Items(count).SubItems.Add((drive.AvailableFreeSpace / 1000000).ToString("N0") & " MB")
Else
lvDriveInfo.Items(count).SubItems.Add("No Disc")
lvDriveInfo.Items(count).SubItems.Add("-")
lvDriveInfo.Items(count).SubItems.Add("-")
End If
count += 1
End If
Next
End Sub
Points of Interest
This class also correctly reports partitions that span drives, like mirrors, stripes or spanned volumes. However, it has only been tested in a machine with mirrored drives. If it behaves badly in systems with alternate configurations, I'd love to know it.