VC++ 获取当前系统下存储设备的Physical ID

一   起因:

因为近期需要写一个获取磁盘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序列号

猜你喜欢

转载自www.cnblogs.com/allen-gg/p/11245890.html