How to check the hard disc space - Clarion9

How to check the hard disc space - Clarion9

Pay attention to the data types used here Windows API help with CopyFileExA() and Callback to show Progress and here
Windows API help with CopyFileExA() and Callback to show Progress
namely, you need to create a pointer (long but Paul Attryde says use a ulong for pointers How can I access the raw stack data? MS callback proc prototype changes when asm starts popping the stack) pointing to a clarion Type’d group structure which matches this MS data type
ULARGE_INTEGER - Win32 apps | Microsoft Docs

Dword’s are ulong’s so this would apply.

UINT64   GROUP,TYPE
lo         ULONG
hi         ULONG
         END

And would be the group data type to point (long/ulong) to in the api.

Its worth noting in the svapi.inc SV have declared which is different to what MS have declared on their website.

_ULARGE_INTEGER   group,type
LowPart                         long
HighPart                        long
                                      end

They also have an equate in WinEqu.clw defined as

Ularge_Integer Equate(Ulong)

Which would be wrong, unless there is some behind the scenes things going on in the runtime.

and then apply to this api.
SHGetDiskFreeSpaceExA function (shellapi.h) - Win32 apps | Microsoft Docs

map
module
MyPrefixForUniquenessToAvoidCompilerWarningsWith3rdPartyAddons_SHGetDiskFreeSpaceExA(CONST *cstring pNullTerminatedStringAkaCstring, long pPointerToUlarge_IntegerFreeBytes,long pPointerToUlarge_IntegerByteNumber , long pPointerToUlarge_IntegerFreeByteNumber),Bool,Raw,Pascal,Name('SHGetDiskFreeSpaceExA')
!Which is also the same as
Prefix_SHGetDiskFreeSpaceExA(long,long,long,long),bool,Pascal,Name(SHGetDiskFreeSpaceExA')
End
End

The next challenge is getting the value out of the group data type UINT64 in order to display.

Because I dont know what data conversion is taking place in the runtime, you could try a Real Over the group structure as shown

TotalFileSize LIKE(INT64),OVER(R_TotalFileSize)

also mentioned here complete with calculations needed to be performed. Hint: Decimal is easiest and scalable.

From 2003!
Clarion, Displaying a ULARGE_INTEGER (computer-programming-forum.com)

I should add, you’ll know when you have the right calculations because they will match what you see in file explorer or dos. :wink:

I use GetDiskFreeSpaceExA from Kernel32, the calculation is quite easy.
Julian

myINT64 Group
lo ULONG
hi ULONG
.
szDirectory                      CSTRING(32)
u64_FreeBytesAvailableToCaller   LIKE(myINT64)
u64_TotalNumberOfBytes           LIKE(myINT64)
u64_TotalNumberOfFreeBytes       LIKE(myINT64)            
freeBytes                        DECIMAL(31)

Code
  !-- Set szDirectory to the drive required ..
  szDirectory = 'C:\'
          
  if GetDiskFreeSpaceExA(Address(szDirectory),Address(u64_FreeBytesAvailableToCaller),Address(u64_TotalNumberOfBytes),Address(u64_TotalNumberOfFreeBytes)) = TRUE
   freeBytes = (u64_FreeBytesAvailableToCaller.Hi * 4294967295) + u64_FreeBytesAvailableToCaller.Lo
  .
1 Like

To save looking up the 32 bit max: .Hi * 0FFFFFFFFh )

Clarion has a base type of LONG so I would worry that may end up as -1. I usually declare a variable:

Max32 ULONG(0FFFFFFFFh)

Here’s a quick conversion on prototype, untested:

BOOL GetDiskFreeSpaceExA(
  [in, optional]  LPCSTR          lpDirectoryName,
  [out, optional] PULARGE_INTEGER lpFreeBytesAvailableToCaller,
  [out, optional] PULARGE_INTEGER lpTotalNumberOfBytes,
  [out, optional] PULARGE_INTEGER lpTotalNumberOfFreeBytes
);

GetDiskFreeSpaceEx    PROCEDURE( |                !BOOL GetDiskFreeSpaceExA(
    <*CSTRING lpDirectoryName>               , |  !in  optional LPCSTR lpDirectoryName
    LONG     lpFreeBytesAvailableToCaller=0  , |  !out optional PULARGE_INTEGER lpFreeBytesAvailableToCaller
    LONG     lpTotalNumberOfBytes=0          , |  !out optional PULARGE_INTEGER lpTotalNumberOfBytes
    LONG     lpTotalNumberOfFreeBytes=0        |  !out optional PULARGE_INTEGER lpTotalNumberOfFreeBytes
    ),BOOL,PROC,RAW,PASCAL,DLL(1),name('GetDiskFreeSpaceExA')  

Edit:
Removed <omittable> on LONG, add =0 default value. It was wrong, thanks @FedericoNavarro.

Probably best to use a named Group,Type for the UInt64 prototyped <*UInt64 > so no needed for the Address() in code.

To set hi offset it needs to be multiplied by 2^n not 2^n-1

   freeBytes = (u64_FreeBytesAvailableToCaller.Hi * 4294967296) + u64_FreeBytesAvailableToCaller.Lo
   freeBytes = (u64_FreeBytesAvailableToCaller.Hi *       2^32) + u64_FreeBytesAvailableToCaller.Lo

or this function which should be optimized
i64toDecimal(freeBytes,u64_FreeBytesAvailableToCaller)

needs on the MAP
INCLUDE('i64.INC')

1 Like

Hi Carl,
I think those should be either LONG lpEtc = 0 without angles <> , or as pointer to structures <*UINT64 lpEtc> because for OMITTED() support Clarion tends to add information about the omission or presence of the parameter, even indicating other calling conventions.

I’ve always coded API prototypes using < omitted > and it worked to pass NULL without any problems or extra flag.

The help says PASCAL is exactly correct for Windows API calls so it should handle <> correctly. Using Default=0 would work well for the LONGs but a pain for the <*CSTRING Dir>. Optional (omittable) parameters are so common in API calls it must to work.

BTW if the Directory Parameter is omitted then the Current Path() is used, which seems useful.

<* > pointer based parameters have no problem, as Clarion assumes the absense of a parameter can be represented with a 0 pointer, but with simple value parameters, extra data is needed to support OMITTED.

Here there is an example app based on both prototypes. With <> on simple value parameters it crashes, with = 0 it works.

Also there is an screen capture of Clarion Debugger where it can be seen the extra PUSH 1’s to the stack when using <>

TestOmitParam.clw (1,4 KB)

2 Likes