1、枚举所有硬盘
这里主要借助了setup API,这些API主要是NT4.0之后提供的一些用于操作设备的API。
枚举所有硬盘借助了SetupDiGetClassDevs与SetupDiEnumDeviceInterfaces和 SetupDiGetDeviceInterfaceDetail这三个API。
#pragma once
#ifndef DEVICE_DISK_H #define DEVICE_DISK_H #include <Windows.h> #include <Setupapi.h> #pragma comment( lib, "setupapi.lib" ) #define DevCount 1024 struct DevInterfaceDetaillArray { ?? ?DWORD szCount; ?? ?PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData_[DevCount]; };
int GetALLDISK(struct DevInterfaceDetaillArray* DevInterfaceDetailArr_);
int FreeALLDISK(struct DevInterfaceDetaillArray* DevInterfaceDetailArr_);
#endif ?
#include "DeviceDisk.h"
#include <iostream> #include <string> using namespace std;
//函数调用出错一定要记得回收内存,否则会内存泄漏。 //切记要与FreeALLDISK 成对使用。
int GetALLDISK(struct DevInterfaceDetaillArray* DevInterfaceDetailArr_) {
? ? HDEVINFO diskClassDevices; ? ? GUID diskClassDeviceInterfaceGuid = GUID_DEVINTERFACE_DISK; ? ? SP_DEVICE_INTERFACE_DATA deviceInterfaceData; ? ? PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData; ? ? DWORD requiredSize; ? ? DWORD deviceIndex;
? ? // ? ? // Get the handle to the device information set for installed ? ? // disk class devices. Returns only devices that are currently ? ? // present in the system and have an enabled disk device ? ? // interface. ? ? // ? ? diskClassDevices = SetupDiGetClassDevs(&diskClassDeviceInterfaceGuid, ? ? ? ? NULL, ? ? ? ? NULL, ? ? ? ? DIGCF_PRESENT | ? ? ? ? DIGCF_DEVICEINTERFACE); ? ?? ? ? if (INVALID_HANDLE_VALUE == diskClassDevices) { ? ? ? ? return -1; ? ? }
? ? ZeroMemory(&deviceInterfaceData, sizeof(SP_DEVICE_INTERFACE_DATA)); ? ? deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); ? ? deviceIndex = 0;
? ? while (SetupDiEnumDeviceInterfaces(diskClassDevices, ? ? ? ? NULL, ? ? ? ? &diskClassDeviceInterfaceGuid, ? ? ? ? deviceIndex, ? ? ? ? &deviceInterfaceData)) {
? ? ? ? SetupDiGetDeviceInterfaceDetail(diskClassDevices, ? ? ? ? ? ? &deviceInterfaceData, ? ? ? ? ? ? NULL, ? ? ? ? ? ? 0, ? ? ? ? ? ? &requiredSize, ? ? ? ? ? ? NULL); ? ? ? ? ? ? //回收掉临时内存 ? ? ? ? if (!(ERROR_INSUFFICIENT_BUFFER == GetLastError())) { ? ? ? ? ? ? wprintf_s(L"122\n"); //正常情况下,就是获得122错误码,咱也不知道windows在干啥。 ? ? ? ? ? ? if (INVALID_HANDLE_VALUE != diskClassDevices) { ? ? ? ? ? ? ? ? SetupDiDestroyDeviceInfoList(diskClassDevices); ? ? ? ? ? ? } ? ? ? ? ? ? return -1; ? ? ? ? }
? ? ? ? deviceInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(requiredSize);
? ? ? ? ZeroMemory(deviceInterfaceDetailData, requiredSize); ? ? ? ? deviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
? ? ? ? if (!SetupDiGetDeviceInterfaceDetail(diskClassDevices, ? ? ? ? ? ? &deviceInterfaceData, ? ? ? ? ? ? deviceInterfaceDetailData, ? ? ? ? ? ? requiredSize, ? ? ? ? ? ? NULL, ? ? ? ? ? ? NULL)) { ? ? ? ? ? ? //没有将此次的deviceInterfaceDetailData 内存返回到DevInterfaceDetailArr_中,所以在返回之前必须释放掉,防止内存泄漏。 ? ? ? ? ? ? free(deviceInterfaceDetailData); ? ? ? ? ? ? //回收掉临时内存 ? ? ? ? ? ? if (INVALID_HANDLE_VALUE != diskClassDevices) { ? ? ? ? ? ? ? ? SetupDiDestroyDeviceInfoList(diskClassDevices); ? ? ? ? ? ? } ? ? ? ? ? ? return -1; ? ? ? ? } ? ? ? ? ? ?? ? ? ? ? DevInterfaceDetailArr_->deviceInterfaceDetailData_[deviceIndex] = deviceInterfaceDetailData; ? ? ? ? ++deviceIndex; ? ? }
? ? DWORD Err_Code = GetLastError();
? ? DevInterfaceDetailArr_->szCount = deviceIndex;
? ? //返回之前回收临时内存 ? ? if (INVALID_HANDLE_VALUE != diskClassDevices) { ? ? ? ? SetupDiDestroyDeviceInfoList(diskClassDevices); ? ? } ? ? if (ERROR_NO_MORE_ITEMS == Err_Code) { ? ? ? ? //正常退出while的状态码:259,no more data availible。 ? ? ? ? return 0; ? ? } ? ? return -2; //0正常执行成功,-1循环内部执行出错,-2执行出错退出循环。 }
int FreeALLDISK(struct DevInterfaceDetaillArray* DevInterfaceDetailArr_) { ? ? for (int i = 0; i < DevInterfaceDetailArr_->szCount; i++) { ? ? ? ? free(DevInterfaceDetailArr_->deviceInterfaceDetailData_[i]); ? ? } ? ? return 0; }
2、获取硬盘信息(容量、制造商,销售商,版本,硬盘号(即硬盘在系统中显示的序号)等)
核心就是通过createfile打开硬盘设备,获得一个硬盘设备相关的处理句柄。
然后通过DeviceIoControl与对应的控制码来获取硬盘相关信息。
一个使用了这种类似方法的项目地址:GitHub - comefromezero/efiboot: a efiboot tool on windows
下面的代码只是示例,并不能直接运行。
??if (0 != GetALLDISK(&DevIn)) { ? ? ? ? wprintf_s(L"调用GetALLDISK出错!"); ? ? ? ? FreeALLDISK(&DevIn); ? ? ? ? return -1; ? ? } ? ? HANDLE hdisk = INVALID_HANDLE_VALUE ; ? ? PSTORAGE_DEVICE_DESCRIPTOR pDevDesc; ? ? STORAGE_PROPERTY_QUERY Query; ? ? DWORD dwOutBytes;
? ? Query.PropertyId = StorageDeviceProperty; ? ? Query.QueryType = PropertyStandardQuery; ? ?? ? ? pDevDesc = (PSTORAGE_DEVICE_DESCRIPTOR)new BYTE[sizeof(STORAGE_DEVICE_DESCRIPTOR) + 512 - 1]; ? ?? ? ? ZeroMemory(pDevDesc, sizeof(STORAGE_DEVICE_DESCRIPTOR) + 512 - 1); ? ? pDevDesc->Size = sizeof(STORAGE_DEVICE_DESCRIPTOR) + 512 - 1; ? ? //wprintf_s(L"%d", pDevDesc->Size); ? ?? ? ? //struct EFI_Disk_Info efi_disk[1024] = { 0 }; ? ? //g_efi_disk = efi_disk;
? ? GET_LENGTH_INFORMATION disk_len = { 0 }; ? ? STORAGE_DEVICE_NUMBER diskNumber = { 0 }; ? ? DWORD sizePar = sizeof(DRIVE_LAYOUT_INFORMATION_EX) + sizeof(PARTITION_INFORMATION_EX) * 128; ? ? PDRIVE_LAYOUT_INFORMATION_EX ParTable = (PDRIVE_LAYOUT_INFORMATION_EX)new BYTE[sizePar]; ? ? ZeroMemory(ParTable, sizePar); ? ? int devIndex = 0;
? ? TCHAR szPathName[MAX_PATH + 1] = { 0 };
? ? for (devIndex = 0; devIndex < DevIn.szCount; devIndex++) { ? ? ? ? wprintf_s(L"DiskInfo:%s\n", DevIn.deviceInterfaceDetailData_[devIndex]->DevicePath); ? ? ? ? hdisk = CreateFile(DevIn.deviceInterfaceDetailData_[devIndex]->DevicePath,? ? ? ? ? ? ? GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,? ? ? ? ? ? ? NULL, ? ? ? ? ? ? OPEN_EXISTING,? ? ? ? ? ? ? FILE_ATTRIBUTE_NORMAL, NULL); ? ? ? ? if (INVALID_HANDLE_VALUE == hdisk) { ? ? ? ? ? ? wprintf_s(L"createfile error! error_code:%d\n", GetLastError()); ? ? ? ? ? ? return -1; ? ? ? ? } ? ? ? ? if (!DeviceIoControl(hdisk, ? ? ? ? ? ? IOCTL_STORAGE_QUERY_PROPERTY, ? ? ? ? ? ? &Query, sizeof(STORAGE_PROPERTY_QUERY), ? ? ? ? ? ? pDevDesc, pDevDesc->Size, ? ? ? ? ? ? &dwOutBytes, ? ? ? ? ? ? NULL) ? ? ? ? ? ? ){? ? ? ? ? ? ? wprintf_s(L"DeviceIoControl Error! line:238 Error_Code:%d %d\n", GetLastError(),dwOutBytes); ? ? ? ? ? ?? ? ? ? ? ? ?? ? ? ? ? ? ?? ? ? ? ? } ? ? ? ? if (!DeviceIoControl(hdisk, IOCTL_DISK_GET_LENGTH_INFO, ? ? ? ? ? ? NULL, ? ? ? ? ? ? 0, ? ? ? ? ? ? &disk_len, sizeof(disk_len), &dwOutBytes, NULL)) {
? ? ? ? ? ? wprintf_s(L"DeviceIoControl Error! line:248 Error_Code:%d %d\n", GetLastError(), dwOutBytes); //122是正常的。
? ? ? ? }
? ? ? ? if (!DeviceIoControl(hdisk, ? ? ? ? ? ? IOCTL_STORAGE_GET_DEVICE_NUMBER, ? ? ? ? ? ? NULL, ? ? ? ? ? ? 0, ? ? ? ? ? ? &diskNumber, ? ? ? ? ? ? sizeof(STORAGE_DEVICE_NUMBER), ? ? ? ? ? ? &dwOutBytes, ? ? ? ? ? ? NULL)) {
? ? ? ? ? ? wprintf_s(L"DeviceIoControl Error! line:272 Error_Code:%d %d\n", GetLastError(), dwOutBytes);
? ? ? ? } ? ? ? ? dwOutBytes = 0; ? ? ? ? if (!DeviceIoControl(hdisk, ? ? ? ? ? ? IOCTL_DISK_GET_DRIVE_LAYOUT_EX, ? ? ? ? ? ? NULL, ? ? ? ? ? ? 0, ? ? ? ? ? ? ParTable, ? ? ? ? ? ? sizePar, ? ? ? ? ? ? &dwOutBytes, ? ? ? ? ? ? NULL)) {
? ? ? ? ? ? wprintf_s(L"DeviceIoControl Error! line:285 Error_Code:%d %d\n", GetLastError(), dwOutBytes);
? ? ? ? }
? ? ? ? g_efi_disk[devIndex] = (struct EFI_Disk_Info*)new (struct EFI_Disk_Info); ? ? ? ? CloseHandle(hdisk); ? ? ? ? hdisk = INVALID_HANDLE_VALUE; ? ? ? ? //wprintf_s(L"%d %d\n", dwOutBytes, pDevDesc->Size); ? ? ? ? char* p_char_string = (char*)pDevDesc; ? ? ? ? stringstream sz_buffer; ? ? ? ? g_efi_disk[devIndex]->productor = std::string(&p_char_string[pDevDesc->ProductIdOffset]); ? ? ? ? g_efi_disk[devIndex]->version = std::string(&p_char_string[pDevDesc->ProductRevisionOffset]); ? ? ? ? g_efi_disk[devIndex]->vendor = std::string(&p_char_string[pDevDesc->VendorIdOffset]); ? ? ? ? int buffer_disk_len = disk_len.Length.QuadPart / 1024 / 1024 / 1024; ? ? ? ? sz_buffer << buffer_disk_len << "GB"; ? ? ? ? g_efi_disk[devIndex]->length = sz_buffer.str(); ? ? ? ? g_efi_disk[devIndex]->number = std::to_string(diskNumber.DeviceNumber); ? ? ? ? printf_s("Productor:%s\n", g_efi_disk[devIndex]->productor.c_str()); ? ? ? ? printf_s("Version:%s\n", g_efi_disk[devIndex]->version.c_str()); ? ? ? ? printf_s("Vendor:%s\n", g_efi_disk[devIndex]->vendor.c_str()); ? ? ? ? printf_s("Length:%s\n", g_efi_disk[devIndex]->length.c_str()); ? ? ? ? printf_s("Number:%s\n", g_efi_disk[devIndex]->number.c_str());
? ? ? ? wprintf_s(L"===================================================================================\n"); ? ? ? ? wprintf_s(L"ParTable:\n"); ? ? ? ? wprintf_s(L"ParTableType:%d\n",ParTable->PartitionStyle); ? ? ? ? wprintf_s(L"ParCount:%d\n", ParTable->PartitionCount); ? ? ? ?? ? ? ? ? wprintf_s(L"Par0:\nParNum:%d\nParName:%s\n", ParTable->PartitionEntry[0].PartitionNumber,ParTable->PartitionEntry[0].Gpt.Name); ? ? ? ? wprintf_s(L"PatLength:%dMB\n", ParTable->PartitionEntry[0].PartitionLength.QuadPart / 1024 / 1024); ? ? ? ? wprintf_s(L"ParType:{%04x-%02x-%02x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n", ? ? ? ? ? ? ParTable->PartitionEntry[0].Gpt.PartitionType.Data1, ? ? ? ? ? ? ParTable->PartitionEntry[0].Gpt.PartitionType.Data2, ? ? ? ? ? ? ParTable->PartitionEntry[0].Gpt.PartitionType.Data3, ? ? ? ? ? ? ParTable->PartitionEntry[0].Gpt.PartitionType.Data4[0], ? ? ? ? ? ? ParTable->PartitionEntry[0].Gpt.PartitionType.Data4[1], ? ? ? ? ? ? ParTable->PartitionEntry[0].Gpt.PartitionType.Data4[2], ? ? ? ? ? ? ParTable->PartitionEntry[0].Gpt.PartitionType.Data4[3], ? ? ? ? ? ? ParTable->PartitionEntry[0].Gpt.PartitionType.Data4[4], ? ? ? ? ? ? ParTable->PartitionEntry[0].Gpt.PartitionType.Data4[5], ? ? ? ? ? ? ParTable->PartitionEntry[0].Gpt.PartitionType.Data4[6], ? ? ? ? ? ? ParTable->PartitionEntry[0].Gpt.PartitionType.Data4[7]); ? ? ? ? wprintf_s(L"ParGUID:{%04x-%02x-%02x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n", ? ? ? ? ? ? ParTable->PartitionEntry[0].Gpt.PartitionId.Data1, ? ? ? ? ? ? ParTable->PartitionEntry[0].Gpt.PartitionId.Data2, ? ? ? ? ? ? ParTable->PartitionEntry[0].Gpt.PartitionId.Data3, ? ? ? ? ? ? ParTable->PartitionEntry[0].Gpt.PartitionId.Data4[0], ? ? ? ? ? ? ParTable->PartitionEntry[0].Gpt.PartitionId.Data4[1], ? ? ? ? ? ? ParTable->PartitionEntry[0].Gpt.PartitionId.Data4[2], ? ? ? ? ? ? ParTable->PartitionEntry[0].Gpt.PartitionId.Data4[3], ? ? ? ? ? ? ParTable->PartitionEntry[0].Gpt.PartitionId.Data4[4], ? ? ? ? ? ? ParTable->PartitionEntry[0].Gpt.PartitionId.Data4[5], ? ? ? ? ? ? ParTable->PartitionEntry[0].Gpt.PartitionId.Data4[6], ? ? ? ? ? ? ParTable->PartitionEntry[0].Gpt.PartitionId.Data4[7]); ? ? ? ?? ? ? ? ? wprintf_s(L"返回的字节数:%d\n", dwOutBytes); ? ? ? ? //ParTable = { 0 }; ? ? ? ? wprintf_s(L"===================================================================================\n"); ? ? ? ? wsprintf(szPathName, L"\\\\\?\\Volume{%04x-%02x-%02x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\", ? ? ? ? ? ? ParTable->PartitionEntry[0].Gpt.PartitionId.Data1, ? ? ? ? ? ? ParTable->PartitionEntry[0].Gpt.PartitionId.Data2, ? ? ? ? ? ? ParTable->PartitionEntry[0].Gpt.PartitionId.Data3, ? ? ? ? ? ? ParTable->PartitionEntry[0].Gpt.PartitionId.Data4[0], ? ? ? ? ? ? ParTable->PartitionEntry[0].Gpt.PartitionId.Data4[1], ? ? ? ? ? ? ParTable->PartitionEntry[0].Gpt.PartitionId.Data4[2], ? ? ? ? ? ? ParTable->PartitionEntry[0].Gpt.PartitionId.Data4[3], ? ? ? ? ? ? ParTable->PartitionEntry[0].Gpt.PartitionId.Data4[4], ? ? ? ? ? ? ParTable->PartitionEntry[0].Gpt.PartitionId.Data4[5], ? ? ? ? ? ? ParTable->PartitionEntry[0].Gpt.PartitionId.Data4[6], ? ? ? ? ? ? ParTable->PartitionEntry[0].Gpt.PartitionId.Data4[7]); ? ? ? ? wprintf_s(L"%s\n", szPathName); ? ? } ? ? delete pDevDesc; ? ? FreeALLDISK(&DevIn);
?3、获取卷或分区相关信息(卷标名字和文件系统格式等)
核心API就是GetVolumeInfomation来获得对应的信息。
一个使用该办法的项目地址:
GitHub - comefromezero/efiboot: a efiboot tool on windows
以下示例不能直接运行。
if (0 == GetVolumeInformation(ParName, VolumeName, 1024, NULL, NULL, NULL, FileSysName, 1024)) { wprintf_s(L"Line:%d Err_Code:%d\n",__LINE__, GetLastError()); return -1; }
4、获取 volume所在硬盘的硬盘号
有了硬盘号就能通过createfile创建一个硬盘设备的句柄,然后利用DeviceIoControl获取硬盘相关信息。
一个使用该办法的项目地址:
GitHub - comefromezero/efiboot: a efiboot tool on windows
以下示例不能直接运行。
? ? //获取分区所在硬盘
? ? TCHAR Buf_Par_Name[1024] = { 0 }; ? ? memcpy(Buf_Par_Name, ParName, wstrlen(ParName)-4); //构建分区设备,用于createfile打开分区。 ? ? //wprintf_s(L" ? ?Line:%d ParName:%s\n",__LINE__, Buf_Par_Name); ? ? HANDLE h_vol = INVALID_HANDLE_VALUE; ? ? h_vol = CreateFile(Buf_Par_Name, ? ? ? ? GENERIC_READ, ? ? ? ? FILE_SHARE_READ | FILE_SHARE_WRITE, ? ? ? ? NULL, ? ? ? ? OPEN_EXISTING, ? ? ? ? FILE_ATTRIBUTE_NORMAL, NULL);
? ? if (INVALID_HANDLE_VALUE == h_vol) { ? ? ? ? wprintf_s(L"Line:%d Err_Code:%d\n",__LINE__, GetLastError()); ? ? ? ? return -1; ? ? }
? ? DWORD dwOutBytes = 0; ? ? PVOLUME_DISK_EXTENTS vol_disk_info = (PVOLUME_DISK_EXTENTS)new BYTE[sizeof(VOLUME_DISK_EXTENTS) + sizeof(DISK_EXTENT) * 10]; ? ? ZeroMemory(vol_disk_info, sizeof(VOLUME_DISK_EXTENTS) + sizeof(DISK_EXTENT) * 10); ? ? if (!DeviceIoControl(h_vol, ? ? ? ? IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, ? ? ? ? NULL, 0, ? ? ? ? vol_disk_info, sizeof(VOLUME_DISK_EXTENTS) + sizeof(DISK_EXTENT) * 10, ? ? ? ? &dwOutBytes, ? ? ? ? NULL) ? ? ? ? ) {
? ? ? ? wprintf_s(L"DeviceIoControl Error! line:%d Error_Code:%d %d\n",__LINE__, GetLastError(), dwOutBytes);
? ? }
其中VOLUME_DISK_EXTENTS结构体中就保存了硬盘号。
5、获取一个硬盘中所有的分区
?使用DeviceIoControl和控制码IOCTL_DISK_GET_DRIVE_LAYOUT_EX枚举出该硬盘的所有的分区入口项,然后就可以知道该硬盘上所有的分区数量以及其相关信息了。
6、枚举出所有的volume信息
FindFirstVolume与FindNextVolume这两个API可以枚举出所有的分区路径,然后通过GetVolumeInfomation这个API就能够获得对应的信息了。
这里有一个问题,在容量这个问题上,GetDiskFreeSpaceA这个获取的是簇的数量,这就有一个对齐的问题,这个API获得的volume容量可能与分区的实际容量不符,因为分区的时候没有文件系统,但是格式化为某个文件系统之后,文件系统对分区容量进行管理,所以出现GetDiskFreeSpaceA容量可能与分区的实际容量不符的问题,这需要注意一下。
系统中显示的volume容量与GetDiskFreeSpaceA容量一致。
|