// 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;
}