用VB獲得大容量硬盤信息

字號:

這是為什么呢?熟悉Win32 API編程的人都知道,在用VB編程時,我們可以用相應的API函數(shù)來獲得有關系統(tǒng)的硬盤的信息,會不會是錯在API的調用函數(shù)呢?想到這里我用自編的程序來查看PC Alert的有關文件,發(fā)現(xiàn)其調用了GetDiskFreeSpace函數(shù),問題就出在這個函數(shù)上。下面是該函數(shù)的參數(shù)說明:Byval lpRootPathName As String(為欲查看的分區(qū)的根路徑如C:\) ,lpSectorsPerCluster As Long(為一簇的扇區(qū)數(shù)), lPBytesPerSector As Long(為每一扇區(qū)的字節(jié)數(shù)), lpNumberOfFreeClusters As Long(當前分區(qū)中未使用的簇數(shù)), lpTotalNumberOfClusters As Long(總的簇數(shù)) As Long。當我們調用此函數(shù)時,是以lpBytesPerSector×lpSectorsPerCluster×TotalNumberOfClusters來計算分區(qū)總的大小的,在VB中我用來查看自己的C盤時返回值分別為512 、64、 65526,因而計算出的C盤的大小只有2.05G。
    以下是關于MSDN中的有關詳細說明:對于大于的2G分區(qū),GetDiskFreeSpace函數(shù)可能(什么可能,是一定!)返回錯誤的值,此時函數(shù)會屏蔽存在lpNumberOfFreeClusters及l(fā)pTotalNumberOfClusters中的值,因此建議不要用該函數(shù)來獲得大于2G分區(qū)的信息。對于大于2G的分區(qū)應當使用GetDiskFreeSpaceEx函數(shù)(從Win95 OEM OSR2開始),此函數(shù)可以返回分區(qū)的有關正確信息。
    找到了問題所在便可以對癥下藥了,即用GetDiskFreeSpaceEx函數(shù)代替GetDiskFreeSpace函數(shù)即可。以下是GetDiskFreeSpaceEx函數(shù)中所要傳遞增的參數(shù)
    lpRootPathName String ,不包括卷名的磁盤根路徑名
    lpFreeBytesAvailableToCaller LARGE_INTEGER,指定一個變量,用于容納調用者可用的字節(jié)數(shù)量
    lpTotalNumberOfBytes LARGE_INTEGER ,指定一個變量,用于容納磁盤上的總字節(jié)數(shù)
    lpTotalNumberOfFreeBytes LARGE_INTEGER,指定一個變量,用于容納磁盤上可用的字節(jié)數(shù)
    Private Type LARGE_INTEGER
    lowpart As Long
    highpart As Long
    End Type
    我們可以看到LARGE_INTEGER是一個由兩個long型組成的一個類型,兩個long組成表示的都是無符號的數(shù),在轉換時應當定義一個single型的變量,使其等于highpart*(2^32-1) + lowpart,注意此處的兩個long型相當于C/C++中的無符號型整數(shù)類型,因為在VB中不存在此種類型,故而在換算時要處理好轉換關系。我本人的做法是首先判斷l(xiāng)ong型變量的正負,如是正直接相乘,如是負則用2^32-1減去該值再相乘(具體算法詳見下面的代碼)。
    Option Explicit
    Private Type LARGE_INTEGER
    lowpart As Long
    highpart As Long
    End Type
    Private Declare Function GetDiskFreeSpace Lib "kernel32" Alias "GetDiskFreeSpaceA" (ByVal lpRootPathName As String, lpSectorsPerCluster As Long, lpBytesPerSector As Long, lpNumberOfFreeClusters As Long, lpTotalNumberOfClusters As Long) As Long
    Private Declare Function GetDiskFreeSpaceEx Lib "kernel32" Alias "GetDiskFreeSpaceExA" _
    (ByVal lpRootPathName As String, lpFreeBytesAvailableToCaller As LARGE_INTEGER, _
    lpTotalNumberOfBytes As LARGE_INTEGER, lpTotalNumberOfFreeBytes _
    As LARGE_INTEGER) As Long
    Private Sub Command1_Click()
    Dim lngSectors&
    Dim lngTotalCluster &
    Dim lngFreeCluster &
    Dim lngPerCluster &
    Dim lngperBytes &
    Dim lngSize#
    GetDiskFreeSpace "c:\", lngPerCluster, lngperBytes, lngFreeCluster, lngTotalCluster
    MsgBox CStr(lngTotalCluster * lngperBytes * lngPerCluster)
    Debug.Print lngTotalCluster, lngperBytes, lngPerCluster
    End Sub
    Private Type LARGE_INTEGER
    lowpart As Long
    highpart As Long
    End Type
    Private Declare Function GetDiskFreeSpace Lib "kernel32" Alias "GetDiskFreeSpaceA" (ByVal lpRootPathName As String, lpSectorsPerCluster As Long, lpBytesPerSector As Long, lpNumberOfFreeClusters As Long, lpTotalNumberOfClusters As Long) As Long