The Windows Disk Management 16

 

 

 

 

 

GetDiskFreeSpace() Function

 

This function retrieves information about the specified disk, including the amount of free space on the disk. The GetDiskFreeSpace() function cannot report volume sizes that are greater than 2 gigabytes (GB). To ensure that your application works with large capacity hard drives, use the GetDiskFreeSpaceEx() function. The syntax is:

 

BOOL WINAPI GetDiskFreeSpace(

     LPCTSTR lpRootPathName,

     LPDWORD lpSectorsPerCluster,

     LPDWORD lpBytesPerSector,

     LPDWORD lpNumberOfFreeClusters,

     LPDWORD lpTotalNumberOfClusters);

 

Parameters

 

lpRootPathName [in] - The root directory of the disk for which information is to be returned. If this parameter is NULL, the function uses the root of the current disk. If this parameter is a UNC name, it must include a trailing backslash (for example, \\MyServer\MyShare\). Furthermore, a drive specification must have a trailing backslash (for example, C:\). The calling application must have FILE_LIST_DIRECTORY access rights for this directory.

lpSectorsPerCluster [out] - A pointer to a variable that receives the number of sectors per cluster.

lpBytesPerSector [out] - A pointer to a variable that receives the number of bytes per sector.

lpNumberOfFreeClusters [out] - A pointer to a variable that receives the total number of free clusters on the disk that are available to the user who is associated with the calling thread. If per-user disk quotas are in use, this value may be less than the total number of free clusters on the disk.

lpTotalNumberOfClusters [out] - A pointer to a variable that receives the total number of clusters on the disk that are available to the user who is associated with the calling thread. If per-user disk quotas are in use, this value may be less than the total number of clusters on the disk.

 

Return Value

 

If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To get extended error information, call GetLastError(). The GetDiskFreeSpaceEx() function lets you avoid some of the arithmetic that is required by the GetDiskFreeSpace() function. For symbolic link behavior - If the path points to a symbolic link, the operation is performed on the target.

 

GetDiskFreeSpaceEx() Function Example

 

This function retrieves information about the amount of space that is available on a disk volume, which is the total amount of space, the total amount of free space, and the total amount of free space available to the user that is associated with the calling thread. The syntax is:

 

BOOL WINAPI GetDiskFreeSpaceEx(

     LPCTSTR lpDirectoryName,

     PULARGE_INTEGER lpFreeBytesAvailable,

     PULARGE_INTEGER lpTotalNumberOfBytes,

     PULARGE_INTEGER lpTotalNumberOfFreeBytes);

 

Parameters

 

lpDirectoryName [in, optional] - A directory on the disk. If this parameter is NULL, the function uses the root of the current disk. If this parameter is a UNC name, it must include a trailing backslash, for example, "\\MyServer\MyShare\". This parameter does not have to specify the root directory on a disk. The function accepts any directory on a disk. The calling application must have FILE_LIST_DIRECTORY access rights for this directory.

lpFreeBytesAvailable [out, optional] - A pointer to a variable that receives the total number of free bytes on a disk that are available to the user who is associated with the calling thread.

This parameter can be NULL. If per-user quotas are being used, this value may be less than the total number of free bytes on a disk.

lpTotalNumberOfBytes [out, optional] - A pointer to a variable that receives the total number of bytes on a disk that are available to the user who is associated with the calling thread.

This parameter can be NULL. If per-user quotas are being used, this value may be less than the total number of bytes on a disk. To determine the total number of bytes on a disk or volume, use IOCTL_DISK_GET_LENGTH_INFO.

lpTotalNumberOfFreeBytes [out, optional] - A pointer to a variable that receives the total number of free bytes on a disk. This parameter can be NULL.

 

Return Value

 

If the function succeeds, the return value is nonzero. If the function fails, the return value is zero (0). To get extended error information, call GetLastError(). The values obtained by this function are of the type ULARGE_INTEGER. Do not truncate these values to 32 bits. The GetDiskFreeSpaceEx() function returns zero (0) for lpTotalNumberOfFreeBytes and lpFreeBytesAvailable for all CD requests unless the disk is an unwritten CD in a CD-RW drive. Symbolic link behavior, if the path points to a symbolic link, the operation is performed on the target.

The following sample code demonstrates how to use GetDiskFreeSpaceEx() and GetDiskFreeSpace() on all Windows platforms. Important elements of the code include:

How to determine at run time whether GetDiskFreeSpaceEx() is present and if not, how to revert to GetDiskFreeSpace(). How to use 64-bit math to report the returned sizes for all volumes, even if they are larger than 2 GB.

Create a new empty Win32 console application project. Give a suitable project name and change the project location if needed.

Then, add the source file and give it a suitable name.

Next, add the following source code.

 

/*    Determines the amount of free space available for the caller.

      Runs on Windows 95 retail and later, and on Windows 4.0 and later. 

      Uses GetDiskFreeSpaceEx() if available, otherwise reverts to GetDiskFreeSpace.

 

      To determine the amount of available space correctly:

 

        Use 64-bit math with the return values of both GetDiskFreeSpace()

        and GetDiskFreeSpaceEx() so that you can determine the sizes of

        volumes that are larger than 2GB.

 

      Programs that need to determine how much free space the current user can have (such as whether

        there is enough space to complete an installation)

        have an additional requirement:

 

        Use the lpFreeBytesAvailableToCaller value from

        GetDiskFreeSpaceEx() rather than lpTotalNumberOfFreeBytes. 

        This is because Windows 2000 has disk quota management that

        administrators may use to limit the amount of disk space that users may use.

   */

 

#include <windows.h>

#include <stdio.h>

 

// typedef

typedef BOOL (WINAPI *P_GDFSE)(LPCTSTR, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER);

 

