使用IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER失败,如何无注册表获取Windows磁盘序列号?
获取磁盘序列号(无需注册表)的正确方法
你遇到的ERROR_INVALID_FUNCTION问题,本质是IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER这个控制码的兼容性极差——它只适配少数老式存储设备(比如早期IDE硬盘、部分可移动媒体),绝大多数现代硬盘(SSD、NVMe、SATA硬盘等)都不支持这个IOCTL,所以调用必然失败。
下面给你一个微软官方推荐的通用方案,使用IOCTL_STORAGE_QUERY_PROPERTY来获取磁盘序列号,兼容性覆盖几乎所有现代存储设备,且完全不需要读取注册表:
完整代码示例
#include <windows.h> #include <stdio.h> #include <initguid.h> #include <ntddstor.h> int main() { // 打开物理磁盘设备(注意替换PhysicalDrive0为你要查询的磁盘编号) HANDLE hDisk = CreateFile(L"\\\\.\\PhysicalDrive0", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hDisk == INVALID_HANDLE_VALUE) { printf("打开磁盘失败,错误码: %d\n", GetLastError()); return 1; } STORAGE_PROPERTY_QUERY query = {0}; query.PropertyId = StorageDeviceProperty; query.QueryType = PropertyStandardQuery; // 第一步:查询所需的输出缓冲区大小 STORAGE_DESCRIPTOR_HEADER header = {0}; DWORD bytesReturned = 0; if (!DeviceIoControl(hDisk, IOCTL_STORAGE_QUERY_PROPERTY, &query, sizeof(query), &header, sizeof(header), &bytesReturned, NULL)) { printf("获取描述符头部失败,错误码: %d\n", GetLastError()); CloseHandle(hDisk); return 1; } // 分配足够的缓冲区存储完整设备属性 DWORD bufferSize = header.Size; BYTE* buffer = (BYTE*)malloc(bufferSize); if (!buffer) { printf("内存分配失败\n"); CloseHandle(hDisk); return 1; } // 第二步:获取完整的设备属性数据 if (!DeviceIoControl(hDisk, IOCTL_STORAGE_QUERY_PROPERTY, &query, sizeof(query), buffer, bufferSize, &bytesReturned, NULL)) { printf("获取设备属性失败,错误码: %d\n", GetLastError()); free(buffer); CloseHandle(hDisk); return 1; } // 解析并输出磁盘序列号 STORAGE_DEVICE_DESCRIPTOR* deviceDesc = (STORAGE_DEVICE_DESCRIPTOR*)buffer; if (deviceDesc->SerialNumberOffset != 0) { // 磁盘序列号以UTF-16宽字符格式存储 WCHAR* serialNumberWide = (WCHAR*)(buffer + deviceDesc->SerialNumberOffset); printf("磁盘序列号(宽字符): %ls\n", serialNumberWide); // 如果需要转换为ANSI格式输出 char serialNumberAnsi[256]; WideCharToMultiByte(CP_ACP, 0, serialNumberWide, -1, serialNumberAnsi, sizeof(serialNumberAnsi), NULL, NULL); printf("磁盘序列号(ANSI): %s\n", serialNumberAnsi); } else { printf("该磁盘未提供序列号\n"); } // 清理资源 free(buffer); CloseHandle(hDisk); return 0; }
关键说明
- 权限要求:程序必须以管理员权限运行,否则
CreateFile会返回错误码5(拒绝访问)。 - 磁盘编号:
PhysicalDrive0对应系统中的第一块物理磁盘,你可以通过磁盘管理工具确认目标磁盘的编号。 - 编码处理:磁盘序列号是UTF-16编码,代码中提供了宽字符直接输出和ANSI转换两种方式,可按需选择。
- 逻辑磁盘适配:如果要获取C:、D:等逻辑驱动器对应的物理磁盘序列号,需要先通过
IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS获取逻辑卷关联的物理磁盘编号,再打开对应的PhysicalDriveN。
内容的提问来源于stack exchange,提问作者pts




