#Include Once "windows.bi"

Type AllDrivesInfo
	'these 4 used in Scan
	As BOOL ScanChange
	As String DrvAdd 'drive letter added (USB or network)
	As String DrvRemove 'drive letter removed (USB or network)
	As String NewDisk 'drive letter that new disk inserted in "floppy" or "CD/DVD"
	'listing of available drive letters
	As String DriveList
	'
	Declare Constructor()
	Declare Sub Scan
	Declare Function GetDrvType(ByVal Drv As String) As Integer
	'
	'return individual info about Drive using GetVolumeInformation
	Declare Function DriveName(ByVal Drv As String) As String
	Declare Function DriveSerNum(ByVal Drv As String) As Integer
	Declare Function DriveSerNum62(ByVal Drv As String) As String 'old dos hex
	Declare Function DriveMaxFilenameLen(ByVal Drv As String) As Integer
	Declare Function DriveFlags(ByVal Drv As String) As Integer 'need worked on
	Declare Function DriveFileSystemType(ByVal Drv As String) As String
	Declare Function DriveHaveDisk(ByVal Drv As String) As Integer
	'
	'return individual info about drive using GetDiskFreeSpaceEx
	Declare Function DiskSpaceTotal(ByVal Drv As String) As ULongInt
	Declare Function DiskSpaceFree(ByVal Drv As String) As ULongInt
	Declare Function DiskSpaceAvail(ByVal Drv As String) As ULongInt
	'
	Private:
	As UInteger DriveMask
	As Integer SN(25) 'serial num of all drives
	Declare Function DiskSpacePrep(ByVal Drv As String) As Integer
End Type

Constructor AllDrivesInfo()
Dim As Integer x
'set up for use of Scan
DriveMask = GetLogicalDrives()
'only 26 letters
For x = 0 To 25
	If (DriveMask And 2^x) Then
		DriveList += Chr(65+x) 'uppercase
		SN(x) = DriveSerNum(Chr(65+x))
	EndIf
Next
End Constructor

Sub AllDrivesInfo.Scan
	Dim As UInteger ScanMask = GetLogicalDrives()
	Dim As Integer ScanF, DriveF, x
	Dim As String DriveL
	'
	'reset user flags
	ScanChange = FALSE
	DrvAdd = ""
	DrvRemove = ""
	NewDisk = "" 'this may be equal to DrvAdd
	'check for "drive" changes
	If ScanMask <> DriveMask Then
		'found "new" drive or drive no longer available
		ScanChange = TRUE
		'as long as you have a short wait time between scans, should only be one drive that changed.
		DriveList = ""
		For x = 0 To 25
			ScanF = ScanMask And 2^x
			DriveF = DriveMask And 2^x
			DriveL = Chr(65+x) 'uppercase
			If ScanF Then
				DriveList += DriveL
				'SN(x) = DriveSerNum(DriveL)
			EndIf
			If ScanF <> DriveF Then
				'this drive added/removed
				If ScanF Then
					DrvAdd += DriveL
				Else
					DrvRemove += DriveL
				EndIf
			EndIf
		Next
	EndIf
	'check for new disk
	For x = 0 To 25
		ScanF = DriveSerNum(Chr(65+x))
		If ScanF <> SN(x) Then
			'disk change
			NewDisk += Chr(65+x)
			SN(x) = ScanF
			ScanChange = TRUE
		EndIf
	Next
End Sub

'using GetVolumeInformation
Function AllDrivesInfo.DriveName(ByVal Drv As String) As String
	Dim As String DrvPath = Left(Drv,1)+":\"
	Dim As Integer GotData
	Dim As String DName
	'vars for API call
	Dim ZName As ZString * 150
	GotData = GetVolumeInformation(DrvPath,@ZName,150,NULL,NULL,NULL,NULL,NULL)
	If GotData Then DName = ZName
	Return DName
End Function

Function AllDrivesInfo.DriveSerNum(ByVal Drv As String) As Integer
	Dim As String DrvPath = Left(Drv,1)+":\"
	Dim As Integer GotData, SNum
	GotData = GetVolumeInformation(DrvPath,NULL,NULL,@SNum,NULL,NULL,NULL,NULL)
	Return SNum
