一 起因:
因为近期需要写一个获取磁盘SMART数值的Windows 工具,研究了下相关文档,发现后续执行的所有DeviceIocontrol函数,都要先获取设备的物理编号,physicalX。记录下我查到的方法。
执行环境VS2019。
二 过程:
1. SetupDiGetClassDevs ()获取指向磁盘类型设备的信息集合指针 HDEVINFO。
2. SetupDiEnumDeviceInterfaces() 通过上一步获取的HDEVINFO,从0开始逐一枚举磁盘类设备是否存在,存在返回TRUE,设备信息放在 SP_DEVICE_INTERFACE_DATA结构中。
3. SetupDiGetDeviceInterfaceDetail() 根据上一步的SP_DEVICE_INTERFACE_DATA,获取devicepath(在PSP_DEVICE_INTERFACE_DETAIL_DATA结构中)。
4. HANDLE = CreateFile(),根据DevicePath,创建文件读写句柄。
5.DeviceIoControl(),使用第4步的handle, ctrl_code使用IOCTL_STORAGE_GET_DEVICE_NUMBER。返回STORAGE_DEVICE_NUMBER结构数值,device_number(id)和分区编号为结构中的变量。
三 详述:
1.SetupDiGetClassDevs
MSDN 解释:
The SetupDiGetClassDevs function returns a handle to a device information set that contains requested device information elements for a local computer.
简单来说,就是获取一个指定了类别或全部类别的所有已安装设备的信息集合,例如指定USB设备等等,返回一个HDEVINFO的指针,下面的函数会用到。
WINSETUPAPI HDEVINFO SetupDiGetClassDevsW(
const GUID *ClassGuid,
PCWSTR Enumerator,
HWND hwndParent,
DWORD Flags
);
参数说明:
PGUID ClassGuid
在创建设备列表的时候提供一个指向GUID的指针。如果设定了标志DIGCF_ALLCLASSES,则这个参数可以忽略,且列表结果中包括所有已经安装的设备类别。
在Winioctl.h文件中找到一些标志的定义
#define DiskClassGuid GUID_DEVINTERFACE_DISK //本次使用该标志,获取所有DISK类型的设备信息集合的指针。
#define CdRomClassGuid GUID_DEVINTERFACE_CDROM
#define PartitionClassGuid GUID_DEVINTERFACE_PARTITION
#define TapeClassGuid GUID_DEVINTERFACE_TAPE
#define WriteOnceDiskClassGuid GUID_DEVINTERFACE_WRITEONCEDISK
#define VolumeClassGuid GUID_DEVINTERFACE_VOLUME
#define MediumChangerClassGuid GUID_DEVINTERFACE_MEDIUMCHANGER
#define FloppyClassGuid GUID_DEVINTERFACE_FLOPPY
#define CdChangerClassGuid GUID_DEVINTERFACE_CDCHANGER
#define StoragePortClassGuid GUID_DEVINTERFACE_STORAGEPORT
#define HiddenVolumeClassGuid GUID_DEVINTERFACE_HIDDEN_VOLUME
#define GUID_CLASS_COMPORT GUID_DEVINTERFACE_COMPORT
#define GUID_SERENUM_BUS_ENUMERATOR GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR
PCTSTR Enumerator
提供包含设备实例的枚举注册表分支下的键名,可以通过它过滤梅举的内容:如:PCI则只显示PCI设备。如果这个参数没有指定,则要从整个枚举树中获取所有设备实例的设备信息。
HWND hwndParent
提供顶级窗口的句柄,所有用户接口可以使用它来与成员联系。
DWORD Flags
提供在设备信息结构中使用的控制选项。SetupApi.h文件中查看到如下的Flags:
#define DIGCF_DEFAULT 0x00000001 // only valid with DIGCF_DEVICEINTERFACE
#define DIGCF_PRESENT 0x00000002 //当前存在的设备
#define DIGCF_ALLCLASSES 0x00000004
#define DIGCF_PROFILE 0x00000008
#define DIGCF_DEVICEINTERFACE 0x00000010
本次配置如下,获取当前系统中的所有磁盘设备信息:
GUID lpGuid = GUID_DEVINTERFACE_DISK;
hDevInfoSet = SetupDiGetClassDevs(
&lpGuid, // class GUID
NULL, // Enumerator
NULL, // hwndParent
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE // present devices
);
四 源码:
DWORD CDiskToolDlg::GetDevicePath() { HDEVINFO hDevInfoSet; SP_DEVICE_INTERFACE_DATA deviceInterfaceData; PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData; DWORD DeviceIndex; BOOL result; GUID lpGuid; DWORD requiredSize; HANDLE handle; STORAGE_DEVICE_NUMBER diskNumber; DWORD bytesReturned; DeviceIndex = 0; lpGuid = GUID_DEVINTERFACE_DISK; //get a handle to a device information set hDevInfoSet = SetupDiGetClassDevs( &lpGuid, // class GUID NULL, // Enumerator NULL, // hwndParent DIGCF_PRESENT | DIGCF_DEVICEINTERFACE // present devices ); if (hDevInfoSet == INVALID_HANDLE_VALUE) { CString res_error; res_error.Format(_T("%d"), GetLastError());//转换成string logs_display(_T("获取设备句柄失败:") + res_error);//输出错误码 return (DWORD)-1; } result = true; ZeroMemory(&deviceInterfaceData, sizeof(SP_DEVICE_INTERFACE_DATA));//清空内存 deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);//函数硬性要求cbSize m_Device_List.ResetContent(); while(SetupDiEnumDeviceInterfaces(hDevInfoSet,NULL,&lpGuid,DeviceIndex,&deviceInterfaceData))//依此获取deviceInterfaceData { DeviceIndex++; SetupDiGetDeviceInterfaceDetail(hDevInfoSet, &deviceInterfaceData, NULL, 0, &requiredSize, NULL); if (ERROR_INSUFFICIENT_BUFFER == GetLastError())//如果Getlasterror的结果为ERROR_INSUFFICIENT_BUFFER,将返回requiresize值。 { deviceInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(requiredSize); ZeroMemory(deviceInterfaceDetailData, requiredSize); deviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); //抓取devicepath,deviceinterfacedetaildata.devicepath. result= SetupDiGetDeviceInterfaceDetail(hDevInfoSet, &deviceInterfaceData, deviceInterfaceDetailData, requiredSize, NULL, NULL); if (result) { handle = CreateFile(deviceInterfaceDetailData->DevicePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (handle!= INVALID_HANDLE_VALUE) { DeviceIoControl(handle, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &diskNumber, sizeof(STORAGE_DEVICE_NUMBER), &bytesReturned, NULL); CloseHandle(handle); BYTE b_deviceIndex=diskNumber.DeviceNumber; IsUsbType(UCHAR(b_deviceIndex)); device_count++; //ReadDiskSmart(UCHAR(b_deviceIndex)); } else { CString res_error; res_error.Format(_T("%d"), GetLastError());//转换成string logs_display(_T("CreateFile error:") + res_error);//输出错误码 return (DWORD)-1; } } else { CString res_error; res_error.Format(_T("%d"), GetLastError());//转换成string logs_display(_T("getdevicepath failure:") + res_error);//输出错误码 return (DWORD)-1; } } else { CString res_error; res_error.Format(_T("%d"), GetLastError());//转换成string logs_display(_T("获取需要的数据内存长度失败:") + res_error);//输出错误码 return (DWORD)-1; } } CString device_count_str; device_count_str.Format(_T("%d"), device_count); }//获取连接硬盘的PHYSICALX序列号
原文地址:https://www.cnblogs.com/allen-gg/p/11245890.html