Click here to Skip to main content
15,896,063 members
Articles / Programming Languages / C++

System Information Utility

Rate me:
Please Sign up or sign in to vote.
4.95/5 (12 votes)
17 Apr 2001 502.7K   8.6K   107  
Utility to extract system information
// Disclaimer and Copyright Information
// HDiskInformation.cpp : Implementation of CHDiskInformation
//
// All rights reserved.
//
// Written by Naveen K Kohli (naveenkohli@netzero.net)
// Version 1.0
//
// Distribute freely, except: don't remove my name from the source or
// documentation (don't take credit for my work), mark your changes (don't
// get me blamed for your possible bugs), don't alter or remove this
// notice.
// No warrantee of any kind, express or implied, is included with this
// software; use at your own risk, responsibility for damages (if any) to
// anyone resulting from the use of this software rests entirely with the
// user.
//
// Send bug reports, bug fixes, enhancements, requests, flames, etc. to
// naveenkohli@netzero.net
///////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include <stdio.h>
#include "SystemHDisk.h"
#include "HDiskInformation.h"

/////////////////////////////////////////////////////////////////////////////
// CHDiskInformation

STDMETHODIMP CHDiskInformation::InterfaceSupportsErrorInfo(REFIID riid)
{
	static const IID* arr[] = 
	{
		&IID_IHDiskInformation
	};
	for (int i=0; i < sizeof(arr) / sizeof(arr[0]); i++)
	{
		if (::InlineIsEqualGUID(*arr[i],riid))
			return S_OK;
	}
	return S_FALSE;
}

STDMETHODIMP CHDiskInformation::get_NumberOfPartitions(long *pVal)
{
	HRESULT hRes = E_FAIL;

	if ((hRes = GetInformation ()) != S_OK)
	{
		return hRes;
	}

	*pVal = m_NumberOfPartitions;

	return hRes;
}

STDMETHODIMP CHDiskInformation::get_Bootable(VARIANT *pVal)
{
	HRESULT hRes = E_FAIL;

	if ((hRes = GetInformation ()) != S_OK)
	{
		return hRes;
	}

	VariantInit (pVal);

	V_VT (pVal) = VT_ARRAY | VT_BOOL;
	V_ARRAY (pVal) = m_pBootable;

	return hRes;
}

STDMETHODIMP CHDiskInformation::get_Letter(VARIANT *pVal)
{
	HRESULT hRes = E_FAIL;

	if ((hRes = GetInformation ()) != S_OK)
	{
		return hRes;
	}

	::VariantInit (pVal);

	V_VT (pVal) = VT_ARRAY | VT_BSTR;
	V_ARRAY (pVal) = m_pPartitionLetter;
	return hRes;
}

STDMETHODIMP CHDiskInformation::get_PartitionType(VARIANT *pVal)
{
	HRESULT hRes = E_FAIL;

	if ((hRes = GetInformation ()) != S_OK)
	{
		return hRes;
	}

	::VariantInit (pVal);

	V_VT (pVal) = VT_ARRAY | VT_BSTR;
	V_ARRAY (pVal) = m_pPartitionType;
	return hRes;
}

STDMETHODIMP CHDiskInformation::get_PartitionNumber(VARIANT *pVal)
{
	HRESULT hRes = E_FAIL;

	if ((hRes = GetInformation ()) != S_OK)
	{
		return hRes;
	}

	VariantInit (pVal);

	V_VT (pVal) = VT_ARRAY | VT_I4;
	V_ARRAY (pVal) = m_pPartitionNumber;
	return hRes;
}

STDMETHODIMP CHDiskInformation::get_PartitionLength(VARIANT *pVal)
{
	HRESULT hRes = E_FAIL;

	if ((hRes = GetInformation ()) != S_OK)
	{
		return hRes;
	}

	::VariantInit (pVal);

	V_VT (pVal) = VT_ARRAY | VT_I4;
	V_ARRAY (pVal) = m_pPartitionLength;
	return hRes;
}

STDMETHODIMP CHDiskInformation::get_HiddenSectors(VARIANT *pVal)
{
	HRESULT hRes = E_FAIL;

	if ((hRes = GetInformation ()) != S_OK)
	{
		return hRes;
	}

	::VariantInit (pVal);

	V_VT (pVal) = VT_ARRAY | VT_I4;
	V_ARRAY (pVal) = m_pHiddenSectors;
	return hRes;
}

