windows下用wmi查询硬盘序列号最可靠,应使用win32_diskdrive类的serialnumber属性,需初始化com、设置代理凭据、遍历结果并trim空格;linux推荐smartctl -i直接读固件,macos须用iokit配合权限配置。

Windows下用WMI查询硬盘序列号最可靠
直接调用WMI(Windows Management Instrumentation)是C++原生获取物理硬盘序列号的主流方式,不依赖第三方库且能绕过驱动签名限制。关键在于用Win32_PhysicalMedia或Win32_DiskDrive类——前者返回SerialNumber字段更接近厂商写入的原始值,后者常返回空或模糊标识。
常见错误是误用Win32_Volume或Win32_BIOS,它们返回的是卷标或主板序列号;还有人用GetVolumeInformation,那只是逻辑卷序列号(16位整数),和物理硬盘无关。
- 必须初始化COM:先调
CoInitializeEx(nullptr, COINIT_MULTITHREADED),再CoInitializeSecurity设权限 - 查询时指定命名空间为
"root\CIMV2",不是"root\WMI"(后者部分字段不可用) - 结果需遍历
IEnumWbemClassObject,单次Next可能只返回部分对象,要循环直到WBEM_S_FALSE - 序列号字段可能含空格或不可见字符,建议用
Trim处理后再用
Linux下读取/sys/class/scsi_device/路径需适配设备模型
Linux没有统一API,/sys/class/scsi_device/是最接近“物理”的路径,但实际依赖内核SCSI子系统是否启用。NVMe盘走/sys/class/nvme/,SATA AHCI盘可能只暴露/sys/block/sdX/device/下的wwn或model,而非严格意义的序列号。
容易踩的坑是硬编码路径如/sys/block/sda/device/serial——很多设备该文件根本不存在,尤其虚拟机或USB盘。正确做法是遍历/sys/class/scsi_device/下的X:Y:Z:A目录,读取device/vpd_pg80(SCSI VPD页80h),它才是标准序列号来源。
- 读
vpd_pg80前需确认设备支持VPD:检查device/vpd_pg83是否存在,存在才说明支持标准VPD -
vpd_pg80内容是二进制,前4字节为长度,序列号从第4字节开始,需跳过头信息再提取ASCII字符串 - 权限问题常见:普通用户读
/sys通常可读,但某些发行版(如RHEL)需udev规则放行 - 注意区分
scsi_level:低于6的设备可能不支持VPD,fallback到model+rev拼接(不唯一)
macOS用IOKit获取序列号必须链接I/O Kit框架
macOS下IOServiceGetMatchingServices配合IOBSDNameMatching是唯一可行路径,但必须链接-framework IOKit -framework CoreFoundation,否则链接失败。直接读/dev/diskX设备节点或diskutil info输出不可靠——那是逻辑卷信息,且diskutil本身调的就是IOKit。
关键陷阱在于匹配条件:用kIOBlockStorageDeviceClass只能拿到块设备抽象层,真正序列号在kIOSCSIPeripheralDeviceType或kIONVMeControllerClass下。例如NVMe盘要查IOPropertyMatch中"NVME Serial Number"键,而SATA盘得查"Protocol Characteristics"里的"Serial Number"。
- 必须调
IOServiceWaitForNotify等待服务就绪,否则首次查询常返回空 - 结果是CFTypeRef类型,需用
CFStringGetCString转C字符串,注意编码为kCFStringEncodingUTF8 - 沙盒应用默认禁止IOKit访问,需在entitlements中添加
com.apple.developer.kernel.iokit权限 - Apple Silicon Mac上部分NVMe控制器(如自研SSD)序列号字段为空,只能fallback到
IORegistryEntryCreateCFProperty读"IOPlatformUUID"(非硬盘专属)
跨平台方案本质是妥协,别信“一次编写到处运行”
所谓“跨平台获取物理硬盘序列号”根本不存在标准实现。Windows靠WMI,Linux靠sysfs+VPD,macOS靠IOKit——三者底层机制、权限模型、甚至“序列号”定义都不同。硬写宏开关封装只会掩盖问题:比如Linux下ioctl调用HDIO_GET_IDENTITY在现代内核已被废弃,macOS的IOKit在ARM64模拟x86_64时行为异常。
真正可行的做法是分平台实现,且每个平台都准备fallback路径:WMI失败时尝试GetPhysicalDriveGeometry读取设备描述符;Linux下VPD不可用时查/sys/block/sdX/device/model和firmware_rev拼接;macOS则用system_profiler SPStorageDataType命令兜底。序列号唯一性无法保证,尤其在RAID、虚拟化、USB转接场景下,同一物理盘可能被识别为多个设备。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











