透過 DeviceIoControl 呼叫 SMART_RCV_DRIVE_DATA 控制碼,向磁碟控制器發送 IDENTIFY DEVICE 命令(ATA: 0xEC, ATAPI: 0xA1)取得識別資料區,解析序列號欄位。
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
internal struct IDSECTOR {
public ushort wGenConfig;
// ... 略 ...
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
public string sSerialNumber; // 序列號位於此欄位
// ... 略 ...
}
[StructLayout(LayoutKind.Sequential)]
internal struct SENDCMDINPARAMS {
public uint cBufferSize;
public IDEREGS irDriveRegs;
public byte bDriveNumber;
// ... 略 ...
}
[StructLayout(LayoutKind.Sequential)]
internal struct SENDCMDOUTPARAMS {
public uint cBufferSize;
public DRIVERSTATUS DriverStatus;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 513)]
public byte[] bBuffer; // 包含 IDSECTOR 資料
}
CreateFile 開啟 \\.\PhysicalDriveX 取得裝置控制代碼DeviceIoControl 呼叫 DFP_GET_VERSION 確認裝置支援SENDCMDINPARAMS 設定 ATA/ATAPI 識別命令DeviceIoControl 呼叫 DFP_RECEIVE_DRIVE_DATA 取得回應資料bBuffer 位移 20-39 位元組解析序列號(位元組序交換)CloseHandle 釋放資源public static string Read(byte drive) {
OperatingSystem os = Environment.OSVersion;
if (os.Platform != PlatformID.Win32NT) throw new NotSupportedException("僅支援 Windows NT/2000/XP");
string driveName = "\\\\.\\PhysicalDrive" + drive;
uint device = CreateFile(driveName, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
if (device == INVALID_HANDLE_VALUE) return "";
GETVERSIONOUTPARAMS verPara = new GETVERSIONOUTPARAMS();
uint bytRv = 0;
if (DeviceIoControl(device, DFP_GET_VERSION, 0, 0, ref verPara, Marshal.SizeOf(verPara), ref bytRv, 0) != 0) {
if (verPara.bIDEDeviceMap > 0) {
byte bIDCmd = (byte)((verPara.bIDEDeviceMap >> drive & 0x10) != 0 ? IDE_ATAPI_IDENTIFY : IDE_ATA_IDENTIFY);
SENDCMDINPARAMS scip = new SENDCMDINPARAMS();
SENDCMDOUTPARAMS scop = new SENDCMDOUTPARAMS();
scip.cBufferSize = IDENTIFY_BUFFER_SIZE;
scip.irDriveRegs.bFeaturesReg = 0;
scip.irDriveRegs.bSectorCountReg = 1;
scip.irDriveRegs.bCylLowReg = 0;
scip.irDriveRegs.bCylHighReg = 0;
scip.irDriveRegs.bDriveHeadReg = (byte)(0xA0 | ((drive & 1) << 4));
scip.irDriveRegs.bCommandReg = bIDCmd;
scip.bDriveNumber = drive;
if (DeviceIoControl(device, DFP_RECEIVE_DRIVE_DATA, ref scip, Marshal.SizeOf(scip), ref scop, Marshal.SizeOf(scop), ref bytRv, 0) != 0) {
StringBuilder s = new StringBuilder();
for (int i = 20; i < 40; i += 2) {
s.Append((char)scop.bBuffer[i + 1]);
s.Append((char)scop.bBuffer[i]);
}
CloseHandle(device);
return s.ToString().Trim();
}
}
}
CloseHandle(device);
return "";
}
注意: 需系統管理員權限執行;NVMe/SCSI/USB 裝置可能不支援此介面;建議搭配 WMI Win32_DiskDrive 作為替代方案。