如何得到硬盘序列号[C#](一)

2014-11-23 22:55:21 · 作者: · 浏览: 175

  硬盘序列号(Serial Number)不等于卷标号(Volume Name),后者虽然很容易得到,但是格式化分区后就会重写,不可靠。遗憾的是很多朋友往往分不清这一点。


  要得到硬盘的物理序列号,可以通过WMI,也就是Win32_PhysicalMedia.SerialNumber。可惜的是Windows 98/ME的WMI并不支持这个类,访问时会出现异常。


  受陆麟的例子的启发,我们还可以通过S.M.A.R.T.接口,直接从RING3调用API DeviceIoControl()来获取硬盘信息,而不需要写VXD或者DRIVER。这样这个问题就解决了,我对它进行了封装,大量使用了P/Invoke技术,一个完整的Library。支持Windows 98-2003。


  使用上很简单:


  HardDiskInfo hdd = AtapiDevice.GetHddInfo(0); // 第一个硬盘
  Console.WriteLine("Module Number: {0}", hdd.ModuleNumber);
  Console.WriteLine("Serial Number: {0}", hdd.SerialNumber);
  Console.WriteLine("Firmware: {0}", hdd.Firmware);
  Console.WriteLine("Capacity: {0} M", hdd.Capacity);


  下面是全部代码:


  using System;
  using System.Runtime.InteropServices;
  using System.Text;


  namespace Sunmast.Hardware
  {
  [Serializable]
  public struct HardDiskInfo
  {
  ///



  #region Internal Structs


  [StructLayout(LayoutKind.Sequential, Pack=1)]
  internal struct GetVersionOutParams
  {
  public byte bVersion;
  public byte bRevision;
  public byte bReserved;
  public byte bIDEDeviceMap;
  public uint fCapabilities;
  [MarshalAs(UnmanagedType.ByValArray, SizeConst=4)]
  public uint[] dwReserved; // For future use.
  }


  [StructLayout(LayoutKind.Sequential, Pack=1)]
  internal struct IdeRegs
  {
  public byte bFeaturesReg;
  public byte bSectorCountReg;
  public byte bSectorNumberReg;
  public byte bCylLowReg;
  public byte bCylHighReg;
  public byte bDriveHeadReg;
  public byte bCommandReg;
  public byte bReserved;
  }


  [StructLayout(LayoutKind.Sequential, Pack=1)]
  internal struct SendCmdInParams
  {
  public uint cBufferSize;
  public IdeRegs irDriveRegs;
  public byte bDriveNumber;
  [MarshalAs(UnmanagedType.ByValArray, SizeConst=3)]
  public byte[] bReserved;
  [MarshalAs(UnmanagedType.ByValArray, SizeConst=4)]
  public uint[] dwReserved;
  public byte bBuffer;
  }


  [StructLayout(LayoutKind.Sequential, Pack=1)]
  internal struct DriverStatus
  {
  public byte bDriverError;
  public byte bIDEStatus;
  [MarshalAs(UnmanagedType.ByValArray, SizeConst=2)]
  public byte[] bReserved;
  [MarshalAs(UnmanagedType.ByValArray, SizeConst=2)]
  public uint[] dwReserved;
  }


  [StructLayout(LayoutKind.Sequential, Pack=1)]
  internal struct SendCmdOutParams
  {
  public uint cBufferSize;
  public DriverStatus DriverStatus;
  public IdSector bBuffer;
  }


  [StructLayout(LayoutKind.Sequential, Pack=1, Size=512)]
  internal struct IdSector
  {
  public ushort wGenConfig;
  public ushort wNumCyls;
  public ushort wReserved;
  public ushort wNumHeads;
  public ushort wBytesPerTrack;
  public ushort wBytesPerSector;
  public ushort wSectorsPerTrack;
  [MarshalAs(UnmanagedType.ByValArray, SizeConst=3)]
  public ushort[] wVendorUnique;
  [MarshalAs(UnmanagedType.ByValArray, SizeConst=20)]
  public byte[] sSerialNumber;
  public ushort wBufferType;
  public ushort wBufferSize;
  public ushort wECCSize;
  [MarshalAs(UnmanagedType.ByValArray, SizeConst=8)]
  public byte[] sFirmwareRev;
  [MarshalAs(UnmanagedType.ByValArray, SizeConst=40)]
  public byte[] sModelNumber;
  public ushort wMoreVendorUnique;
  public ushort wDoubleWordIO;
  public ushort wCapabilities;
  public ushort wReserved1;
  public ushort wPIOTiming;
  public ushort wDMATiming;
  public ushort wBS;
  public ushort wNumCurrentCyls;
  public ushort wNumCurrentHeads;
  public ushort wNumCurrentSectorsPerTrack;
  public uint ulCurrentSectorCapacity;
  public ushort wMultSectorStuff;
  public uint ulTotalAddressableSectors;
  public ushort wSingleWordDMA;
  p