Available disk space (not win95)

by Michael R├╝sweg-Gilbert

To get the amount of available disk space you can call GetDiskFreeSpace or GetDiskFreeSpaceEx.
GetDiskFreeSpaceEx is best because it supports disks larger than 2 gigabyte. Unfortunately this function may not be available on every Windows version (Windows 95 before OSR2 only supports GetDiskFreeSpace).

The following program shows how to call GetDiskFreeSpaceEx. Note how the 64-bit parameters are cast in MEMPTR variables and converted to decimal values.

/* ===============================================================================
    Program:  VolSpace.p
    Created:  Michael R?Gilbert    Feb 2001
              mailto:rg@rgilbert.de
Description:  returns the capacity and free space of a volume (even if Vol > 2 GB)
      Usage:  for ex. run VolSpace.p ("C:",
                                      "KB",
                                      output freeSpace,
                                      output totalSpace).
 Parameters: - Volume to check or Blank
                 (Blank returns informations abaout the working drirector drive)
               It does not have to be the root, accepts any directory.   
             - Unit to format the result; legal entries are 
                   "KB", "MB" or "GB".
               If the unit is not recognized or empty, VolSpace will return 
               Number of Bytes.
             - OUTPUT available free space in given unit
             - OUTPUT total space in given unit
 
             When VolSpace is not successful, both output parameters will return ?.
 
modifications:
   March 14, 2001: Jurjen - added function IsAPIFunctionSupported()             
===================================================================================== */
 
DEFINE INPUT  PARAMETER ip_drive   AS CHARACTER NO-UNDO.
DEFINE INPUT  PARAMETER ip_unit    AS CHARACTER NO-UNDO.
DEFINE OUTPUT PARAMETER op_free    AS DECIMAL   NO-UNDO.
DEFINE OUTPUT PARAMETER op_total   AS DECIMAL   NO-UNDO.
 
&SCOPED-DEFINE WTRUE 1
&SCOPED-DEFINE WFALSE 0
 
FUNCTION get64BitValue RETURNS DECIMAL
    (INPUT m64 AS MEMPTR) FORWARD.
 
FUNCTION IsAPIFunctionSupported RETURNS LOGICAL 
    (FunctionName AS CHAR, ModuleName AS CHARACTER) FORWARD.
 
DEFINE VARIABLE retval     AS INTEGER    NO-UNDO.
DEFINE VARIABLE divident   AS INTEGER    NO-UNDO INIT 1.
DEFINE VARIABLE i          AS INTEGER    NO-UNDO.
 
DEFINE VARIABLE mem1 AS MEMPTR     NO-UNDO.
DEFINE VARIABLE mem2 AS MEMPTR     NO-UNDO.
DEFINE VARIABLE mem3 AS MEMPTR     NO-UNDO.
 
/* See if GetDiskFreeSpaceEx is available in this Windows version.
   (it is available in NT4, Windows 95 OSR2, Windows 98, Windows 2000)  */
IF NOT IsAPIFunctionSupported("GetDiskFreeSpaceExA":U, "kernel32.dll":U) THEN DO:
    MESSAGE "Sorry, your version of Windows does not support GetDiskFreeSpaceEx"
            VIEW-AS ALERT-BOX.
    ASSIGN op_free  = ?
           op_total = ?.
    RETURN.
END.
 
IF CAN-DO("KB,Kilo,Kilobyte,Kilobytes", ip_unit)
THEN divident = 1024.
ELSE
IF CAN-DO("MB,Mega,Megabyte,Megabytes", ip_unit)
THEN divident = 1024 * 1024.
ELSE
IF CAN-DO("GB,Giga,Gigabyte,Gigabytes", ip_unit)
THEN divident = 1024 * 1024 * 1024.
ELSE divident = 1.
 
/* No directory specified? Then use the current directory */
IF (ip_drive = "") OR (ip_drive=?) THEN DO:
    FILE-INFO:FILE-NAME = ".".
    ip_drive = FILE-INFO:FULL-PATHNAME.
END.
 
/* If a UNC name was specified, make sure it ends with a backslash ( \\drive\share\dir\ )
   This won't hurt for a mapped drive too */
