dualbrain
Junior Member
The only bug free code is code that is no longer used.
Posts: 51
|
Post by dualbrain on Dec 24, 2022 3:16:49 GMT
I'm attempting to utilize the GetDiskFreeSpaceExA api but am failing to get the right combination for the DECLARE and/or usage... any assistance with this would be appreciated. (I was able to GetDiskFreeSpaceA working; however, it apparently doesn't work on more modern computers with "larger drives" - thus the need to get the Ex version working.)
Thanks in advance.
|
|
|
Post by mdijkens on Dec 24, 2022 11:02:00 GMT
Declare Library Function GetDriveTypeA& (nDrive As String) Function GetLogicalDriveStringsA& (ByVal nBuff As Long, lpbuff As String) End Declare Declare Dynamic Library "Kernel32" Function GetVolumeInformationA& (Drive As String, Label As String, Byval nVol As Long, Byval Serial As _Offset, Byval Max As _Offset, Byval Flags As _Offset, Sys As String, Byval nSys As Long) Function GetDiskFreeSpaceA& (nDrive As String, Byval csectors As _Offset, Byval sbytes As _Offset, Byval cfree As _Offset, Byval ctotal As _Offset) End Declare
Dim Drive As String, DriveType As Long Drive = "C:\" + Chr$(0): DriveType = GetDriveTypeA(Drive)
Dim Label As String, Sys As String, ret As Long Dim Serial As Long, nMax As Long, nFlags As Long Label = Space$(20): Sys = Space$(20): ret = GetVolumeInformationA(Drive, Label, Len(Label), _Offset(Serial), _Offset(nMax), _Offset(nFlags), Sys, Len(Sys))
Dim csectors As Long, sbytes As Long, cfree As Long, ctotal As Long If ret > 0 Then ret = GetDiskFreeSpaceA(Drive, _Offset(csectors), _Offset(sbytes), _Offset(cfree), _Offset(ctotal)) If ret > 0 Then bpc~&& = csectors * sbytes Print "Size ="; ctotal * bpc~&& Print "VolumeName = "; Left$(Label, _InStrRev(Label, Chr$(0)) - 1) Print "Serial = "; Hex$(Serial) Print "DriveType = "; DriveType '0=unknown,1=NoRoot,2=Removable,3=Local,4=Network,5=CD,6=Ramdisk Print "FileSystem = "; Left$(Sys, _InStrRev(Sys, Chr$(0)) - 1) Print "FreeSpace = "; cfree * bpc~&& End If
|
|
|
Post by dcromley on Dec 24, 2022 17:00:26 GMT
> {code} What fabulous code! You should call yourself APIMAN! I took the liberty of turning your code into a subroutine.
THANKS!
Declare Library Function GetDriveTypeA& (nDrive As String) Function GetLogicalDriveStringsA& (ByVal nBuff As Long, lpbuff As String) End Declare Declare Dynamic Library "Kernel32" Function GetVolumeInformationA& ( _ Drive As String, Label As String, Byval nVol As Long, Byval Serial As _Offset, _ Byval Max As _Offset, Byval Flags As _Offset, Sys As String, Byval nSys As Long) Function GetDiskFreeSpaceA& (_ nDrive As String, Byval csectors As _Offset, Byval sbytes As _Offset, Byval cfree As _Offset, Byval ctotal As _Offset) End Declare
Screen _NewImage(1024, 768, 256) Call Sub1("C:\" + Chr$(0)) Call Sub1("D:\" + Chr$(0)) Call Sub1("E:\" + Chr$(0)) Call Sub1("X:\" + Chr$(0)) Call Sub1("Y:\" + Chr$(0)) Call Sub1("Z:\" + Chr$(0))
Sub Sub1 (Drive As String) Dim DriveType As Long Dim Label As String, Sys As String, ret As Long Dim Serial As Long, nMax As Long, nFlags As Long Dim csectors As Long, sbytes As Long, cfree As Long, ctotal As Long
DriveType = GetDriveTypeA(Drive) Label = Space$(20) Sys = Space$(20) ret = GetVolumeInformationA(Drive, Label, Len(Label), _Offset(Serial), _Offset(nMax), _Offset(nFlags), Sys, Len(Sys)) If ret > 0 Then ret = GetDiskFreeSpaceA(Drive, _Offset(csectors), _Offset(sbytes), _Offset(cfree), _Offset(ctotal)) If ret > 0 Then bpc~&& = csectors * sbytes sType$ = "Unknown NoRoot RemovableLocal Network CD Ramdisk " Print Drive Print "Size ="; Using "##,###,###,###,###"; ctotal * bpc~&& Print "VolumeName = "; Left$(Label, _InStrRev(Label, Chr$(0)) - 1) Print "Serial = "; Hex$(Serial) Print "DriveType = "; Mid$(sType$, DriveType * 9 + 1, 9) Print "FileSystem = "; Left$(Sys, _InStrRev(Sys, Chr$(0)) - 1) Print "FreeSpace = "; Using "##,###,###,###,###"; cfree * bpc~&& Print End If End Sub
|
|
dualbrain
Junior Member
The only bug free code is code that is no longer used.
Posts: 51
|
Post by dualbrain on Dec 26, 2022 18:33:21 GMT
Thanks for the replies; it's good to confirm that I was on the right track with these. There certainly does seem to be some confusion (at least on my part) as to when/where do you use String, Long, etc. versus _OFFSET. With all that out of the way, as I was explaining in my OP; I was able to get GetDiskFreeSpaceA working (as mentioned above); however, it doesn't appear to work with "large drive" (read: modern machines) and you are, instead, supposed to utilize the *replacement* GetDiskFreeSpaceExA (notice the added **Ex**) in order to get free space from "large drives". It is GetDiskFreeSpaceExA that I'm seeking assistance with. GetDiskFreeSpaceExA (Microsoft)Thanks.
|
|
|
Post by dcromley on Dec 28, 2022 16:54:01 GMT
> "confusion" I certainly don't understand all I know about API's, but this seems to work. I had to take out "ByVal" on lpDirectoryName. I hope this doesn't break our computers.
Declare Dynamic Library "kernel32" ' Function GetDiskFreeSpaceEx& Alias "GetDiskFreeSpaceExA" ( _ lpDirectoryName As String, _ lpFreeBytesAvailableToCaller As _INTEGER64, _ lpTotalNumberOfBytes As _INTEGER64, _ lpTotalNumberOfFreeBytes As _INTEGER64) End Declare
Screen _NewImage(1024, 768, 256) Call Sub1("C:\" + Chr$(0)) Call Sub1("E:\" + Chr$(0))
Sub Sub1 (DirName As String) Dim FreeBytesToCaller As _Integer64 Dim TotalBytes As _Integer64 Dim TotalFreeBytes As _Integer64 Print DirName ret = GetDiskFreeSpaceEx(DirName, FreeBytesToCaller, TotalBytes, TotalFreeBytes) If ret > 0 Then Print "FreeBytesToCaller ="; Using "##,###,###,###,###"; FreeBytesToCaller Print "TotalBytes ="; Using "##,###,###,###,###"; TotalBytes Print "TotalFreeBytes ="; Using "##,###,###,###,###"; TotalFreeBytes End If Print End Sub
|
|
tonylazuto
New Member
Tony Lazuto says hello
Posts: 25
|
Post by tonylazuto on Dec 28, 2022 18:14:05 GMT
The variable typing is mismatched here, definitely. It might work but it is better to make sure everything matches first. I'll reply back with correct typing.
|
|
tonylazuto
New Member
Tony Lazuto says hello
Posts: 25
|
Post by tonylazuto on Dec 28, 2022 18:21:08 GMT
I didn't bother to fix the other functions but I'd recommend checking the Wiki on your GitHub. The information on that page is incomplete but will at least give some help. Also, please check this MSDN page on data types. LPCSTR = pointer to a string = _OFFSET(string$) PULARGE_INTEGER = pointer to an unsigned int64 = _OFFSET(int64~&&) Option _Explicit
$Console:Only
Declare Dynamic Library "Kernel32"
Function GetDiskFreeSpaceEx& Alias "GetDiskFreeSpaceExA" (ByVal lpDirectoryName As _Offset, Byval lpFreeBytesAvailableToCaller As _Offset, Byval lpTotalNumberOfBytes As _Offset, Byval lpTotalNumberOfFreeBytes As _Offset)
End Declare
Dim As String drive: drive = "C:\" + Chr$(0)
Dim As _Unsigned _Integer64 FreeBytesToCaller, TotalBytes, TotalFreeBytes
If GetDiskFreeSpaceEx(_Offset(drive), _Offset(FreeBytesToCaller), _Offset(TotalBytes), _Offset(TotalFreeBytes)) Then
Print "FreeBytesToCaller ="; Using "##,###,###,###,###"; FreeBytesToCaller
Print "TotalBytes ="; Using "##,###,###,###,###"; TotalBytes
Print "TotalFreeBytes ="; Using "##,###,###,###,###"; TotalFreeBytes
End If
|
|
|
Post by dcromley on Dec 28, 2022 21:38:53 GMT
Tony, Thanks for popping in here. You got your "Declare" from learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getdiskfreespaceexacorrect? I got mine from www.jasinskionline.com/windowsapi/ref/g/getdiskfreespaceex.htmlwhich follows: "Declare Function GetDiskFreeSpaceEx Lib "kernel32.dll" Alias "GetDiskFreeSpaceExA" (ByVal lpDirectoryName As String, lpFreeBytesAvailableToCaller As ULARGE_INTEGER, lpTotalNumberOfBytes As ULARGE_INTEGER, lpTotalNumberOfFreeBytes As ULARGE_INTEGER) As Long" Q1): You have "ByVal" on all 4 parameters, mine has it only on the first parameter. What is the impact of having/not-having ByVal? Q2): It seems to me that _Unsigned _Integer64 is the QB64 version of ULARGE_INTEGER. Why have _Offset? What is the difference with/without? Without _Offset, we still get a pointer to the 64-bit variable, right? I (we) would appreciate any education on this. Thanks again, Dave
|
|
tonylazuto
New Member
Tony Lazuto says hello
Posts: 25
|
Post by tonylazuto on Dec 28, 2022 22:29:52 GMT
The offset is because it is PULARGE_INTEGER. Not ULARGE_INTEGER. The P tells you it is a pointer and the MSDN page tells you it is a pointer to the ULARGE_INTEGER. So you'd use an _OFFSET to _INTEGER64. Byval should be used as a rule when passing numeric data. It's especially important if the external library is a header file rather than a DLL. A DLL allows you to fudge a bit but I strongly recommend passing all numeric variables/constants as BYVAL. Only ones you wouldn't/couldn't use it on would be UDTs and strings. I typically pass a string as _OFFSET anyways just to be consistent but those are the ones you can fudge the most on, in my opinion.
But as a rule, any variable that starts with "p" or "lp" will be passed as an _OFFSET because "p" means pointer and "lp" means long pointer. Both are equal for our purposes. I do a lot with the WinAPI in QB64 and will gladly help out with anything you do with it.
|
|
|
Post by mdijkens on Dec 30, 2022 12:00:06 GMT
Thanks for pointing me to GetDiskFreeSpaceExA. Although I personally do not experience any difference (tested with drives up to 4TB), I reworked my programs to use the 'newer' GetDiskFreeSpaceExA
|
|
tonylazuto
New Member
Tony Lazuto says hello
Posts: 25
|
Post by tonylazuto on Dec 30, 2022 16:35:48 GMT
mdijkens The difference between the two is that GetDiskFreeSpaceA uses DWORDs (LONGs), which are 4 bytes in length each. GetDiskFreeSpaceExA uses ULARGE_INTEGERs (INTEGER64s), which are 8 bytes in length each. This would allow that function to support much larger numbers.
|
|