int wmain(int argc, WCHAR **argv)

{

      BOOL  fResult;

      WCHAR  *pszDrive  = NULL, szDrive[4];

      DWORD dwSectPerClust, dwBytesPerSect, dwFreeClusters, dwTotalClusters;

      P_GDFSE pGetDiskFreeSpaceEx = NULL;

      unsigned __int64 i64FreeBytesToCaller, i64TotalBytes, i64FreeBytes;

     

      /* Command line parsing.

      If the drive is a drive letter and not a UNC path, append a trailing

      backslash to the drive letter and colon.  This is required on Windows 95 and 98. */

     

      if (argc != 2)

      {

            wprintf(L"usage:  %s <drive|UNC path>\n", argv[0]);

            wprintf(L"\texample:  %s C:\\\n", argv[0]);

            return 1;

      }

     

      pszDrive = argv[1];

      // Parse the drive

      if (pszDrive[1] == ':')

      {

            szDrive[0] = pszDrive[0];

            szDrive[1] = ':';

            szDrive[2] = '\\';

            szDrive[3] = '\0';

           

            pszDrive = szDrive;

      }

     

      /* Use GetDiskFreeSpaceEx() if available; otherwise, use GetDiskFreeSpace().

      Note: Since GetDiskFreeSpaceEx() is not in Windows 95 Retail, we

      dynamically link to it and only call it if it is present.  We

      don't need to call LoadLibrary() on KERNEL32.DLL because it is

      already loaded into every Win32 process's address space. */

      pGetDiskFreeSpaceEx = (P_GDFSE)GetProcAddress(GetModuleHandle (L"kernel32.dll"), "GetDiskFreeSpaceExW");

      if (pGetDiskFreeSpaceEx)

      {

            fResult = pGetDiskFreeSpaceEx((LPCTSTR)pszDrive, (PULARGE_INTEGER)&i64FreeBytesToCaller,

                  (PULARGE_INTEGER)&i64TotalBytes, (PULARGE_INTEGER)&i64FreeBytes);

           

            if (fResult)

            {

                  wprintf(L"\nGetDiskFreeSpaceExW reports:\n\n");

                  wprintf(L"Available space to caller = %I64u MB\n", i64FreeBytesToCaller / (1024*1024));

                  wprintf(L"Total space               = %I64u MB\n", i64TotalBytes / (1024*1024));

                  wprintf(L"Free space on drive       = %I64u MB\n", i64FreeBytes / (1024*1024));

            }

      }

      else

      {

            fResult = GetDiskFreeSpace((LPCWSTR)pszDrive, &dwSectPerClust, &dwBytesPerSect, &dwFreeClusters, &dwTotalClusters);

           

            if (fResult)

            {

                  /* force 64-bit math */

                  i64TotalBytes = (__int64)dwTotalClusters * dwSectPerClust * dwBytesPerSect;

                  i64FreeBytes = (__int64)dwFreeClusters * dwSectPerClust * dwBytesPerSect;

                 

                  wprintf(L"GetDiskFreeSpace reports\n");

                  wprintf(L"Free space  = %I64u MB\n", i64FreeBytes / (1024*1024));

                  wprintf(L"Total space = %I64u MB\n", i64TotalBytes / (1024*1024));

            }

      }

     

      if (!fResult)

            wprintf(L"error: %lu:  could not get free space for \"%s\"\n", GetLastError(), argv[1]);

     

      return 0;

}

 

Build and run the project. The following screenshot is a sample output.

 

GetDiskFreeSpaceEx() Function Example: A sample console program output

 

Notes on 64-bit Integer Math

 

Microsoft Visual C++ versions 4.0 and later support a 64-bit integer type called __int64. The compiler generates code to do the 64-bit math because the Intel x86 family of microprocessors supports 8-bit, 16-bit, and 32-bit integer math, but not 64-bit integer math. To perform a 64-bit integer multiply, one of the arguments must be 64-bit; the other can be either 32-bit or 64-bit. When functions such as GetDiskFreeSpace() return only 32-bit integer values that will be multiplied together but you need to have a 64-bit integer to contain the product, cast one of the values to an __int 64 as follows:

 

i64TotalBytes = (__int64)dwTotalClusters * dwSectPerClust *  dwBytesPerSect;

                                                            

The first multiply is of a 64-bit integer with a 32-bit integer; the result is a 64-bit integer, which is then multiplied by another 32-bit integer, resulting in a 64-bit product. Many Win32 API functions that take a 64-bit quantity do so as two separate 32-bit quantities. Others, such as QueryPerformanceCounter(), take a single 64-bit quantity. The LARGE_INTEGER union type defined in the Platform SDK WINNT.H header file manages these differing ways to handle 64-bit integers. There's a corresponding ULARGE_INTEGER for unsigned large integers.

The LARGE_INTEGER union consists of a 64-bit __int64 member (QuadPart) and two 32-bit values (HighPart and LowPart). Each of the two 32-bit values is one-half of the 64-bit integer. The HighPart member is a signed long integer, while the LowPart is an unsigned long integer. Since the LARGE_INTEGER.QuadPart member is an __int64, you can easily intermix LARGE_INTEGER variables with __int64 variables. To perform integer math with LARGE_INTEGER variables, always use the QuadPart member to treat the LARGE_INTEGER as the single 64-bit value it represents. Use the 32-bit HighPart and LowPart members when you must pass a LARGE_INTEGER to a function in two 32-bit parts. An equivalent to the above example using LARGE_INTEGERs instead of __int64 variables is:

 

liTotalBytes.QuadPart = (__int64)dwTotalClusters * dwSectPerClust  * dwBytesPerSect;

 

 

 

 

< Windows Disk 15 | Win32 Programming Index Page | Windows Disk Index | Windows Disk 17 >