IF SUBSTR(ip_drive, LENGTH(ip_drive), 1) NE "\"
   THEN ip_drive = ip_drive + "\".
 
SET-SIZE(mem1) = 8.  /* 64 bit integer! */
SET-SIZE(mem2) = 8.
SET-SIZE(mem3) = 8.
 
RUN GetDiskFreeSpaceExA ( ip_drive + CHR(0),
                         OUTPUT mem1,
                         OUTPUT mem2,
                         OUTPUT mem3,
                         OUTPUT retVal  ).
IF retVal NE {&WTRUE} THEN DO:
        op_free = ?.
        op_total = ?.
END.
ELSE DO:
     ASSIGN
        op_free  = TRUNC( get64BitValue(mem3) / divident, 3)
        op_total = TRUNC( get64BitValue(mem2) / divident, 3).
END.
 
SET-SIZE(mem1) = 0.
SET-SIZE(mem2) = 0.
SET-SIZE(mem3) = 0.
 
RETURN.
 
PROCEDURE GetModuleHandleA EXTERNAL "kernel32.dll" :
    DEFINE  INPUT PARAMETER lpModuleName       AS CHARACTER NO-UNDO.
    DEFINE RETURN PARAMETER hModule            AS LONG      NO-UNDO.
END PROCEDURE.
 
PROCEDURE GetProcAddress EXTERNAL "kernel32.dll" :
    DEFINE  INPUT PARAMETER hModule            AS LONG NO-UNDO.
    DEFINE  INPUT PARAMETER lpProcName         AS CHARACTER NO-UNDO.
    DEFINE RETURN PARAMETER lpFarproc          AS LONG NO-UNDO.
END PROCEDURE.
 
PROCEDURE GetDiskFreeSpaceExA EXTERNAL "kernel32.dll" :
    DEFINE  INPUT  PARAMETER  lpDirectoryName        AS CHARACTER NO-UNDO.
    DEFINE OUTPUT  PARAMETER  FreeBytesAvailable     AS MEMPTR    NO-UNDO.
    DEFINE OUTPUT  PARAMETER  TotalNumberOfBytes     AS MEMPTR    NO-UNDO.
    DEFINE OUTPUT  PARAMETER  TotalNumberOfFreeBytes AS MEMPTR    NO-UNDO.
    DEFINE RETURN  PARAMETER  retval                 AS LONG      NO-UNDO.
END PROCEDURE.
 
 
/* See if GetDiskFreeSpaceEx is available in this Windows version */
FUNCTION IsAPIFunctionSupported RETURNS LOGICAL
    (FunctionName AS CHAR, ModuleName AS CHARACTER):
 
    DEFINE VARIABLE hModule AS INTEGER NO-UNDO.
    DEFINE VARIABLE lpFarProc AS INTEGER NO-UNDO.
 
    /* you should run LoadLibraryA to load the module into memory, 
       but this is not necessary for ModuleName="kernel32.dll": the kernel is 
       always available. */
    RUN GetModuleHandleA (ModuleName, OUTPUT hModule).
    RUN GetProcAddress   (hModule, FunctionName, OUTPUT lpFarProc).
    RETURN lpFarProc NE 0.
END FUNCTION.
 
 
/* Converts a 64-bit integer given in a 8 byte mempointer into a decimal */
FUNCTION get64BitValue RETURNS DECIMAL
( INPUT m64 AS MEMPTR ):
 
    /* constant 2^32 */
    &SCOPED-DEFINE BigInt 4294967296
 
    DEFINE VARIABLE d1 AS DECIMAL    NO-UNDO.
    DEFINE VARIABLE d2 AS DECIMAL    NO-UNDO.
 
    d1 = GET-LONG(m64, 1).
    IF d1 < 0 
    THEN d1 = d1 + {&BigInt}.
 
    d2 = GET-LONG(m64, 5).
    IF d2 < 0 
    THEN d2 = d2 + {&BigInt}.
 
    IF d2 GT 0
    THEN d1 = d1 + (d2 * {&BigInt}).
 
    RETURN d1.
 
END FUNCTION.