【问题标题】:C#/Native: Reading HDD Serial Using SCSI PassThroughC#/Native:使用 SCSI PassThrough 读取 HDD 串行
【发布时间】:2013-05-02 20:00:04
【问题描述】:

我已经编写了三种不同的方法,它们利用本地 CreateFileDeviceIoControl 调用来检索 HDD 序列号(而不是型号)。第一个使用S.M.A.R.T.,第二个使用Storage Query,第三个使用SCSI PassThrough。我的大部分代码都是基于this thread 的内容(有一些修复和改进)。

这是我使用 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?

【问题讨论】:

    标签: c# .net winapi native serial-number


    【解决方案1】:

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

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

    【讨论】:

    • 你有什么样的设备?
    • HP ML115 上的 64 位 Windows Server 2008 R2,磁盘为 GB0160CAABV。即使是 diskid32 也不能为使用这些技术的所有驱动器获得一致的结果 - 从过去的经验来看,它似乎非常受欢迎。
    猜你喜欢
    • 2012-08-05
    • 2012-05-11
    • 2012-03-04
    • 2014-05-10
    • 2011-06-26
    • 1970-01-01
    • 2018-02-12
    • 1970-01-01
    • 2014-11-01
    相关资源
    最近更新 更多