2013-05-08 122 views
2

我已經寫了三種不同的方法,它們使用原生的CreateFileDeviceIoControl調用來檢索HDD序列號(不是型號)。第一個使用S.M.A.R.T.,第二個使用Storage Query和第三人使用SCSI PassThrough。我的大部分代碼都基於this thread的內容(有一些修復和改進)。C#/ Native:使用SCSI PassThrough讀取HDD串行

這裏是我開始使用diskid32 utility結果:

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] 

現在,這裏是用我的方法的結果:

S.M.A.R.T. = 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?

回答

3

您的代碼實際上是在我確定,即返回相同的數據在引用的線程所描述的其他方法。我不得不做出的唯一改變是從:

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(); 
+0

你有什麼樣的設備? – 2013-05-09 23:18:31

+0

64位Windows Server 2008 R2上的HP ML115,磁盤是GB0160CAABV。即使diskid32對於使用這些技術的所有驅動器都不會得到一致的結果 - 它似乎非常受到過去經驗的打擊和懷念。 – 2013-05-10 12:41:44

+0

很奇怪! -.- – 2013-05-10 23:43:29