End Function

Function AllDrivesInfo.DriveSerNum62(ByVal Drv As String) As String
	Dim As String HexSerNum
	Dim As Integer HexHalf
	'
	Dim As Integer GotData = DriveSerNum(Drv)
	'
	HexHalf = HiWord(GotData)
	HexSerNum = Hex(HexHalf,4)
	HexSerNum += "-"
	HexHalf = LoWord(GotData)
	HexSerNum += Hex(HexHalf,4)
	Return HexSerNum
End Function

Function AllDrivesInfo.DriveMaxFilenameLen(ByVal Drv As String) As Integer
	Dim As String DrvPath = Left(Drv,1)+":\"
	Dim As Integer GotData, SNum
	GotData = GetVolumeInformation(DrvPath,NULL,NULL,NULL,@SNum,NULL,NULL,NULL)
	Return SNum
End Function

'to work in
/'Flag definitions
Points to a doubleword that receives flags associated with the specified file system.
This parameter can be any combination of the following flags, with one exception: FS_FILE_COMPRESSION and FS_VOL_IS_COMPRESSED are mutually exclusive. 

Value	Meaning
FS_CASE_IS_PRESERVED	If this flag is set, the file system preserves the case of filenames when it places a name on disk.
FS_CASE_SENSITIVE	If this flag is set, the file system supports case-sensitive filenames.
FS_UNICODE_STORED_ON_DISK	If this flag is set, the file system supports Unicode in filenames as they appear on disk.
FS_PERSISTENT_ACLS	If this flag is set, the file system preserves and enforces ACLs. For example, NTFS preserves and enforces ACLs, HPFS and FAT do not. 
FS_FILE_COMPRESSION	The file system supports file-based compression.
FS_VOL_IS_COMPRESSED	The specified volume is a compressed volume; for example, a DoubleSpace volume.
'/
Function AllDrivesInfo.DriveFlags(ByVal Drv As String) As Integer
	Dim As String DrvPath = Left(Drv,1)+":\"
	Dim As Integer GotData, SNum
	GotData = GetVolumeInformation(DrvPath,NULL,NULL,NULL,NULL,@SNum,NULL,NULL)
	Return SNum
End Function

Function AllDrivesInfo.DriveFileSystemType(ByVal Drv As String) As String
	Dim As String DrvPath = Left(Drv,1)+":\"
	Dim As Integer GotData
	Dim As String FSType
	'vars for API call
	Dim ZName As ZString * 20
	GotData = GetVolumeInformation(DrvPath,NULL,NULL,NULL,NULL,NULL,@ZName,20)
	If GotData Then FSType = ZName
	Return FSType
End Function

Function AllDrivesInfo.DriveHaveDisk(ByVal Drv As String) As Integer
	'check for serial number
	Dim As Integer Ret, SN
	SN = DriveSerNum(Drv)
	If SN Then Return 1
	Return 0
End Function

Private Function AllDrivesInfo.DiskSpacePrep(ByVal Drv As String) As Integer
	Dim As String DrvPath = Left(Drv,1)+":\"
	Dim As Integer IsReady, DType
	'
	'can we access the data? "network"
	DType = GetDrvType(DrvPath) 'could have just used GetDriveType() but wanted a test
	If DType <> DRIVE_REMOVABLE And DType <> DRIVE_FIXED And DType <> DRIVE_CDROM Then Return 0
	'verify that drive has "disk"
	IsReady = DriveHaveDisk(Drv)
	Return IsReady
End Function

Function AllDrivesInfo.DiskSpaceTotal(ByVal Drv As String) As ULongInt
	'Dim As ULARGE_INTEGER V 'API USES THIS
	Dim As Integer GotData
	Dim As ULongInt R
	Dim As String DrvPath = Left(Drv,1)+":\"
	'
	'can we access?
	GotData = DiskSpacePrep(Drv)
	If GotData = 0 Then Return 0
	'Avail might be less than BFree if "quota" is enforced
	'GotData = GetDiskFreeSpaceEx(DrvPath, @Avail, @Total, @BFree)
	GotData = GetDiskFreeSpaceEx(DrvPath, NULL, Cast(ULARGE_INTEGER Ptr,@R), NULL)
	Return R
