Windows用WMI查询Win32_PhysicalMedia.SerialNumber需关联Win32_DiskDrive过滤并Trim空格;Linux按设备类型分流:SCSI/SATA读/sys/class/scsi_disk//device/vpd_pg80,NVMe读/sys/class/nvme//nvme*/serial,均需处理权限与硬件兼容性。

Windows下用WMI查询Win32_PhysicalMedia的SerialNumber
Windows没有提供标准C++ API直接读取硬盘物理序列号,WMI是最稳定、权限要求相对低的方式。注意:Win32_PhysicalMedia类返回的是硬盘制造商写入的物理序列号(非卷标或逻辑ID),但部分NVMe盘或虚拟磁盘可能返回空值或“0”。
实操要点:
立即学习“C++免费学习笔记(深入)”;
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 需链接
ole32.lib和oleaut32.lib,初始化COM(CoInitializeEx(nullptr, COINIT_MULTITHREADED)) - 查询时用
SELECT SerialNumber FROM Win32_PhysicalMedia,但必须关联Win32_DiskDrive过滤出真实物理盘(避免光驱、USB设备干扰) - 返回的
SerialNumber常含前后空格或不可见字符,务必用Trim()处理 - 管理员权限不是必须的,但某些企业环境策略可能拦截WMI查询,此时会返回空字符串而非报错
Linux下读取/sys/class/scsi_disk/*/device/vpd_pg80的ASCII序列号
Linux不依赖udev或smartctl,直接从sysfs读取VPD页最可靠。关键路径是/sys/class/scsi_disk/*/device/vpd_pg80,它对应SCSI标准的Page 0x80(Unit Serial Number),多数SATA/NVMe转接的盘也支持。
实操要点:
立即学习“C++免费学习笔记(深入)”;
- 遍历
/sys/class/scsi_disk/下的每个子目录,检查device/vpd_pg80是否存在且可读(部分USB-SATA桥芯片不实现该页) - 文件内容前2字节是长度,后跟ASCII序列号(无null终止),需跳过头2字节再截取指定长度
- 若读取失败(如Permission denied),不要fallback到
/sys/block/*/device/model——那是型号,不是序列号 - 注意NVMe原生设备走
/sys/class/nvme/*/nvme*/model和serial,但serial文件才是真实序列号,路径为/sys/class/nvme/*/nvme*/serial
跨平台方案只能拼接,不能统一API
没有POSIX或C++标准库函数能跨平台获取物理序列号。试图封装成单一接口容易掩盖差异,反而增加误判风险。
推荐做法:
- Windows走WMI,Linux按设备类型分流:SCSI/SATA用
vpd_pg80,NVMe用/sys/class/nvme/*/nvme*/serial,IDE或老旧USB盘可尝试hdparm -I /dev/sdX | grep "Serial Number"(需root) - 别信任
GetVolumeInformation或statfs——它们返回的是文件系统UUID或卷序列号,和物理盘无关 - 某些云主机或虚拟机返回的是虚拟磁盘ID(如AWS EBS的vol-xxxx),和宿主物理盘完全无关,需在调用前判断运行环境
权限、缓存与硬件兼容性是最大陷阱
拿到空字符串或乱码,90%不是代码写错,而是环境限制。
常见卡点:
- Windows Defender或EDR软件可能静默拦截WMI查询,现象是
WBEM_E_ACCESS_DENIED被吞掉,最终结果为空 - Linux容器中默认挂载的sysfs不含
vpd_pg80(需特权模式或手动bind-mount) - 消费级NVMe盘(尤其PCIe 4.0+)部分固件不响应VPD请求,此时
nvme id-ctrl命令也可能失败,只能放弃 - 序列号可能含非ASCII字符(如日韩厂商),C++ string按字节读取没问题,但显示时需确认终端编码
真正难的从来不是怎么调API,而是判断当前环境下哪条路径有效、哪条只是看起来像能跑通。

















