C#/ Native:使用SCSI PassThrough读取硬盘串口

我编写了三种不同的方法,使用本机CreateFileDeviceIoControl调用来检索HDD序列号(而不是型号)。 第一个使用SMART ,第二个使用Storage Query ,第三个使用SCSI PassThrough 。 我的大多数代码都基于此线程的内容(带有一些修复和改进)。

以下是我使用diskid32实用程序获得的结果:

 Trying to read the drive IDs using physical access with admin rights Drive Model Number________________: [ST975XXXXX] Drive Serial Number_______________: [ 6WS2XXXX] Trying to read the drive IDs using physical access with zero rights Product Id = [ST975XXXXX] Serial Number = [6WS2XXXX] Trying to read the drive IDs using Smart Drive Model Number________________: [ST975XXXXX] Drive Serial Number_______________: [ 6WS2XXXX] 

现在,这是使用我的方法的结果:

 SMART = 6WS2XXXX Storage Query = 6WS2XXXX SCSI PassThrough = ST975XXXXX 

嗯……休斯顿我们这里有问题。 使用前两种方法,我得到正确的序列号。 最后一个,我得到了非常糟糕的型号。 现在,这是我的代码:

 --- METHOD --- internal static String GetHardDiskSerialSCSIPassthrough(SafeFileHandle deviceHandle) { IntPtr bufferPointer = IntPtr.Zero; String serial = String.Empty; UInt32 bytesReturned; SCSIPassthroughBuffered bspt = new SCSIPassthroughBuffered(); bspt.SPT.Length = (UInt16)Marshal.SizeOf(bspt.SPT); bspt.SPT.CommandDescriptorBlockLength = 16; bspt.SPT.DataIn = 0x1; bspt.SPT.DataTransferLength = 64; bspt.SPT.DataBufferOffset = new IntPtr(Marshal.SizeOf(bspt) - 64); bspt.SPT.TimeOutValue = 60; bspt.SPT.CommandDescriptorBlock = new Byte[] { 0x12, 0x1, 0x80, 0x0, 64, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; Int32 bufferSize = Marshal.SizeOf(bspt); try { bufferPointer = Marshal.AllocHGlobal(bufferSize); Marshal.StructureToPtr(bspt, bufferPointer, true); if (DeviceIoControl(deviceHandle, 0x4D004, bufferPointer, (UInt32)bufferSize, bufferPointer, (UInt32)bufferSize, out bytesReturned, IntPtr.Zero) && (bytesReturned > 0)) { SCSIPassthroughBuffered result = (SCSIPassthroughBuffered)Marshal.PtrToStructure(bufferPointer, typeof(SCSIPassthroughBuffered)); serial = Encoding.ASCII.GetString(result.Buffer, 0, result.Buffer.Length).Replace("\0", String.Empty).Trim(); } } finally { Marshal.FreeHGlobal(bufferPointer); } return serial; } --- STRUCTURES --- [StructLayout(LayoutKind.Sequential)] private struct SCSIPassthrough { public UInt16 Length; public Byte SCSIStatus; public Byte PathID; public Byte TargetID; public Byte LogicalUnitNumber; public Byte CommandDescriptorBlockLength; public Byte SenseInfoLength; public Byte DataIn; public UInt32 DataTransferLength; public UInt32 TimeOutValue; public IntPtr DataBufferOffset; public UInt32 SenseInfoOffset; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public Byte[] CommandDescriptorBlock; } [StructLayout(LayoutKind.Sequential)] private struct SCSIPassthroughBuffered { public SCSIPassthrough SPT; public UInt32 Filler; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] public Byte[] Buffer; } 

我究竟做错了什么? 也许使用错误的CDB?

您的代码实际上对我来说运行正常,即它返回与引用线程中描述的其他方法相同的数据。 我必须做的唯一改变是:

 serial = Encoding.ASCII.GetString(result.Buffer, 0, result.Buffer.Length) .Replace("\0", String.Empty) .Trim(); 

至:

 serial = Encoding.ASCII.GetString(result.Buffer, 0, result.Buffer.Length) .Substring(IntPtr.Size) .Replace("\0", String.Empty) .Trim();