End Function

Function AllDrivesInfo.DiskSpaceFree(ByVal Drv As String) As ULongInt
	Dim As Integer GotData
	Dim As ULongInt R
	Dim As String DrvPath = Left(Drv,1)+":\"
	'
	'can we access?
	GotData = DiskSpacePrep(Drv)
	If GotData = 0 Then Return 0
	GotData = GetDiskFreeSpaceEx(DrvPath, NULL, NULL, Cast(ULARGE_INTEGER Ptr,@R))
	Return R
End Function

Function AllDrivesInfo.DiskSpaceAvail(ByVal Drv As String) As ULongInt
	Dim As Integer GotData
	Dim As ULongInt R
	Dim As String DrvPath = Left(Drv,1)+":\"
	'
	'can we access?
	GotData = DiskSpacePrep(Drv)
	If GotData = 0 Then Return 0
	GotData = GetDiskFreeSpaceEx(DrvPath, Cast(ULARGE_INTEGER Ptr,@R), NULL, NULL)
	Return R
End Function

Function AllDrivesInfo.GetDrvType(ByVal Drv As String) As Integer
	Dim As String DrvPath = Left(Drv,1)+":\"
	Return GetDriveType(DrvPath)
End Function

'test
'easier to comment one line or just delete below
'#Define AllDrivesInfo_Test 'comment to use in another module
#Ifdef AllDrivesInfo_Test
Dim As Integer ValidData
Dim As ULongInt DriveSize, FreeBytes
Dim As String NameOfDrive, FileSys

Dim MyDrives As AllDrivesInfo
Print MyDrives.DriveList
'individual functions to get "each" item only (re-using vars)
Print "Test of Individual functions"
NameOfDrive = MyDrives.DriveName("C")
Print "Disk C has the name of ";NameOfDrive
'
FileSys = MyDrives.DriveFileSystemType("C")
Print "and has a ";FileSys;" filing system"
'
ValidData = MyDrives.DriveSerNum("C")
Print "and it's serial number is: ";ValidData
'
NameOfDrive = MyDrives.DriveSerNum62("C")
Print "the old dos serial number would be ";NameOfDrive
'
ValidData = MyDrives.DriveMaxFilenameLen("C")
Print "Maximum lenth of a filename is ";ValidData
'
ValidData = MyDrives.DriveFlags("C")
'see note above function for details
Print "Flags --- ";ValidData
'
FreeBytes = MyDrives.DiskSpaceFree("C")
Print "Free space: ";FreeBytes
'
DriveSize = MyDrives.DiskSpaceTotal("C")
Print "Total space: ";DriveSize
Print
'
'NO DISK?
'drive E: is my CD/DVD
Print "CD drive ";
If MyDrives.DriveHaveDisk("E") Then
	Print "has a disk in it."
Else
	Print "is empty."
EndIf
DriveSize = MyDrives.DiskSpaceTotal("E")
Print "Total space: ";DriveSize

Sleep
FileSys = InKey 'erase keypress
'
'test of scanning for changes
Do
	Cls
	Print "Scan run at: ";Time
	MyDrives.Scan
	If MyDrives.ScanChange Then
		'drive added or removed
		If Len(MyDrives.NewDisk) = 0 Then Print "New listing of drive letters: ";MyDrives.DriveList
		If Len(MyDrives.DrvAdd) Then Print "Drive added: ";MyDrives.DrvAdd
		If Len(MyDrives.DrvRemove) Then Print "Drive removed: ";MyDrives.DrvRemove
		'
		If Len(MyDrives.NewDisk) Then Print "Disk changed: ";MyDrives.NewDisk
		'do updates main prg
		Print "Updating main prg"
		Sleep 2000
	EndIf
	'exit?
	FileSys = InKey
	If Len(FileSys) Then Exit Do
	Sleep 3000
Loop
#EndIf
