Windows下最可靠的磁盘序列号获取方式是调用DeviceIoControl发送IOCTL_STORAGE_QUERY_PROPERTY,需以管理员权限打开.PhysicalDrive0句柄,使用STORAGE_DEVICE_PROPERTY查询,返回UTF-16LE编码序列号并正确处理空格与截断。

c++如何获取磁盘的序列号和硬件信息_ioctl用法【进阶】

先说一下核心结论:在Windows平台上,直接调用DeviceIoControl发送IOCTL_STORAGE_QUERY_PROPERTY,是目前获取真实硬件序列号(注意,不是卷标,也不是驱动器号)最稳定、最可靠的方式。很多程序误用了GetVolumeInformation或者WMI,结果拿到的其实是卷序列号(volume serial number),跟硬盘物理标签完全是两码事。

这里的关键在于:必须以管理员权限打开物理设备句柄(比如\\.\PhysicalDrive0),并且需要结合STORAGE_PROPERTY_ID.StorageDevicePropertyStorageAdapterProtocolSpecificProperty,才能绕过某些NVMe设备设置的访问限制。具体操作中有几个地方需要特别注意:

Linux下用ioctl(fd, HDIO_GET_IDENTITY, ...)获取ATA硬盘信息失败怎么办

到了Linux这边,情况就有点不一样了。直接在/dev/sda上发HDIO_GET_IDENTITY,常常会失败,报错Operation not permittedInappropriate ioctl for device。很多人第一反应是权限问题,但实际上,这更多是内核策略的限制——从2.6.35+版本开始,内核默认禁止普通进程对块设备执行这个ioctl,特别是对SATA和NVMe设备,基本无效。

真正可行的方案,是读取sysfs接口:/sys/block/sda/device/model/sys/block/sda/device/serial,或者直接用smartctl -i /dev/sda(依赖smartmontools工具)。如果非要坚持用ioctl,那必须满足两个条件:

跨平台C++封装要注意struct packing和ioctl编号差异

Windows的IOCTL_STORAGE_QUERY_PROPERTY和Linux的HDIO_GET_IDENTITY,不仅语义完全不同,底层ioctl编号的构造规则也截然不同。Windows是通过CTL_CODE(...)宏生成的32位值,而Linux则是通过_IOR/_IOW宏按bit位域拼出来的。如果硬写宏常量,很可能在编译或运行时静默失败,查错会非常痛苦。

更隐蔽的问题在于结构体的内存布局。hd_driveid_t在x86/x86_64架构下默认对齐为2字节,而Windows的STORAGE_DEVICE_DESCRIPTOR要求1字节packed。如果不加#pragma pack(1)__attribute__((packed))DeviceIoControl可能返回ERROR_INVALID_PARAMETER,Linux那边则可能读到错位的字段,结果完全不可用。

序列号里混入空格、不可见字符、UTF-16 BOM是常见陷阱

从实际开发的角度看,市面上有哪些坑?Windows返回的STORAGE_DEVICE_DESCRIPTOR中,SerialNumberOffset指向的字符串是UTF-16LE编码,而且末尾不保证有\0终止符。Linux的hd_driveid_t.serial_no是ASCII字符数组,但厂商常常填满20字节,中间混入空格或0x00/0x20交替填充。如果直接用std::string((char*)ptr, len),很可能截断或引入乱码。

最后需要提醒一句:硬件序列号本身其实并不可靠。部分OEM盘(比如戴尔、惠普定制的SSD)会返回全0或固定字符串,这时候只能fallback到WWN或NVMe EUI-64,不过那已经不属于“序列号”的范畴了。

本文转载于:https://www.php.cn/faq/2343882.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。