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序列号

原文地址:https://www.cnblogs.com/allen-gg/p/11245890.html

时间: 2024-08-04 19:37:29

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

获取iOS系统版本和设备的电量

获取iOS系统版本 --- UIDevice的使用 UIDevice类是一个单例,其唯一的实例( [UIDevice currentDevice] ) 代表了当前使用的设备. 通过这个实例,可以获得设备的相关信息(包括系统名称,版本号,设备模式等等). 也可以使用使用该实例来监测设备的特征(比如物理方向). NSString *strName = [[UIDevice currentDevice] name]; // 设备名称 NSString *strId = [[UIDevice curre

python基础——Linux系统下的文件目录结构

单用户操作系统和多用户操作系统 单用户操作系统:指一台计算机在同一时间只能由一个用户使用,一个用户独自享用系统的全部硬件和软件资源. 多用户操作系统:指一台计算机在同一时间可以由多个用户使用,多个用户共同享用系统的全部硬件和软件资源. UNIX和Linux的涉及初衷就是多用户操作系统. 在Linux中是没有盘符的概念,只有一个根目录/,所有的目录都是在它的下面. Linux目录速查表 /:根目录,一般根目录下只存放目录,在 linux 下有且只有一个根目录,所有的东西都是从这里开始 当在终端里输

UWP 应用获取各类系统、用户信息 (1) - 设备和系统的基本信息、应用包信息、用户数据账户信息和用户账户信息

应用开发中,开发者时常需要获取一些系统.用户信息用于数据统计遥测.问题反馈.用户识别等功能.本文旨在介绍在 Windows UWP 应用中获取一些常用系统.用户信息的方法.示例项目代码可参见 Github: https://github.com/validvoid/UWP-SystemInfoCollector 由于涉及内容较多,故本文会分为多篇展开.本篇介绍获取设备和系统的基本信息.应用包信息.用户数据账户信息和用户账户信息. 原博客阅读地址:http://validvoid.net/uwp-

获取与设置windows系统下音频设备音量

一.获取设备音量 不同系统获取音量的方法是有差别的,比如vista和win7获取音量的方式就是不同的,因此,我们应该首先获取系统的信息,然后根据系统信息,用其对应的方法获取音量. 1.OSVERSIONINFO 系统信息结构体 以下结构体均用于检索或设置系统信息. ANIMATIONINFO HW_PROFILE_INFO MINIMIZEDMETRICS NONCLIENTMETRICS OSVERSIONINFO SYSTEM_INFO 使用说明 在OSVERSIONINFO数据结构中包含操

Linux系统下实现iscsi共享存储

Linux系统下实现iscsi共享存储 iscsi简介:iscsi 是基于TCP/IP传输封装的SCSI数据包的块级别的共享,其也为C/S架构模型,服务器端提供客户端所需要的存储设备,客户端只需要进行挂载就可以将其当作自己主机上的存储设备进行分区.格式化使用. 实现iscsi需要的2个角色: iscsi target(server) 存储资源所在的iscsi服务器被称为"target".iscsi target通常是一个硬盘存储设备.当前大部分的主流操作系统都提供了配合iscsi ta

Linux系统下查看硬件设备信息

本节索引 Linux系统下查看硬件信息的工具有很多种,在生产中使用的也就是为数不多的几个,这里主要介绍三种工具分别为 dmidecode工具 lshw工具 ls*系列命令 inxi工具 dmidecode工具 由dmidecode软件包提供,查看关于机器硬件方面信息,比如BIOS,系统,主板,处理器,内存,缓存等.查看信息一般包括制造商,型号名称,序列号,版本,资产标签以及其他许多不同的细节.dmidecode把DMI数据库中的信息进行解码以文本方式打印.但是,dmi信息是可以人为的去修改,所以

在linux和Windows下配置HP FC存储设备多路径驱动

主机安装HBA卡驱动,一般光纤卡的厂家就是QLogic和Emulex的. Linux下查看光纤卡驱动模块是否加载通过 lsmod |grep qla2xxx #查看是否加载了QLogic的光纤卡模块 lsmod |grep lpfc #查看是否加载了Emulex的光纤卡模块 modprobe lpfc  #加载相应的光纤卡模块 Windows下查看设备管理器查看是否加载了驱动(如果没有的话安装相应的光纤卡驱动). 2. 查看光纤卡的WWN号(记录下来为存储设备映射时使用) Linux more 

Linux(RadHat)基础学习—系统存储设备与系统分区

1.系统存储设备 1.本地存储设备的识别 fdisk -l ##真实存在的设备,入插的u盘等 cat /proc/partitions ##系统识别的设备信息 blkid ##系统可使用的设备. df ##系统正在挂载的设备 blkid: cat /proc/partitions: df: 2.设备的挂载和卸载 1.设备名称 /dev/xdx ##dev/hd0 /dev/hd1 /dev/sda /dev/sdb /dev/sdb1 /dev/sda1 /dev/sda2 /dev/sr0 #

Linux下搭建iSCSI共享存储的方法 TGT 方式 CentOS6.9系统下

iSCSI(internet SCSI)技术由IBM公司研究开发,是一个供硬件设备使用的.可以在IP协议的上层运行的SCSI指令集,这种指令集合可以实现在IP网络上运行SCSI协议,使其能够在诸如高速千兆以太网上进行路由选择.iSCSI技术是一种新储存技术,该技术是将现有SCSI接口与以太网络(Ethernet)技术结合,使服务器可与使用IP网络的储存装置互相交换资料. iSCSI分为服务端和客户端,服务端需要安装scsi target用来共享存储设备,客户端需要安装iscsi initiato