CDiskDriveUtils.h
#pragma once
#include <wtypesbase.h>
#include <string>
#include <tchar.h>
#include <vector>
#include <map>
#ifdef _UNICODE
using _tstring = std::wstring;
#else
using _tstring = std::string;
#endif
namespace CDiskDriveUtils
{
enum ePartitionStyle {
ePartitionMBR,
ePartitionGPT,
ePartitionRAW
};
enum eDriveType
{
eDriveUnknown,
eDriveNoRootDir,
eDriveRemovable,
eDriveFixed,
eDriveRemote,
eDriveCDROM,
eDriveRAMdisk
};
enum eStorageBusType {
eBusUnknown,
eBusScsi,
eBusAtapi,
eBusAta,
eBus1394,
eBusSsa,
eBusFibre,
eBusUsb,
eBusRAID,
eBusiScsi,
eBusSas,
eBusSata,
eBusSd,
eBusMmc,
eBusVirtual,
eBusFileBackedVirtual,
eBusSpaces,
eBusNvme,
eBusSCM,
eBusUfs,
eBusMax,
eBusMaxReserved = 0x7F
};
typedef struct _DISK_PARTION_INFO
{
_tstring PathName;
_tstring VolumeName;
uint64_t StartingOffset;
uint64_t PartitionLength;
uint64_t FreeBytes;
uint32_t PartitionNumber;
ePartitionStyle PartitionStyle;
eDriveType DriveType;
_DISK_PARTION_INFO() :
PartitionNumber(0),
PartitionLength(0),
StartingOffset(0),
FreeBytes(0),
PartitionStyle(ePartitionStyle::ePartitionRAW),
DriveType(eDriveType::eDriveUnknown)
{
}
}DISK_PARTION_INFO;
typedef struct _LOGICAL_VOLUME_INFO
{
_tstring PathName;
_tstring VolumeName;
_tstring FileSystemName;
uint64_t StartingOffset;
uint64_t ExtentLength;
uint64_t FreeBytes;
uint32_t DiskNumber;
eDriveType DriveType;
_LOGICAL_VOLUME_INFO() :
DiskNumber(0),
StartingOffset(0),
ExtentLength(0),
FreeBytes(0),
DriveType(eDriveType::eDriveUnknown)
{
}
}LOGICAL_VOLUME_INFO;
typedef struct _DISK_INFO
{
_tstring DevicePath;
_tstring ProductId;
_tstring SerialNumber;
_tstring AdapterSerialNumber;
_tstring ProductRevision;
uint64_t DiskSize;
uint64_t Attributes;
eStorageBusType BusType;
int16_t Temperature;
bool fRemovableMedia;
std::vector<DISK_PARTION_INFO> Partitions;
_DISK_INFO() :
Temperature(0),
BusType(eStorageBusType::eBusUnknown),
DiskSize(0),
Attributes(0),
fRemovableMedia(false)
{
}
}DISK_DRIVE_INFO;
std::map<uint32_t, DISK_DRIVE_INFO> GetDiskDriveInfos();
bool GetDiskDriveInfo(DWORD nIndex, DISK_DRIVE_INFO& info);
bool GetLogicalVolumeInfo(std::vector<LOGICAL_VOLUME_INFO>& vVolumeInfo);
}
CDiskDriveUtils.cpp
#include "CDiskDriveUtils.h"
#include <winioctl.h>
#include <strsafe.h>
#include <cstdint>
namespace CDiskDriveUtils
{
std::string _WStrToMultiStr(UINT CodePage, const std::wstring& str)
{
int cbMultiByte = ::WideCharToMultiByte(CodePage, 0, str.c_str(), -1, NULL, 0, NULL, NULL);
std::string strResult(cbMultiByte, 0);
size_t nConverted = ::WideCharToMultiByte(CodePage, 0, str.c_str(), (int)str.size(), &strResult[0], (int)strResult.size(), NULL, NULL);
strResult.resize(nConverted);
return strResult;
}
std::wstring _MultiStrToWStr(UINT CodePage, const std::string& str)
{
int cchWideChar = ::MultiByteToWideChar(CodePage, 0, str.c_str(), -1, NULL, 0);
std::wstring strResult(cchWideChar, 0);
size_t nConverted = ::MultiByteToWideChar(CodePage, 0, str.c_str(), (int)str.size(), &strResult[0], (int)strResult.size());
strResult.resize(nConverted);
return strResult;
}
_tstring WStrToTStr(const std::wstring& str)
{
#ifdef _UNICODE
return str;
#else
return _WStrToMultiStr(CP_ACP, str);
#endif
}
_tstring AStrToTStr(const std::string& str)
{
#ifdef _UNICODE
return _MultiStrToWStr(CP_ACP, str);
#else
return str;
#endif
}
std::map<uint32_t, DISK_DRIVE_INFO> GetDiskDriveInfos()
{
std::map<uint32_t, DISK_DRIVE_INFO> result;
for (int i = 0; i < 1000; i++)
{
DISK_DRIVE_INFO info;
if (GetDiskDriveInfo(i, info))
{
result.emplace(i, info);
}
}
return result;
}
void RemoveBackSpace(_tstring& strName)
{
size_t nLength = strName.size();
for (auto it = strName.crbegin(); it != strName.crend(); it++)
{
if (_T(' ') == *it)
{
nLength--;
}
else
{
break;
}
}
strName.resize(nLength);
}
bool GetDiskDriveInfo(DWORD nIndex, DISK_DRIVE_INFO& info)
{
TCHAR szFileName[MAX_PATH] = { 0 };
HANDLE hFile = INVALID_HANDLE_VALUE;
DWORD dwBytesReturned = 0;
bool bSuccess = false;
do
{
(void)::StringCchPrintf(szFileName, _countof(szFileName), _T(R"(\\.\PhysicalDrive%d)"), nIndex);
DWORD dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
DWORD dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
hFile = ::CreateFile(szFileName, dwDesiredAccess, dwShareMode, NULL, OPEN_EXISTING, 0, NULL);
if (INVALID_HANDLE_VALUE == hFile)
{
break;
}
STORAGE_PROPERTY_QUERY StorageQuery = { };
StorageQuery.PropertyId = StorageDeviceProperty;
StorageQuery.QueryType = PropertyStandardQuery;
std::vector<uint8_t> OutBuffer(1024 * 64);
info.DevicePath = szFileName;
if (::DeviceIoControl(hFile, IOCTL_STORAGE_QUERY_PROPERTY, &StorageQuery, sizeof(StorageQuery), OutBuffer.data(), OutBuffer.size(), &dwBytesReturned, NULL))
{
PSTORAGE_DEVICE_DESCRIPTOR pDesc = (PSTORAGE_DEVICE_DESCRIPTOR)OutBuffer.data();
info.ProductId = AStrToTStr((LPCSTR)((LPBYTE)pDesc + pDesc->ProductIdOffset));
info.ProductRevision = AStrToTStr((LPCSTR)((LPBYTE)pDesc + pDesc->ProductRevisionOffset));
info.SerialNumber = AStrToTStr((LPCSTR)((LPBYTE)pDesc + pDesc->SerialNumberOffset));
info.BusType = (eStorageBusType)pDesc->BusType;
info.fRemovableMedia = pDesc->RemovableMedia;
RemoveBackSpace(info.ProductId);
}
StorageQuery.PropertyId = StorageDeviceTemperatureProperty;
if (::DeviceIoControl(hFile, IOCTL_STORAGE_QUERY_PROPERTY, &StorageQuery, sizeof(StorageQuery), OutBuffer.data(), OutBuffer.size(), &dwBytesReturned, NULL))
{
PSTORAGE_TEMPERATURE_DATA_DESCRIPTOR pDesc = (PSTORAGE_TEMPERATURE_DATA_DESCRIPTOR)OutBuffer.data();
info.Temperature = pDesc->TemperatureInfo->Temperature;
}
StorageQuery.PropertyId = StorageAdapterSerialNumberProperty;
if (::DeviceIoControl(hFile, IOCTL_STORAGE_QUERY_PROPERTY, &StorageQuery, sizeof(StorageQuery), OutBuffer.data(), OutBuffer.size(), &dwBytesReturned, NULL))
{
PSTORAGE_ADAPTER_SERIAL_NUMBER pDesc = (PSTORAGE_ADAPTER_SERIAL_NUMBER)OutBuffer.data();
info.AdapterSerialNumber = WStrToTStr(pDesc->SerialNumber);
}
if (::DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, OutBuffer.data(), OutBuffer.size(), &dwBytesReturned, NULL))
{
PDISK_GEOMETRY_EX pDesc = (PDISK_GEOMETRY_EX)OutBuffer.data();
info.DiskSize = *(unsigned long long*) & pDesc->DiskSize;
}
if (::DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, NULL, 0, OutBuffer.data(), OutBuffer.size(), &dwBytesReturned, NULL))
{
PDRIVE_LAYOUT_INFORMATION_EX pDesc = (PDRIVE_LAYOUT_INFORMATION_EX)OutBuffer.data();
for (DWORD i = 0; i < pDesc->PartitionCount; i++)
{
PPARTITION_INFORMATION_EX pPartInfo = &pDesc->PartitionEntry[i];
if (0 == pPartInfo->PartitionNumber)
{
continue;
}
DISK_PARTION_INFO partionInfo;
partionInfo.PartitionStyle = (ePartitionStyle)pPartInfo->PartitionStyle;
partionInfo.PartitionLength = pPartInfo->PartitionLength.QuadPart;
partionInfo.PartitionNumber = pPartInfo->PartitionNumber;
partionInfo.StartingOffset = pPartInfo->StartingOffset.QuadPart;
info.Partitions.push_back(partionInfo);
}
}
if (::DeviceIoControl(hFile, IOCTL_DISK_GET_DISK_ATTRIBUTES, NULL, 0, OutBuffer.data(), OutBuffer.size(), &dwBytesReturned, NULL))
{
PGET_DISK_ATTRIBUTES pDesc = (PGET_DISK_ATTRIBUTES)OutBuffer.data();
info.Attributes = pDesc->Attributes;
}
if (::DeviceIoControl(hFile, IOCTL_DISK_GET_CACHE_INFORMATION, NULL, 0, OutBuffer.data(), OutBuffer.size(), &dwBytesReturned, NULL))
{
PDISK_CACHE_INFORMATION pDesc = (PDISK_CACHE_INFORMATION)OutBuffer.data();
pDesc = (PDISK_CACHE_INFORMATION)OutBuffer.data();
}
// 从卷信息设置分区信息
std::vector<LOGICAL_VOLUME_INFO> vVolumeInfo;
(void)GetLogicalVolumeInfo(vVolumeInfo);
for (auto& Partition : info.Partitions)
{
for (const auto& volume : vVolumeInfo)
{
if (nIndex == volume.DiskNumber && Partition.StartingOffset == volume.StartingOffset)
{
Partition.PathName = volume.PathName;
Partition.VolumeName = volume.VolumeName;
Partition.FreeBytes = volume.FreeBytes;
Partition.DriveType = volume.DriveType;
break;
}
}
}
bSuccess = true;
} while (false);
if (INVALID_HANDLE_VALUE != hFile)
{
::CloseHandle(hFile);
}
return bSuccess;
}
bool GetLogicalVolumeInfo(std::vector<LOGICAL_VOLUME_INFO>& vVolumeInfo)
{
CHAR szOutBuffer[1024] = { 0 };
TCHAR szBuf[MAX_PATH] = { 0 };
DWORD dwBytesReturned = 0;
if (0 == GetLogicalDriveStrings(_countof(szBuf), szBuf))
{
return false;
}
LPCTSTR lpDriveString = szBuf;
while (_T('\0') != *lpDriveString)
{
TCHAR szDeviceBuf[MAX_PATH] = { 0 };
HANDLE hDevice = INVALID_HANDLE_VALUE;
::StringCchCopy(szDeviceBuf, _countof(szDeviceBuf), _T(R"(\\.\)"));
::StringCchCatN(szDeviceBuf, _countof(szDeviceBuf), lpDriveString, 2);
hDevice = ::CreateFile(szDeviceBuf, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN,
NULL);
if (INVALID_HANDLE_VALUE == hDevice)
{
lpDriveString += 4;
continue;
}
if (::DeviceIoControl(hDevice,
IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
NULL,
0,
&szOutBuffer,
sizeof(szOutBuffer),
&dwBytesReturned,
NULL))
{
PVOLUME_DISK_EXTENTS pDesc = (PVOLUME_DISK_EXTENTS)szOutBuffer;
//当用户尝试获取有关没有软盘的软盘驱动器或没有光盘的 CD-ROM 驱动器的信息时,
//系统会显示一个消息框, 防止系统显示此消息框
(void)::SetErrorMode(SEM_FAILCRITICALERRORS);
//获取卷信息 (卷中的磁盘数可以跨多个磁盘) 。
for (DWORD i = 0; i < pDesc->NumberOfDiskExtents; i++)
{
PDISK_EXTENT pDiskExtent = &pDesc->Extents[i];
TCHAR szVolumeName[MAX_PATH] = { 0 };
DWORD dwVolumeSerialNumber = 0;
DWORD dwMaximumComponentLength = 0;
DWORD dwFileSystemFlags = 0;
TCHAR szFileSystemName[MAX_PATH] = { 0 };
::GetVolumeInformation(lpDriveString,
szVolumeName,
_countof(szVolumeName),
&dwVolumeSerialNumber,
&dwMaximumComponentLength,
&dwFileSystemFlags,
szFileSystemName,
_countof(szFileSystemName)
);
ULARGE_INTEGER FreeBytesAvailableToCaller = { 0 };
ULARGE_INTEGER TotalNumberOfBytes = { 0 };
ULARGE_INTEGER TotalNumberOfFreeBytes = { 0 };
GetDiskFreeSpaceEx(lpDriveString, &FreeBytesAvailableToCaller, &TotalNumberOfBytes, &TotalNumberOfFreeBytes);
LOGICAL_VOLUME_INFO info;
info.PathName = _tstring(lpDriveString).substr(0, 2);
info.VolumeName = szVolumeName;
info.FileSystemName = szFileSystemName;
info.DiskNumber = pDiskExtent->DiskNumber;
info.StartingOffset = *(unsigned long long*) & pDiskExtent->StartingOffset;
info.ExtentLength = *(unsigned long long*) & pDiskExtent->ExtentLength;
info.FreeBytes = TotalNumberOfFreeBytes.QuadPart;
info.DriveType = (eDriveType)::GetDriveType(lpDriveString);
vVolumeInfo.push_back(info);
}
}
::CloseHandle(hDevice);
lpDriveString += 4;
}
return true;
}
}
main.cpp
#include <locale.h>
#include <tchar.h>
#include "Win32Utils/CDiskDriveUtils.h"
int _tmain(int argc, LPCTSTR argv[])
{
setlocale(LC_ALL, "");
std::map<uint32_t, CDiskDriveUtils::DISK_DRIVE_INFO> diskInfoList = CDiskDriveUtils::GetDiskDriveInfos();
return 0;
}