[WinAPI] 로컬 디스크 – 2. 로컬 디스크 용량 얻기(GetDiskFreeSpaceEx)

저번글에 이어서 이번 글에서는 로컬 디스크의 용량을 얻어오는 작업을 해보겠습니다.

디스크에는 전체 용량, 현재 용량, 사용 용량 등의 정보가 있습니다. 이러한 정보들은 GetDiskFreeSpace 함수를 써서 확인을 할 수 있습니다.
GetDiskFreeSpaceEx 함수 사용을 위해 필요한 요구사항은 아래와 같습니다.

지원되는 최소 클라이언트Windows XP
지원되는 최소 서버Windows Server 2003
헤더fileapi.h (Windows.h)
라이브러리Kernel32.lib
DLLKernel32.dll

GetDiskFreeSpaceEx 함수 원형은 아래와 같습니다.

BOOL GetDiskFreeSpaceExA(
	LPCSTR lpDirectoryName, // 디스크의 디렉터리, NULL이면 현재 디렉터리
	PULARGE_INTEGER lpFreeBytesAvailableToCaller, // 호출 스레드와 연결된 사용자가 사용 가능한 공간
	PULARGE_INTEGER lpTotalNumberOfBytes, // 전체 공간
	PULARGE_INTEGER lpTotalNumberOfFreeBytes // 사용 가능한 총 바이트 수
);

함수가 실패하면 0, 성공하면 0이 아닙니다. 실패 시 GetLastError를 통해 확인 할 수 있습니다.
예제 코드는 아래와 같습니다.

DWORD dwError = 0;
TCHAR tzDriveString[MAX_PATH] = { 0, };

// 반환 예 : "C:\\\0D:\\\0E:\\\0\0"
// 구분 : "\0", 끝 : "\0\0"
DWORD dwStringsLen = ::GetLogicalDriveStrings( MAX_PATH, tzDriveString ); // 로컬 디스크 목록 얻기
if ( dwStringsLen != 0 && dwStringsLen <= MAX_PATH )
{
	CString strTrace;
	strTrace.Format( _T( "Length : %lu" ), dwStringsLen );
	TRACE( _T( "%s\n" ), strTrace );

	DWORD dwIndex = 0;
	while ( 0 < _tcslen( &tzDriveString[dwIndex] ) )
	{
		strTrace.Format( _T( "Drive : %s" ), &tzDriveString[dwIndex] );
		TRACE( _T( "%s\n" ), strTrace );

		ULARGE_INTEGER uliAvailable;
		ULARGE_INTEGER uliTotal;
		ULARGE_INTEGER uliFree;

		CString strDrive;
		strDrive.Format( _T( "%s" ), &tzDriveString[dwIndex] );
		GetDiskFreeSpaceEx( strDrive, &uliAvailable, &uliTotal, &uliFree );

		int iAvailable = (int)(uliAvailable.QuadPart >> 30);
		int iTotal = (int)(uliTotal.QuadPart >> 30);
		int iFree = (int)(uliFree.QuadPart >> 30);
		TRACE( _T( "Disk(%s), 사용 중(%d), 전체(%d), 사용 가능(%d)\n" ), strDrive, iTotal - iFree, iTotal, iFree );

		dwIndex += _tcslen( &tzDriveString[dwIndex] ) + 1;
	}
}
else
	dwError = ::GetLastError();

if ( dwError != 0 )
{
	// 에러 처리
}

return;

추가적으로 설명을 드리자면, GetDiskFreeSpaceEx 함수의 2, 3, 4번째 인자는 ULARGE_INTEGER를 사용합니다. 여기에 입력된 변수에 디스크의 용량이 반환이 됩니다.
하지만 요새 디스크는 기가 혹은 테라로 지원하는데, 그렇게 되면 반환 되는 변수에는 엄청 큰 수가 들어있습니다.
그래서 단위를 변수에 입력된 값을 변환 해줘야하는데 이럴 경우 비트쉬프트를 사용하면 계산이 편합니다.

int iAvailable = (int)(uliAvailable.QuadPart >> 30);
int iTotal = (int)(uliTotal.QuadPart >> 30);
int iFree = (int)(uliFree.QuadPart >> 30);

오른쪽 쉬프트 30은 기가 단위로 표시하겠다는 겁니다. 30인 이유는 대략적으로 1기가는 2의 30승이기 때문이구요.
비슷하게 1메가 바이트는 약 2의 20승, 1키로 바이트는 약 2의 10승입니다.

저의 PC의 C:\의 용량을 출력해봤는데 동일하게 출력되었습니다.