Monday, September 29, 2008

Get disk drive type with VB.NET

Sometimes you have to find disk drives of particular type. For example, you may have to search all removable disk drives or network mapped drives with VB.NET.

This sample shows how to check all drives and get their drive type, volume label and check if the drive is ready.

First, create a new standard WinForms project. Drop in a one button control and a one listbox control.

Import System.IO namespace

Imports System.IO

and then add the following declaration and helper procedure after form's declaration

Public Declare Function WNetGetConnection Lib "mpr.dll" Alias "WNetGetConnectionA" _
 (ByVal lpszLocalName As String, ByVal lpszRemoteName As String, ByRef cbRemoteName As Integer) As Integer

Public Function GetNetDriveName(ByVal DriveLetter As String) As String
  '
  ' Return mapped drive UNC name
  Dim RetVal As Integer
  Dim OutName As String = New String(CChar(" "), 260)
  Dim NameLength As Integer = 260

  Try
    RetVal = WNetGetConnection(DriveLetter, OutName, NameLength)
    OutName = OutName.Replace(Chr(0), " ").TrimEnd(CChar(" "))
    Return OutName
  Catch ex As Exception
    Return ""
  End Try

End Function

Mpr.dll is a Windows module which handles communication with installed networked providers. In this case its used in the helper function above to get UNC-name for mapped network drives.

Next is the actual procedure which loops drive letters and returns available information.

Public Sub GetDrives(ByRef DriveLetter() As String, ByRef VolumeLabel() As String, _
  ByRef DriveTypeVal() As DriveType, ByRef PathToDrive() As String, _
  ByRef IsDriveReady() As Boolean)
  '
  ' Return available disc drives
  '
  Const DRIVELETTERS As String = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  Dim Info As DriveInfo
  Dim Count As Integer
  Dim i As Integer

  Try
    Count = DRIVELETTERS.Length - 1
    ReDim DriveLetter(Count)
    ReDim VolumeLabel(Count)
    ReDim DriveTypeVal(Count)
    ReDim PathToDrive(Count)
    ReDim IsDriveReady(Count)
    For i = 0 To Count
      DriveLetter(i) = DRIVELETTERS.Substring(i, 1)
      VolumeLabel(i) = ""
      DriveTypeVal(i) = DriveType.Unknown
      PathToDrive(i) = ""
      IsDriveReady(i) = False
    Next i
    For Each Info In My.Computer.FileSystem.Drives
      Count = DRIVELETTERS.IndexOf(Info.RootDirectory.FullName.Substring(0, 1))
      DriveTypeVal(Count) = Info.DriveType
      If Info.IsReady Then
        IsDriveReady(Count) = True
        VolumeLabel(Count) = Info.VolumeLabel
      Else
        IsDriveReady(Count) = False
        VolumeLabel(Count) = ""
      End If
      If Info.DriveType = DriveType.Network Then
        PathToDrive(Count) = GetNetDriveName(DriveLetter(Count) & ":")
      Else
        PathToDrive(Count) = DriveLetter(Count) & ":"
      End If
    Next Info
  Catch ex As Exception
    ' Error handling
  End Try

End Sub

And finally here's the code for Button1. The code call GetGrives-procedure and displays returned information in the ListBox1.

Private Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
  '
  ' Get drives and their types
  Dim DriveLetter() As String
  Dim VolumeLabel() As String
  Dim DriveTypeVal() As DriveType
  Dim PathToDrive() As String
  Dim IsDriveReady() As Boolean
  Dim TempStr As String
  Dim i As Integer

  Try
    ReDim DriveLetter(0)
    ReDim VolumeLabel(0)
    ReDim DriveTypeVal(0)
    ReDim PathToDrive(0)
    ReDim IsDriveReady(0)
    GetDrives(DriveLetter, VolumeLabel, DriveTypeVal, PathToDrive, IsDriveReady)
    ListBox1.Items.Clear()
    TempStr = "DriveLetter" & "; "
    TempStr = TempStr & "DriveType" & "; "
    TempStr = TempStr & "VolumeLabel" & "; "
    TempStr = TempStr & "PathToDrive" & "; "
    TempStr = TempStr & "IsDriveReady"
    ListBox1.Items.Add(TempStr)
    For i = 0 To DriveLetter.GetUpperBound(0)
      TempStr = DriveLetter(i) & "; "
      TempStr = TempStr & DriveTypeVal(i).ToString & "; "
      TempStr = TempStr & VolumeLabel(i) & "; "
      TempStr = TempStr & PathToDrive(i) & "; "
      TempStr = TempStr & IsDriveReady(i).ToString
      ListBox1.Items.Add(TempStr)
    Next i
  Catch ex As Exception
    ' Error handling
  End Try

End Sub

The output looks something like this:

DriveLetter; DriveType; VolumeLabel; PathToDrive; IsDriveReady
A; Removable; ; A:; False
B; Unknown; ; ; False
C; Fixed; ; C:; True
D; Fixed; New Volume; D:; True
E; CDRom; ; E:; False
F; Fixed; HD-HCU2; F:; True
G; Fixed; HD-HSU2; G:; True
H; Fixed; MAXTOR; H:; True
I; Removable; PORTABLEAPP; I:; True
J; Unknown; ; ; False
K; Unknown; ; ; False
L; Unknown; ; ; False
M; Unknown; ; ; False
N; Unknown; ; ; False
O; Unknown; ; ; False
P; Unknown; ; ; False
Q; Unknown; ; ; False
R; Unknown; ; ; False
S; Unknown; ; ; False
T; Unknown; ; ; False
U; Unknown; ; ; False
V; Unknown; ; ; False
W; Unknown; ; ; False
X; Unknown; ; ; False
Y; Unknown; ; ; False
Z; Network; Vista; \\Cameron\Public; True

The listing shows that drive A is a removable disk but its not ready (it's a floppy disk drive). Drives C, D, F, G and H are hard disk drives and drive C has no volume label. Drive E is a CD/DVD drive and drive I is also a removable drive (USB memory stick). And finally drive Z is a network mapped drive.

What can you do and do not with this information? First, the only USB drive is drive I because drive letters A and B are assigned to floppy disks even if you do not have one. Second, drive Z's volume label is "Vista" in the PC from which it is shared. The share name is \\Cameron\Public so the server's name is "Cameron" and the shared folder is "Public".

And there's a few things you won't get with this code. First, only two of the five fixed disk drives are internal drives and three drives are external had disk drives, but you can't tell which. At least for sure. Second, drive E is of type "CDRom" but it is actually a writable CD/DVD combo drive. But again, you can't tell the difference with this code.

Do more with DriveInfo class

Now that you know how to get this information. you may experience other properties that DriveInfo class offers. Here's a list of a few interesting properties:

  • Info.AvailableFreeSpace
  • Info.DriveFormat
  • Info.Name
  • Info.TotalFreeSpace
  • Info.TotalSize

Get drives of particular type with Visual Basic.NET

Here is a slight modification to the code above to make it more practical to use in VB.NET. This code gets the required drive type as parameter and returns only matching drives, if any. You may use this code to get only USB memory drives or network mapped drives for example.

Public Sub GetDrivesOfType(ByRef VolumeLabel() As String, _
  ByRef PathToDrive() As String, ByRef IsDriveReady() As Boolean, _
  ByVal DriveTypeVal As DriveType)
  '
  ' Return drives of given type
  Dim Info As DriveInfo
  Dim ThisLetter As Char
  Dim Count As Integer

  Try
    Count = 0
    For Each Info In My.Computer.FileSystem.Drives
      If Info.DriveType = DriveTypeVal Then
        ReDim Preserve VolumeLabel(Count)
        ReDim Preserve PathToDrive(Count)
        ReDim Preserve IsDriveReady(Count)
        ThisLetter = CChar(Info.RootDirectory.FullName.Substring(0, 1))
        If Info.IsReady Then
          IsDriveReady(Count) = True
          VolumeLabel(Count) = Info.VolumeLabel
        Else
          IsDriveReady(Count) = False
          VolumeLabel(Count) = ""
        End If
        If Info.DriveType = DriveType.Network Then
          PathToDrive(Count) = GetNetDriveName(ThisLetter & ":")
        Else
          PathToDrive(Count) = ThisLetter & ":"
        End If
        Count += 1
      End If
    Next Info
  Catch ex As Exception
    ' Error handling
  End Try

End Sub

and you call this procedure:

ReDim VolumeLabel(0)
ReDim PathToDrive(0)
ReDim IsDriveReady(0)
GetDrivesOfType(VolumeLabel, PathToDrive, IsDriveReady, DriveType.Removable)

to get all removable drives. If you want to get only USB memory sticks, remember that drives A and B are floppy disks. The output, if you use similar ListBox output as above, would look like this:

VolumeLabel; PathToDrive; IsDriveReady
; A:; False
PORTABLEAPP; I:; True

So, the only USB stick drive would have a drive letter "I".

5 comments:

Anonymous said...

This was a big help. Worked without modification and really saved me some time. Thanks from OKC!

√Čbeo® said...

Thanks! I used and works fine!

prasad said...

I logon to a server with RDP connection and from the server I want to see all the client drive mappings. but your code displays only server mapped drives and not the client drives mapped with \\tsclient\C

Your help will be much appreciated.

Teme64 said...

Yes it displays server (mapped) drives. Listing client mappings should be possible but not with this code. I don't have code for that right now so I suggest posting your question to some developer forum. For example http://www.daniweb.com has very skillful professionals answering the questions.

Anonymous said...

Thank you so much. This is one of the best examples I've ever used from the web. It's clean, clear and worked immediately, all of which is rare in my experience. Thank you again!