How to get volume information
by
, 27-Aug-2009 at 08:31 AM (12869 Views)
Always wanted to know what drives are available in your computer? Wanted to know what the status of the drive is? Wanted to know the serialnumber (e.g. 503E-A401)? Wanted to know is filename casing preserved? No... then go to the next blog. Yes, read on...
Drives
Visual DataFlex has a command called GetDskInfo. You pass it an integer and because drives can be assigned to a drive letter there is a maximum of 26 drives. So we can make a loop through all the drives. In the following code this is done inside the event OnCreateTree of an TreeView object.
As you can see we add 64 to the drive number to get the drive letter. If the drive does not exists (no Net Use or Subst) the drive status will be Drive_Root_Not_Exist. The treeview therefor only shows the drives available.Code:Procedure OnCreateTree Integer iDrive iDriveStatus String sDrive Handle hItem For iDrive from 1 to 26 GetDskInfo iDrive iDriveStatus If (iDriveStatus <> Drive_root_not_exist) Begin Move (Character (iDrive + 64) - ":") to sDrive Get AddTreeItem sDrive 0 iDrive 0 0 to hItem End Loop End_Procedure
When the user navigates through a treeview the event OnItemChanged fires and we can use this to start a process of querying the drive/volume information. In my sample application I decided to show the information in a RichEdit object because I can make certain information bold in a control of this class.
Windows API FunctionCode:Procedure OnItemChanged Handle hItem Handle hItemOld String sRootPath Integer iDrive Get ItemLabel hItem to sRootPath Get ItemData hItem to iDrive Send ShowVolumeInfo of oVolumeInfoRichEdit (sRootPath - '\') iDrive End_Procedure
For the information about a volume we can use the GetVolumeInformation Windows API function. We declare (import) the function with the following instruction;
The names of the arguments are not important but are pretty much equal to what the Window API documentation lists.Code:External_Function GetVolInfo "GetVolumeInformationA" Kernel32.Dll; Address aRoot Address aVName Integer nVNameSize Address aVSerNum ; Address aMaxCLen Address aFSysFlag Address aFSysName ; Integer nFSysNameSize Returns Integer
Using the function is done with:
Some of the parameters are defined as "__out" which means that the function call will write its information in the memory allocated for that parameter. Instead of passing the variable we pass the AddressOf() the variable, the memory location. To obtain memory location of a variable the variable needs to be initialized or in case of the strings have the space available to write the information back into. The following code does that:Code:Move (GetVolInfo (AddressOf (sRootPathName), AddressOf (sVolumeNameBuffer), ; (MAX_PATH+1), AddressOf (iSerialNumber), AddressOf (iMaximumComponentLength), ; AddressOf (iFileSystemFlags), AddressOf (sFileSystemName), (MAX_PATH+1))) ; to iResult
Of course to be called before the GetVolInfo() is executed!Code:ZeroString (MAX_PATH+1) to sVolumeNameBuffer ZeroString (MAX_PATH+1) to sFileSystemName Move 0 to iSerialNumber Move 0 to iMaximumComponentLength Move 0 to iFileSystemFlags
Show the Results
As mentioned before I created a cRichEdit object to show the information. The method to get the volume information is also coded inside this object. To show the information as illustrated below we have to toggle the pbBold boolean property to true and false before and after adding information. Instead of writing many lines of code I added a method called AppendTextBold to the RichEdit object. You could also add it to a subclass if you were planning to use this more often.
The Windows API function returns some strings that we can simply add to the editor control with a line like:Code:Procedure AppendBoldText String sText Set pbBold to True Send AppendText sText Set pbBold to False End_Procedure
but it also contains integer values like the flags (iFileSystemFlags) and an integer that represent the volume's serialnumber.Code:Send AppendText "VolumeName: " Send AppendBoldText (Cstring (sVolumeNameBuffer)) Send AppendTextLn " "
We can use the IsFlagIn() function to find out if a certain flag has been set. I used a slightly modified version that returns the words "true" and "false" because they are easier to understand for someone that looks at the picture. The code for that is:
The serialnumber is usually shown as a hexadecimal value in 2 groups of 4 characters. We use a function named Dec2Hex written a long time ago for DFCONFIG.Code:Function FlagStatus Integer iFlag Integer iFlags Returns String If (IsFlagIn (iFlag, iFlags)) Begin Function_Return "True" End Function_Return "False" End_Function
The serial number we split with the folded integer splitting functions Hi() and Low(). So the code is:Code:Function Dec2Hex Global Integer iDec Returns String String sHex Repeat Move (Insert (Mid ("0123456789ABCDEF", 1, ((iDec iand |CI$0F) + 1)), sHex, 1)) to sHex Move (iDec / |CI$10) to iDec Until (iDec = 0) Function_Return (Right (Trim ("0000" - sHex), 4)) End_Function
The full source is:Code:(Dec2Hex (Hi (iSerialNumber)))
Code:Use Windows.pkg Use Dll.pkg Use cApplication.pkg Use dfTreeVw.pkg Use cRichEdit.pkg Object oApplication is a cApplication End_Object Function Dec2Hex Global Integer iDec Returns String String sHex Repeat Move (Insert (Mid ("0123456789ABCDEF", 1, ((iDec iand |CI$0F) + 1)), sHex, 1)) to sHex Move (iDec / |CI$10) to iDec Until (iDec = 0) Function_Return (Right (Trim ("0000" - sHex), 4)) End_Function Function Hex2Dec Global String sHex Returns Integer Function_Return ("$" + Trim (sHex)) End_Function // 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 and FAT // does 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. Define FILE_CASE_SENSITIVE_SEARCH for |CI$00000001 Define FILE_CASE_PRESERVED_NAMES for |CI$00000002 Define FILE_UNICODE_ON_DISK for |CI$00000004 Define FILE_PERSISTENT_ACLS for |CI$00000008 Define FILE_FILE_COMPRESSION for |CI$00000010 Define FILE_VOLUME_IS_COMPRESSED for |CI$00008000 Define FS_CASE_IS_PRESERVED for FILE_CASE_PRESERVED_NAMES Define FS_CASE_SENSITIVE for FILE_CASE_SENSITIVE_SEARCH Define FS_UNICODE_STORED_ON_DISK for FILE_UNICODE_ON_DISK Define FS_PERSISTENT_ACLS for FILE_PERSISTENT_ACLS Define FS_VOL_IS_COMPRESSED for FILE_VOLUME_IS_COMPRESSED Define FS_FILE_COMPRESSION for FILE_FILE_COMPRESSION External_Function GetVolInfo "GetVolumeInformationA" Kernel32.Dll; Address aRoot Address aVName Integer nVNameSize Address aVSerNum Address aMaxCLen Address aFSysFlag Address aFSysName Integer nFSysNameSize Returns Integer Object oPanel is a BasicPanel Set Location to 3 3 Set Label to "Volume Information" Set Icon to "Default.Ico" Set Size to 267 410 Object oDrivesTreeView is a TreeView Set Size to 257 100 Set Location to 5 5 Set peAnchors to anTopBottomLeft Procedure OnCreateTree Integer iDrive iDriveStatus String sDrive Handle hItem For iDrive from 1 to 26 GetDskInfo iDrive iDriveStatus If (iDriveStatus <> Drive_root_not_exist) Begin Move (Character (iDrive + 64) - ":") to sDrive Get AddTreeItem sDrive 0 iDrive 0 0 to hItem End Loop End_Procedure Procedure OnItemChanged Handle hItem Handle hItemOld String sRootPath Integer iDrive Get ItemLabel hItem to sRootPath Get ItemData hItem to iDrive Send ShowVolumeInfo of oVolumeInfoRichEdit (sRootPath - '\') iDrive End_Procedure End_Object Object oVolumeInfoRichEdit is a cRichEdit Set Size to 257 296 Set Location to 5 110 Set peAnchors to anAll Procedure AppendBoldText String sText Set pbBold to True Send AppendText sText Set pbBold to False End_Procedure Function FlagStatus Integer iFlag Integer iFlags Returns String If (IsFlagIn (iFlag, iFlags)) Begin Function_Return "True" End Function_Return "False" End_Function Procedure ShowVolumeInfo String sRootPathName Integer iDrive Integer iSerialNumber iMaximumComponentLength iFileSystemFlags String sVolumeNameBuffer sFileSystemName sDriveStatus Integer iResult iDriveStatus ZeroString (MAX_PATH+1) to sVolumeNameBuffer ZeroString (MAX_PATH+1) to sFileSystemName Move 0 to iSerialNumber Move 0 to iMaximumComponentLength Move 0 to iFileSystemFlags Move (GetVolInfo (AddressOf (sRootPathName), AddressOf (sVolumeNameBuffer), (MAX_PATH+1), ; AddressOf (iSerialNumber), AddressOf (iMaximumComponentLength), AddressOf (iFileSystemFlags), ; AddressOf (sFileSystemName), (MAX_PATH+1))) to iResult Send Delete_Data GetDskInfo iDrive iDriveStatus Case Begin Case (iDriveStatus = Drive_not_available) Move "Drive not available" to sDriveStatus Case Break Case (iDriveStatus = Drive_removable) Move "Drive is Removable" to sDriveStatus Case Break Case (iDriveStatus = Drive_fixed) Move "Drive is Fixed" to sDriveStatus Case Break Case (iDriveStatus = Drive_remote) Move "Drive is Remote" to sDriveStatus Case Break Case (iDriveStatus = Drive_cdrom) Move "Drive is CDROM" to sDriveStatus Case Break Case (iDriveStatus = Drive_ramdisk) Move "Drive is RAM Disk" to sDriveStatus Case Break Case End Send AppendText "Drive:" Send AppendBoldText (String (iDrive) * sRootPathName * sDriveStatus) Send AppendTextLn " " If (iResult = 1) Begin Send AppendText "VolumeName: " Send AppendBoldText (Cstring (sVolumeNameBuffer)) Send AppendTextLn " " Send AppendText "VolumeSerialNumber: " Send AppendBoldText (Dec2Hex (Hi (iSerialNumber)) - "-" - Dec2Hex (Low (iSerialNumber))) Send AppendTextLn " " Send AppendText "MaximumComponentLength: " Send AppendBoldText iMaximumComponentLength Send AppendTextLn " " Send AppendText "FS_CASE_IS_PRESERVED: " Send AppendBoldText (FlagStatus (Self, FS_CASE_IS_PRESERVED, iFileSystemFlags)) Send AppendTextLn " " Send AppendText "FS_CASE_SENSITIVE: " Send AppendBoldText (FlagStatus (Self, FS_CASE_SENSITIVE, iFileSystemFlags)) Send AppendTextLn " " Send AppendText "FS_UNICODE_STORED_ON_DISK: " Send AppendBoldText (FlagStatus (Self, FS_UNICODE_STORED_ON_DISK, iFileSystemFlags)) Send AppendTextLn " " Send AppendText "FS_PERSISTENT_ACLS: " Send AppendBoldText (FlagStatus (Self, FS_PERSISTENT_ACLS, iFileSystemFlags)) Send AppendTextLn " " Send AppendText "FS_VOL_IS_COMPRESSED: " Send AppendBoldText (FlagStatus (Self, FS_VOL_IS_COMPRESSED, iFileSystemFlags)) Send AppendTextLn " " Send AppendText "FS_FILE_COMPRESSION: " Send AppendBoldText (FlagStatus (Self, FS_FILE_COMPRESSION, iFileSystemFlags)) Send AppendTextLn " " Send AppendText "FileSystemName: " Send AppendBoldText (Cstring (sFileSystemName)) Send AppendTextLn " " End End_Procedure End_Object End_Object Start_UI oPanel