STDMETHODIMP CHDiskInformation::GetHDiskInformation(long *plNumberOfPartitions,
													VARIANT *pbstrDriveLetterArr,
													VARIANT *pbBootableArr,
													VARIANT *pbstrTypeArr,
													VARIANT *plPartitionNumberArr,
													VARIANT *plLengthArr,
													VARIANT *plHiddenSectorsArr)
{
	HRESULT hRes = E_FAIL;

	if ((hRes = GetInformation ()) != S_OK) {
		return hRes;
	}

	*plNumberOfPartitions = m_NumberOfPartitions;

	::VariantInit (pbstrDriveLetterArr);
	::VariantInit (pbBootableArr);
	::VariantInit (pbstrTypeArr);
	::VariantInit (plPartitionNumberArr);
	::VariantInit (plLengthArr);
	::VariantInit (plHiddenSectorsArr);

	V_VT (pbstrDriveLetterArr) = VT_ARRAY | VT_BSTR;
	V_ARRAY (pbstrDriveLetterArr) = m_pPartitionLetter;

	V_VT (pbBootableArr) = VT_ARRAY | VT_BOOL;
	V_ARRAY (pbBootableArr) = m_pBootable;

	V_VT (pbstrTypeArr) = VT_ARRAY | VT_BSTR;
	V_ARRAY (pbstrTypeArr) = m_pPartitionType;

	V_VT (plPartitionNumberArr) = VT_ARRAY | VT_I4;
	V_ARRAY (plPartitionNumberArr) = m_pPartitionNumber;

	V_VT (plLengthArr) = VT_ARRAY | VT_R8;
	V_ARRAY (plLengthArr) = m_pPartitionLength;

	V_VT (plHiddenSectorsArr) = VT_ARRAY | VT_I4;
	V_ARRAY (plHiddenSectorsArr) = m_pHiddenSectors;
	return S_OK;
}

HRESULT CHDiskInformation::GetInformation ()
{
	UINT i, nIndex;
	UINT nDrives, nDriveType;
	HRESULT hRes = S_OK;
	HANDLE hDevice = NULL;
	BOOL fResult;
	DWORD dwBytes, dwError;
	double tmpNum = 0.;
	char szCurrentDrive[MAX_PATH];
	char szName[80];
	char lpMultiByteStr[128];
	DWORD dwLogicalDrives;
	PARTITION_INFORMATION  *pPartitionInfo = NULL;

	if (m_bInformationObtained)
	{
		return S_OK;
	}

	CComBSTR bstrDriveLetter;
	SAFEARRAY *pSafeArray = NULL;
	SAFEARRAYBOUND arrayBound[1];

	arrayBound[0].lLbound = 0;
	arrayBound[0].cElements = 32;

	pSafeArray = ::SafeArrayCreate (VT_BSTR, 1, arrayBound);

	// Get the all the logical drives. Function will return a bit mask of the logical
	// drives. Bits are set if the corresponding drives are available. Bit 0 represents
	// drive A, bit 2 is drive B and so on.
	dwLogicalDrives = ::GetLogicalDrives ();

	m_NumberOfPartitions = nIndex = 0;

	for (nDrives = 0; nDrives < 32; nDrives ++)
	{
		if (dwLogicalDrives && (1 << nDrives))
		{
			wsprintf (szCurrentDrive, "%c", nDrives + 'A');
			strcpy (szName, szCurrentDrive);
			strcat (szCurrentDrive, _T (":\\"));
			
			// Get the drive type.
			nDriveType = ::GetDriveType (szCurrentDrive);

			// If its a hard drive type of drive, then get the partition information.
			if (nDriveType == DRIVE_FIXED)
			{
				bstrDriveLetter = szName;
				::SafeArrayPutElement (pSafeArray, (long *) &nIndex, bstrDriveLetter.Copy ());
				m_NumberOfPartitions++;
				nIndex++;
			}
		}
	}

	// Create the SafeArrays.

	if (FAILED (this->InitializeSafeArrays ()))
	{
		return E_FAIL;
	}

	// Get information for each drive and stuff into arrays.
	for (i = 0; i < nIndex; i++)
	{
		::SafeArrayGetElement (pSafeArray, (long *) &i, &bstrDriveLetter);

		::WideCharToMultiByte (CP_ACP, 0, bstrDriveLetter, -1, lpMultiByteStr,
							   sizeof (lpMultiByteStr), NULL, NULL);

		strcat (lpMultiByteStr, _T (":"));
		sprintf(szName,"\\\\.\\%s", lpMultiByteStr);

		hDevice = CreateFile (szName, GENERIC_READ | GENERIC_WRITE,
							  FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
							  OPEN_EXISTING, 0, NULL);
		if (hDevice == INVALID_HANDLE_VALUE)
		{
			dwError = ::GetLastError ();
			continue;
		}

		// Get the partition information.
		pPartitionInfo = new PARTITION_INFORMATION ;
		fResult = ::DeviceIoControl (hDevice, IOCTL_DISK_GET_PARTITION_INFO, NULL, 0,
									 pPartitionInfo, sizeof (*pPartitionInfo),
									 &dwBytes, (LPOVERLAPPED) NULL);
		
		if (!fResult) {
			dwError = GetLastError ();
			continue;
		}

		::SafeArrayPutElement (m_pPartitionLetter, (long *) &i, bstrDriveLetter.Copy ());
		::SafeArrayPutElement (m_pBootable, (long *) &i, &pPartitionInfo->BootIndicator);
		tmpNum = (double)pPartitionInfo->PartitionLength.QuadPart;
		::SafeArrayPutElement (m_pPartitionLength, (long *) &i, &tmpNum);
		::SafeArrayPutElement (m_pHiddenSectors, (long *) &i, &pPartitionInfo->HiddenSectors);
		::SafeArrayPutElement (m_pPartitionNumber, (long *) &i, &pPartitionInfo->PartitionNumber);
		::SafeArrayPutElement (m_pPartitionType, (long *) &i,
							   GetPartitionType ((DWORD)pPartitionInfo->PartitionType).Copy ());

		::CloseHandle (hDevice);

		if (pPartitionInfo != NULL)
		{
			delete pPartitionInfo;
			pPartitionInfo = NULL;
		}
	}

	m_bInformationObtained = true;
	return S_OK;
}

