Source code for Issue Number 51

Copyright 1997-2000 by C&D Programming Corp. All Rights Reserved. Source code may not be reproduced except for use in a compiled executable. All rights reserved. If you would like to reprint any or all of this code please email us at info@codeoftheweek.com

Code of the Week Home


Source Code

Just paste this source code into a class module called cVolumeInfo and include it in your project.

'----------------------------------------------------------------------
'
'   Module Name:    cVolumeInfo
'   Written By:     C&D Programming Corp.
'   Create Date:    7/98, 8/98
'   Copyright:      Copyright 1998 by C&D Programming Corp.  Source
'                   code may not be reproduced except for use in a
'                   compiled executable.  All rights reserved.  If
'                   you would like to reprint any or all of this
'                   code please email us at info@codeoftheweek.com
'----------------------------------------------------------------------
Option Explicit

'
'   This API call allows us to gather volume information
'
Private Declare Function GetVolumeInformation Lib "KERNEL32" _
            Alias "GetVolumeInformationA" _
            (ByVal lpRootPathName As String, _
                ByVal lpVolumeNameBuffer As String, _
                ByVal nVolumeNameSize As Long, _
                lpVolumeSerialNumber As Long, _
                lpMaximumComponentLength As Long, _
                lpFileSystemFlags As Long, _
                ByVal lpFileSystemNameBuffer As String, _
                ByVal nFileSystemNameSize As Long) As Long


'
'   This enumerator contains the possible values returned by
'   GetDriveType
'
Public Enum eDriveTypes
    drvtype_Unknown = 1
    drvtype_Removable = 2
    drvtype_Fixed = 3           ' Hard Drive or Local Drive
    drvtype_Remote = 4
    drvtype_CDRom = 5
    drvtype_Ramdisk = 6
End Enum

'
'   This API call allows us determine what type of
'   we are looking at and to gather disk drive stats
'
Private Declare Function GetDriveType Lib "KERNEL32" _
                        Alias "GetDriveTypeA" _
                        (ByVal nDrive As String) As eDriveTypes

Private Declare Function GetDiskFreeSpace Lib "KERNEL32" _
            Alias "GetDiskFreeSpaceA" _
            (ByVal lpRootPathName As String, _
                lpSectorsPerCluster As Long, _
                lpBytesPerSector As Long, _
                lpFreeClusters As Long, _
                lpTotalClusters As Long) As Long

Dim msDrive As String
Dim msLabel As String
Dim mlSectorsPerCluster As Long
Dim mlBytesPerSector As Long
Dim mlFreeClusters As Long
Dim mlTotalClusters As Long

Public Property Get Drive() As String
    Drive = msDrive
End Property

Public Property Let Drive(sDrive As String)

    On Error GoTo Handler

    If Left(sDrive, 2) = "\\" Then
        Err.Raise 5, "cVolumeInfo.Drive", "Network drives are not supported in this version."
        Exit Property
    Else
        msDrive = Left(sDrive, 1) & ":\"
    End If
    ClearDriveInfo  ' to make sure the data gets refreshed when a
                    ' property used
    Exit Property

Handler:
    Err.Raise Err.Number, Err.Source, Err.Description
End Property

Public Property Get Label() As String
    GetVolumeLabel
    Label = msLabel
End Property

Private Sub GetVolumeLabel()
    Dim lRet As Long
    Dim sLabel As String
    Dim lLabelSize As Long
    Dim lSerialNumber As Long
    Dim lMaxComponentLen As Long
    Dim lFileSysFlags As Long
    Dim sFileSysName As String
    Dim lFileSysNameSize As Long
    Dim elDriveType As eDriveTypes

    elDriveType = GetDriveType(Drive)

    '
    ' don't include unknown drives and network drives
    '
    If elDriveType <> drvtype_Unknown And elDriveType <> drvtype_Remote Then
        sLabel = String$(64, 0)
        lLabelSize = 63
        lRet = GetVolumeInformation(Drive, sLabel, lLabelSize, lSerialNumber, _
                    lMaxComponentLen, lFileSysFlags, sFileSysName, lFileSysNameSize)
        Select Case Err.LastDllError
            Case 21
                msLabel = ""  ' device is not ready
            Case 111
                ' buffer for label not large enough.
            Case 0 ' success
                msLabel = Left(sLabel, lLabelSize)
            Case Else
                msLabel = ""
                Err.Raise Err.LastDllError, "cVolumeInfo.GetVolumeLabel", "API Error " & Err.LastDllError
        End Select
    Else
        msLabel = ""
    End If
End Sub
'
'   This routine returns True if the GetDiskSpace function
'   was called.  This allows the cache to avoid making additional
'   calls to the API to gather disk space information
'
Private Property Get GotData() As Boolean
    GotData = False                 ' assume we haven't retrieved the data
    If mlSectorsPerCluster = 0 Then ' if SectorsPerCluster are we probably
                                    ' did not retrieve the data
        GetDiskSpace                ' Get the data
        GotData = True              ' Assume we retrieved it ok.
    Else
        GotData = True              ' If SectorsPerCluster is non-zero, we
                                    ' already have the data, so don't get
                                    ' it again.  If you set the Drive
                                    ' property it will reset the
                                    ' necessary flags for making sure
                                    ' the data is retrieved.
    End If
End Property

Public Property Get SectorsPerCluster() As Long
    If GotData Then
        SectorsPerCluster = mlSectorsPerCluster
    End If
End Property

Public Property Get BytesPerSector() As Long
    If GotData Then
        BytesPerSector = mlBytesPerSector
    End If
End Property

Public Property Get FreeClusters() As Long
    If GotData Then
        FreeClusters = mlFreeClusters
    End If
End Property

Public Property Get TotalClusters() As Long
    If GotData Then
        TotalClusters = mlTotalClusters
    End If
End Property

Private Function GetDiskSpace() As Boolean
    Dim lStatus As Long

    lStatus = GetDiskFreeSpace(Drive, mlSectorsPerCluster, _
                                mlBytesPerSector, mlFreeClusters, _
                                mlTotalClusters)
    If lStatus = 0 Then     ' if failed, zero out counters
        ClearDriveInfo
        GetDiskSpace = True
    Else
        GetDiskSpace = False
    End If
End Function

Public Function TotalDiskSpace() As Double
    TotalDiskSpace = SectorsPerCluster * BytesPerSector * TotalClusters
End Function

Public Function FreeDiskSpace() As Double
    FreeDiskSpace = SectorsPerCluster * BytesPerSector * FreeClusters
End Function

Private Sub Class_Initialize()
    ClearDriveInfo
End Sub

Private Sub ClearDriveInfo()
    mlSectorsPerCluster = 0
    mlBytesPerSector = 0
    mlTotalClusters = 0
    mlFreeClusters = 0
End Sub