您现在的位置: 中国男护士网 >> 考试频道 >> 计算机等级 >> 二级辅导 >> C语言 >> 辅导 >> 正文    
  如何得到硬盘序列号[C#] 【注册男护士专用博客】          

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

www.nanhushi.com     佚名   不详 

  硬盘序列号(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
  {
  /// <summary>
  /// 型号
  /// </summary>
  public string ModuleNumber;
  /// <summary>
  /// 固件版本
  /// </summary>
  public string Firmware;
  /// <summary>
  /// 序列号
  /// </summary>
  public string SerialNumber;
  /// <summary>
  /// 容量,以M为单位
  /// </summary>
  public uint Capacity;
  }

  #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;
  public ushort wMultiWordDMA;
  [MarshalAs(UnmanagedType.ByValArray, SizeConst=128)]
  public byte[] bReserved;
  }

  #endregion

  /// <summary>
  /// ATAPI驱动器相关
  /// </summary>
  public class AtapiDevice
  {

  #region DllImport

  [DllImport("kernel32.dll", SetLastError=true)]
  static extern int CloseHandle(IntPtr hObject);

  [DllImport("kernel32.dll", SetLastError=true)]
  static extern IntPtr CreateFile(
  string lpFileName,
  uint dwDesiredAccess,
  uint dwShareMode,
  IntPtr lpSecurityAttributes,
  uint dwCreationDisposition,
  uint dwFlagsAndAttributes,
  IntPtr hTemplateFile);

  [DllImport("kernel32.dll")]
  static extern int DeviceIoControl(
  IntPtr hDevice,
  uint dwIoControlCode,
  IntPtr lpInBuffer,
  uint nInBufferSize,
  ref GetVersionOutParams lpOutBuffer,
  uint nOutBufferSize,
  ref uint lPBytesReturned,
  [Out] IntPtr lpOverlapped);

  [DllImport("kernel32.dll")]
  static extern int DeviceIoControl(
  IntPtr hDevice,
  uint dwIoControlCode,
  ref SendCmdInParams lpInBuffer,
  uint nInBufferSize,
  ref SendCmdOutParams lpOutBuffer,
  uint nOutBufferSize,
  ref uint lpBytesReturned,
  [Out] IntPtr lpOverlapped);

  const uint DFP_GET_VERSION = 0x00074080;
  const uint DFP_SEND_DRIVE_COMMAND = 0x0007c084;
  const uint DFP_RECEIVE_DRIVE_DATA = 0x0007c088;

  const uint GENERIC_READ = 0x80000000;
  const uint GENERIC_WRITE = 0x40000000;
  const uint FILE_SHARE_READ = 0x00000001;
  const uint FILE_SHARE_WRITE = 0x00000002;
  const uint CREATE_NEW = 1;
  const uint OPEN_EXISTING = 3;

  #endregion

  #region GetHddInfo

  /// <summary>
  /// 获得硬盘信息
  /// </summary>
  /// <param name="driveIndex">硬盘序号</param>
  /// <returns>硬盘信息</returns>
  /// <remarks>
  /// 参考lu0的文章:http://lu0s1.3322.org/App/2k1103.html
  /// by sunmast for everyone
  /// thanks lu0 for his great works
  /// 在Windows 98/ME中,S.M.A.R.T并不缺省安装,请将SMARTVSD.VXD拷贝到%SYSTEM%\IOSUBSYS目录下。
  /// 在Windows 2000/2003下,需要Administrators组的权限。
  /// </remarks>
  /// <example>
  /// AtapiDevice.GetHddInfo()
  /// </example>
  public static HardDiskInfo GetHddInfo(byte driveIndex)
  {
  switch(Environment.OSVersion.Platform)
  {
  case PlatformID.Win32Windows:
  return GetHddInfo9x(driveIndex);
  case PlatformID.Win32NT:
  return GetHddInfoNT(driveIndex);
  case PlatformID.Win32S:
  throw new NotSupportedException("Win32s is not supported.");
  case PlatformID.WinCE:
  throw new NotSupportedException("WinCE is not supported.");
  default:
  throw new NotSupportedException("Unknown Platform.");
  }
  }

  #region GetHddInfo9x

  private static HardDiskInfo GetHddInfo9x(byte driveIndex)
  {
  GetVersionOutParams vers = new GetVersionOutParams();
  SendCmdInParams inParam = new SendCmdInParams();
  SendCmdOutParams outParam = new SendCmdOutParams();
  uint bytesReturned = 0;

  IntPtr hDevice = CreateFile(
  @"\\.\Smartvsd",
  0,
  0,
  IntPtr.Zero,
  CREATE_NEW,
  0,
  IntPtr.Zero);
  if (hDevice == IntPtr.Zero)
  {
  throw new Exception("Open smartvsd.vxd failed.");
  }
  if (0 == DeviceIoControl(
  hDevice,
  DFP_GET_VERSION,
  IntPtr.Zero,
  0,
  ref vers,
  (uint)Marshal.SizeOf(vers),
  ref bytesReturned,
  IntPtr.Zero))
  {
  CloseHandle(hDevice);
  throw new Exception("DeviceIoControl failed:DFP_GET_VERSION");
  }
  // If IDE identify command not supported, fails
  if (0 == (vers.fCapabilities & 1))
  {
  CloseHandle(hDevice);
  throw new Exception("Error: IDE identify command not supported.");
  }
  if (0 != (driveIndex & 1))
  {
  inParam.irDriveRegs.bDriveHeadReg = 0xb0;
  }
  else
  {
  inParam.irDriveRegs.bDriveHeadReg = 0xa0;
  }
  if (0 != (vers.fCapabilities & (16 >> driveIndex)))
  {
  // We don''t detect a ATAPI device.
  CloseHandle(hDevice);
  throw new Exception(string.Format("Drive {0} is a ATAPI device, we don''t detect it",driveIndex + 1));
  }
  else
  {
  inParam.irDriveRegs.bCommandReg = 0xec;
  }
  inParam.bDriveNumber = driveIndex;
  inParam.irDriveRegs.bSectorCountReg = 1;
  inParam.irDriveRegs.bSectorNumberReg = 1;
  inParam.cBufferSize = 512;
  if (0 == DeviceIoControl(
  hDevice,
  DFP_RECEIVE_DRIVE_DATA,
  ref inParam,
  (uint)Marshal.SizeOf(inParam),
  ref outParam,
  (uint)Marshal.SizeOf(outParam),
  ref bytesReturned,
  IntPtr.Zero))
  {
  CloseHandle(hDevice);
  throw new Exception("DeviceIoControl failed: DFP_RECEIVE_DRIVE_DATA");
  }
  CloseHandle(hDevice);

  return GetHardDiskInfo(outParam.bBuffer);
  }

  #endregion

  #region GetHddInfoNT

  private static HardDiskInfo GetHddInfoNT(byte driveIndex)
  {
  GetVersionOutParams vers = new GetVersionOutParams();
  SendCmdInParams inParam = new SendCmdInParams();
  SendCmdOutParams outParam = new SendCmdOutParams();
  uint bytesReturned = 0;

  // We start in NT/Win2000
  IntPtr hDevice = CreateFile(
  string.Format(@"\\.\PhysicalDrive{0}",driveIndex),
  GENERIC_READ | GENERIC_WRITE,
  FILE_SHARE_READ | FILE_SHARE_WRITE,
  IntPtr.Zero,
  OPEN_EXISTING,
  0,
  IntPtr.Zero);
  if (hDevice == IntPtr.Zero)
  {
  throw new Exception("CreateFile faild.");
  }
  if (0 == DeviceIoControl(
  hDevice,
  DFP_GET_VERSION,
  IntPtr.Zero,
  0,
  ref vers,
  (uint)Marshal.SizeOf(vers),
  ref bytesReturned,
  IntPtr.Zero))
  {
  CloseHandle(hDevice);
  throw new Exception(string.Format("Drive {0} may not exists.",driveIndex + 1));
  }
  // If IDE identify command not supported, fails
  if (0 == (vers.fCapabilities & 1))
  {
  CloseHandle(hDevice);
  throw new Exception("Error: IDE identify command not supported.");
  }
  // Identify the IDE drives
  if (0 != (driveIndex & 1))
  {
  inParam.irDriveRegs.bDriveHeadReg = 0xb0;
  }
  else
  {
  inParam.irDriveRegs.bDriveHeadReg=0xa0;
  }
  if (0 != (vers.fCapabilities & (16 >> driveIndex)))
  {
  // We don''t detect a ATAPI device.
  CloseHandle(hDevice);
  throw new Exception(string.Format("Drive {0} is a ATAPI device, we don''t detect it.",driveIndex + 1));
  }
  else
  {
  inParam.irDriveRegs.bCommandReg = 0xec;
  }
  inParam.bDriveNumber = driveIndex;
  inParam.irDriveRegs.bSectorCountReg = 1;
  inParam.irDriveRegs.bSectorNumberReg = 1;
  inParam.cBufferSize = 512;

  if (0 == DeviceIoControl(
  hDevice,
  DFP_RECEIVE_DRIVE_DATA,
  ref inParam,
  (uint)Marshal.SizeOf(inParam),
  ref outParam,
  (uint)Marshal.SizeOf(outParam),
  ref bytesReturned,
  IntPtr.Zero))
  {
  CloseHandle(hDevice);
  throw new Exception("DeviceIoControl failed: DFP_RECEIVE_DRIVE_DATA");
  }
  CloseHandle(hDevice);

  return GetHardDiskInfo(outParam.bBuffer);
  }

  #endregion

  private static HardDiskInfo GetHardDiskInfo(IdSector phdinfo)
  {
  HardDiskInfo hddInfo = new HardDiskInfo();

  ChangeByteOrder(phdinfo.sModelNumber);
  hddInfo.ModuleNumber = Encoding.ASCII.GetString(phdinfo.sModelNumber).Trim();

  ChangeByteOrder(phdinfo.sFirmwareRev);
  hddInfo.Firmware = Encoding.ASCII.GetString(phdinfo.sFirmwareRev).Trim();

  ChangeByteOrder(phdinfo.sSerialNumber);
  hddInfo.SerialNumber = Encoding.ASCII.GetString(phdinfo.sSerialNumber).Trim();

  hddInfo.Capacity = phdinfo.ulTotalAddressableSectors / 2 / 1024;

  return hddInfo;
  }

  private static void ChangeByteOrder(byte[] charArray)
  {
  byte temp;
  for(int i = 0; i < charArray.Length; i += 2)
  {
  temp = charArray[i];
  charArray[i] = charArray[i+1];
  charArray[i+1] = temp;
  }
  }

  #endregion
  }
  }

  注:

  在Windows 98/ME中,S.M.A.R.T并不缺省安装,请将SMARTVSD.VXD拷贝到%SYSTEM%\IOSUBSYS目录下。
  在Windows 2000/2003下,需要Administrators组的权限。
  不要在装有SCSI硬盘的机器上尝试了,因为SCSI硬盘根本不存在序列号。

  最终版权归陆麟所有,任何人不得将此代码占为己有。

 

文章录入:杜斌    责任编辑:杜斌 
  • 上一篇文章:

  • 下一篇文章:
  • 【字体: 】【发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
     

    联 系 信 息
    QQ:88236621
    电话:15853773350
    E-Mail:malenurse@163.com
    免费发布招聘信息
    做中国最专业男护士门户网站
    最 新 热 门
    最 新 推 荐
    相 关 文 章
    没有相关文章
    专 题 栏 目