Как определить размер свободного места на диске?

Для определения свободного места на диске в Win32 используются функции GetDiskFreeSpaceEx или GetDiskFreeSpace. В принципе, функция GetDiskFreeSpaceEx возвращает всю необходимую информацию, включая свободное место доступное пользователю, ассоциированному с вызывающим потоком. Но, как это обычно бывает с удобными и полезными функциями, она отсутствует в ранних версиях Windows и появилась только в Windows 95 OSR2.

Если Вы разрабатываете приложения, способные работать со всеми версиями Windows, то этот факт исключает возможность применения данной функции. С другой стороны, отказываться от преимуществ, которые даёт GetDiskFreeSpaceEx неразумно. Раз нам нельзя воспользоваться прямым вызовом функции, значит следует воспользоваться другим способом, а именно через вызов GetProcAddress. Функция, приведённая ниже, производит проверку наличия функции GetDiskFreeSpaceEx в системе и если не находит её, то выполняет вызов GetDiskFreeSpace.


#include <windows.h>
#include <stdlib.h>
#include <tchar.h>
 
#ifdef UNICODE
#define nmGetDiskFreeSpaceEx "GetDiskFreeSpaceExW"
#else
#define nmGetDiskFreeSpaceEx "GetDiskFreeSpaceExA"
#endif
 
BOOL GetPathFreeSpace (LPCTSTR szPath,LARGE_INTEGER& liSize)
{
    liSize.LowPart  = 0;
    liSize.HighPart = 0;
 
    HMODULE hm = ::GetModuleHandle(TEXT("KERNEL32.DLL"));
    if (hm != 0) {
        typedef BOOL (WINAPI *GDFSEx)(LPCSTR,PULARGE_INTEGER,
                                      PULARGE_INTEGER,
                                      PULARGE_INTEGER);
        GDFSEx func = (GDFSEx)GetProcAddress(hm,nmGetDiskFreeSpaceEx);
        if (func) {
            ULARGE_INTEGER liFreeAvailable,
                           liTotal;
            if (func(szPath,&liFreeAvailable,
                            &liTotal,
                            NULL)) {
                liSize.QuadPart = liFreeAvailable.QuadPart;
                return TRUE;
            }
//            return FALSE;
        }
    }
 
    TCHAR szDrive[_MAX_DRIVE+10];
    if (szPath != NULL) {
        _tsplitpath(szPath,szDrive,0,0,0);
        if (szDrive[0] == 0) {
            TCHAR szPath[MAX_PATH];
            ::GetCurrentDirectory(MAX_PATH,szPath);
            _tsplitpath(szPath,szDrive,0,0,0);
        }
        _tcscat(szDrive,TEXT("\\"));
        szPath = szDrive;
    }
 
    DWORD dwSecPerClus, dwBytesPerSec, dwFreeClus, dwTotalClus;
    if (::GetDiskFreeSpace(
            szPath,
            &dwSecPerClus,&dwBytesPerSec,&dwFreeClus,&dwTotalClus)) {
        liSize.QuadPart = __int64(dwFreeClus) * dwSecPerClus * dwBytesPerSec;
        return TRUE;
    }
 
    return FALSE;
}

Эта функция принимает в качестве параметра путь к каталогу, а не просто диск. Дело в том, что GetDiskFreeSpaceEx позволяет получать информацию не просто о свободном пространстве, а о доступном пространстве на диске для текущего пользователя в заданной директории. Но, если Вы ошибётесь и неправильно зададите путь, то GetDiskFreeSpaceEx вернёт ошибку и будет произведена попытка получить необходимую информацию через GetDiskFreeSpace. Если такая возможность Вам не нужна, то откомментируйте строчку:


//            return FALSE;

Если в качестве первого параметра задать NULL, то будет выполнено определение свободного места для текущего каталога или диска.

Функция возвращает значение в структуре LARGE_INTEGER, которая состоит из двух 32-х битных полей LowPart и HighPart. При этом через поле QuadPart можно получить доступ к 64-х разрядному значению типа __int64.