HRESULT CHDiskInformation::InitializeSafeArrays ()
{
	SAFEARRAYBOUND arrayBound[1];

	if (m_NumberOfPartitions <= 0)
	{
		return E_FAIL;
	}

	arrayBound[0].lLbound = 0;
	arrayBound[0].cElements = m_NumberOfPartitions;

	m_pBootable = ::SafeArrayCreate (VT_BOOL, 1, arrayBound);
	m_pPartitionLetter = ::SafeArrayCreate (VT_BSTR, 1, arrayBound);
	m_pPartitionType = ::SafeArrayCreate (VT_BSTR, 1, arrayBound);
	m_pPartitionNumber = ::SafeArrayCreate (VT_I4, 1, arrayBound);
	m_pPartitionLength = ::SafeArrayCreate (VT_R8, 1, arrayBound);
	m_pHiddenSectors = ::SafeArrayCreate (VT_I4, 1, arrayBound);

	return S_OK;
}

CComBSTR CHDiskInformation::GetPartitionType (DWORD dwType) const
{
	CComBSTR bstrType;

	switch (dwType)
	{
		case PARTITION_ENTRY_UNUSED:
			bstrType = _T ("Unknown");
			break;
		case PARTITION_FAT_12:
			bstrType = _T ("12-bit FAT");
			break;
		case PARTITION_XENIX_1:
			bstrType = _T ("Xenix type 1");
			break;
		case PARTITION_XENIX_2:
			bstrType = _T ("Xenix type 2");
			break;
		case PARTITION_FAT_16:
			bstrType = _T ("FAT16");
			break;
		case PARTITION_EXTENDED:
			bstrType = _T ("Extended"); 
			break;
		case PARTITION_FAT32:
			bstrType = _T ("FAT32");
			break;
		case PARTITION_HUGE:
			bstrType = _T ("MS-DOS V4 Huge");
			break;
		case PARTITION_IFS:
			bstrType = _T ("IFS");
			break;
		case PARTITION_PREP:
			bstrType = _T ("PowerPC Reference Platform");
			break;
		case PARTITION_UNIX:
			bstrType = _T ("UNIX");
			break;
		case VALID_NTFT:
			bstrType = _T ("NTFT");
			break;
		case PARTITION_LDM:
			bstrType = _T ("Logical Disk Manager");
			break;
		case PARTITION_XINT13:
			bstrType = _T ("Partition with Extened int13 Services");
			break;
		case PARTITION_XINT13_EXTENDED:
			bstrType = _T ("Exteneded Partition with Extended int13 Services");
			break;
		case PARTITION_FAT32_XINT13 :
			bstrType = _T ("FAT32 with Extended int13 Services");
			break;
	}

	return bstrType;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions