如何获取NVMe硬盘的真实序列号?
解决Delphi中获取NVMe真实序列号的问题
1. 修正IOCTL_STORAGE_QUERY_PROPERTY的调用参数
IOCTL_STORAGE_QUERY_PROPERTY默认返回通用存储设备信息,而非NVMe专属序列号。需指定协议特定属性获取NVMe原生数据:
- 将
STORAGE_PROPERTY_QUERY的PropertyId设为StorageDeviceProtocolSpecificProperty QueryType设为PropertyStandardQuery- 在
AdditionalParameters中填充STORAGE_PROTOCOL_SPECIFIC_DATA,指定ProtocolType为ProtocolTypeNvme,DataType为NVMeDataTypeIdentify(对应NVMe的Identify命令)
2. 严格匹配Windows API的Delphi结构体定义
NVMe相关结构体的字节布局必须和C语言完全一致,否则会解析错误。关键结构体示例:
type STORAGE_PROTOCOL_SPECIFIC_DATA = packed record ProtocolType: DWORD; DataType: DWORD; ProtocolDataRequestValue: DWORD; ProtocolDataRequestSubValue: DWORD; ProtocolDataOffset: DWORD; ProtocolDataLength: DWORD; FixedProtocolReturnData: array[0..31] of Byte; end; NVME_IDENTIFY_NAMESPACE_DATA = packed record NamespaceSize: UInt64; Capacity: UInt64; LBAFormat: array[0..15] of Byte; SerialNumber: array[0..29] of AnsiChar; // NVMe序列号为30字节ASCII // 省略其他无关字段 end;
必须使用packed record保证结构体无额外对齐字节,避免字段偏移错误。
3. 直接发送NVMe Identify命令(替代方案)
若IOCTL_STORAGE_QUERY_PROPERTY仍无效,可通过IOCTL_SCSI_PASS_THROUGH_DIRECT直接发送NVMe Identify命令(命令码0x06):
- 构造
SCSI_PASS_THROUGH_DIRECT结构,指定CdbLength为16(NVMe命令CDB长度),数据方向设为DataIn - CDB数组填充命令参数:操作码0x06,目标命名空间ID
- 用
NVME_IDENTIFY_NAMESPACE_DATA作为接收缓冲区,提取SerialNumber字段
4. 常见排查点
- 程序需以管理员权限运行:存储设备IOCTL调用需要高权限,普通权限可能返回错误或无效数据
- 验证设备路径正确性:需打开NVMe物理设备路径(如
\\.\PhysicalDriveX),而非逻辑盘符 - 检查错误码:调用
DeviceIoControl后,通过GetLastError()获取具体错误,定位参数或结构问题
内容的提问来源于stack exchange,提问作者yonni
相关产品推荐
相关产品推荐

