您的位置:首页 > 其它

.NET相关的获取硬盘物理序列号的方法

2017-08-03 14:48 183 查看
来源不详:
最近作软件注册,收集了很多.NET相关的获取硬盘物理序列号的方法,主要分为使用WMI方式和API方式。但这些方法均可能有问题。
 
1,使用WMI方式,有的机器根本取不到硬盘序列号,有的方式在Vista下面会报错。
 
常用的使用WMI的方式主要有下面一些方式:
 
class HardDrive
    {
        privatestring model = null;

        privatestring type = null;

        privatestring serialNo = null;

 
        publicstring Model
        {
            get{return model;}

            set{model = value;}

        }
 
        publicstring Type
        {
            get{return type;}
            set{type = value;}

        }
 
        publicstring SerialNo
        {
            get{return serialNo;}

            set{serialNo = value;}

        }
    }
 
    classTestProgram
    {
        ///<summary>
        /// Themain entry point for the application.

        ///</summary>
       [STAThread]
        staticvoid Main(string[] args)

        {
            //在Vista下面失败

           ArrayList hdCollection = new ArrayList();

 
           ManagementObjectSearcher searcher = new

               ManagementObjectSearcher("SELECT * FROM Win32_DiskDrive");

 
           foreach(ManagementObject wmi_HD in searcher.Get())

            {
               HardDrive hd = new HardDrive();

               hd.Model    =wmi_HD["Model"].ToString();

               hd.Type     =wmi_HD["InterfaceType"].ToString();

 
               hdCollection.Add(hd);

            }
 
           searcher = new
               ManagementObjectSearcher("SELECT * FROM Win32_PhysicalMedia");
 
            inti = 0;
           foreach(ManagementObject wmi_HD in searcher.Get())

            {
               // get the hard drive from collection

               // using index
               HardDrive hd = (HardDrive)hdCollection[i];

 
               // get the hardware serial no.

               if (wmi_HD["SerialNumber"] == null)

                    hd.SerialNo = "None";

               else
                   hd.SerialNo = wmi_HD["SerialNumber"].ToString();

 
               ++i;
            }
 
            //Display available hard drives

           foreach(HardDrive hd in hdCollection)

            {
               Console.WriteLine("Model\t\t: " + hd.Model);

               Console.WriteLine("Type\t\t: " + hd.Type);

               Console.WriteLine("Serial No.\t: " + hd.SerialNo);

               Console.WriteLine();

            }
 
            //Pause application

           Console.WriteLine("Press [Enter] to exit...");

           Console.ReadLine();

        }
    }
 上面的方式先查询Win32_DiskDrive,然后再查询 Win32_PhysicalMedia,经过测试,这种方式不能保证在所有机器上均取得硬盘序列号,而且在Vista下面还会出错,程序直接抛出无法处理的异常。
 
 
另外,还可以使用另外一WMI方式,就是查询 PNPDeviceID
的 signature,代码如下:
 
/// <summary>
       /// 获取硬盘唯一序列号(不是卷标号),可能需要以管理员身份运行程序

       ///</summary>
       ///<returns></returns>
        publicstatic string GetHdId()

        {
           ManagementObjectSearcher wmiSearcher = new ManagementObjectSearcher();

            /*
             *PNPDeviceID   的数据是由四部分组成的:   

  1、接口,通常有   IDE,ATA,SCSI;   

  2、型号   

  3、(可能)驱动版本号   

  4、(可能)硬盘的出厂序列号   

            * 
             * 
             */
 
 
           //signature 需要程序以管理员身份运行(经过测试,2003系统上非管理员身份也可以运行,查相关资料说,可能在2000系统上获取的值为空)

 
           wmiSearcher.Query = new SelectQuery(

           "Win32_DiskDrive",
           "",
            newstring[] { "PNPDeviceID", "signature" }

            );
           ManagementObjectCollection myCollection = wmiSearcher.Get();

           ManagementObjectCollection.ManagementObjectEnumerator em =

           myCollection.GetEnumerator();

           em.MoveNext();
           ManagementBaseObject mo = em.Current;

           //string id =mo.Properties["PNPDeviceID"].Value.ToString().Trim();

           string id =mo.Properties["signature"].Value.ToString().Trim();

           return id;
        }
 
 
有人说,使用 signature 需要程序以管理员身份运行(经过测试,2003系统上非管理员身份也可以运行),而且查询相关资料说,可能在2000系统上获取的值为空。
 
使用这种方式,在Vista上面工作良好。
 
经过测试,使用 signature  均能够取得硬盘序列号,但是跟 Win32_PhysicalMedia
查询出来的号不一样。目前我也不能肯定 使用signature  能够100%取道硬盘序列号。
 
 
 
使用WMI方式需要客户机开启WMI服务,但这个往往不能保证,所以使用这种方式有一定局限性。
 
 
 
2,使用API方式。
 
在网上找到一片资料,说使用 RING3调用 APIDeviceIoControl()来获取硬盘信息,下面是原话:
 
硬盘序列号(Serial Number)不等于卷标号(VolumeName),后者虽然很容易得到,但是格式化分区后就会重写,不可靠。遗憾的是很多朋友往往分不清这一点。
 
要得到硬盘的物理序列号,可以通过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 HardwareUtility
{
   [Serializable]
    publicstruct HardDiskInfo
    {
        ///<summary>
        /// 型号

        ///</summary>
        publicstring ModuleNumber;

        ///<summary>
        /// 固件版本

        ///</summary>
        publicstring Firmware;

        ///<summary>
        /// 序列号

        ///</summary>
        publicstring SerialNumber;

        ///<summary>
        /// 容量,以M为单位

        ///</summary>
        publicuint Capacity;
    }
 
    #regionInternal Structs
 
   [StructLayout(LayoutKind.Sequential, Pack = 1)]

    internalstruct GetVersionOutParams

    {
        publicbyte bVersion;
        public byte bRevision;

        publicbyte bReserved;
        publicbyte bIDEDeviceMap;

        publicuint fCapabilities;

       [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]

        publicuint[] dwReserved; // For future use.

    }
 
   [StructLayout(LayoutKind.Sequential, Pack = 1)]

    internalstruct IdeRegs
    {
        publicbyte bFeaturesReg;

        publicbyte bSectorCountReg;

        publicbyte bSectorNumberReg;

        publicbyte bCylLowReg;

        publicbyte bCylHighReg;

        publicbyte bDriveHeadReg;

        publicbyte bCommandReg;

        publicbyte bReserved;
    }
 
   [StructLayout(LayoutKind.Sequential, Pack = 1)]

    internalstruct SendCmdInParams

    {
        publicuint cBufferSize;

        public IdeRegs irDriveRegs;

        publicbyte bDriveNumber;

       [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]

        publicbyte[] bReserved;

       [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]

        publicuint[] dwReserved;

        publicbyte bBuffer;
    }
 
   [StructLayout(LayoutKind.Sequential, Pack = 1)]

    internalstruct DriverStatus

    {
        publicbyte bDriverError;

        publicbyte bIDEStatus;

       [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]

        publicbyte[] bReserved;

       [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]

        publicuint[] dwReserved;

    }
 
   [StructLayout(LayoutKind.Sequential, Pack = 1)]

    internal struct SendCmdOutParams

    {
        publicuint cBufferSize;

        publicDriverStatus DriverStatus;

        publicIdSector bBuffer;

    }
 
   [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 512)]

    internalstruct IdSector
    {
        publicushort wGenConfig;

        publicushort wNumCyls;

        publicushort wReserved;

        publicushort wNumHeads;

        publicushort wBytesPerTrack;

        publicushort wBytesPerSector;

        publicushort wSectorsPerTrack;

       [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]

        publicushort[] wVendorUnique;

       [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]

        publicbyte[] sSerialNumber;

        publicushort wBufferType;

        publicushort wBufferSize;

        publicushort wECCSize;

       [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]

        publicbyte[] sFirmwareRev;

       [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]

        publicbyte[] sModelNumber;

        publicushort wMoreVendorUnique;

        publicushort wDoubleWordIO;

        publicushort wCapabilities;

        publicushort wReserved1;

        publicushort wPIOTiming;

        publicushort wDMATiming;

        publicushort wBS;
        publicushort wNumCurrentCyls;

        publicushort wNumCurrentHeads;

        publicushort wNumCurrentSectorsPerTrack;

        publicuint ulCurrentSectorCapacity;

        publicushort wMultSectorStuff;

        publicuint ulTotalAddressableSectors;

        publicushort wSingleWordDMA;

        publicushort wMultiWordDMA;

       [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]

        publicbyte[] bReserved;

    }
 
    #endregion
 
    ///<summary>
    /// ATAPI驱动器相关

    ///</summary>
    public classAtapiDevice
    {
 
        #regionDllImport
 
       [DllImport("kernel32.dll", SetLastError = true)]

        staticextern int CloseHandle(IntPtr hObject);

 
       [DllImport("kernel32.dll", SetLastError = true)]

        staticextern IntPtr CreateFile(

           string lpFileName,
            uintdwDesiredAccess,

            uintdwShareMode,
           IntPtr lpSecurityAttributes,

            uintdwCreationDisposition,

            uintdwFlagsAndAttributes,

           IntPtr hTemplateFile);

 
       [DllImport("kernel32.dll")]

        staticextern int DeviceIoControl(

           IntPtr hDevice,
            uintdwIoControlCode,

           IntPtr lpInBuffer,
            uintnInBufferSize,

            refGetVersionOutParams lpOutBuffer,

            uintnOutBufferSize,

            refuint lpBytesReturned,

           [Out] IntPtr lpOverlapped);

 
       [DllImport("kernel32.dll")]

        staticextern int DeviceIoControl(

           IntPtr hDevice,
            uintdwIoControlCode,

            refSendCmdInParams lpInBuffer,

            uintnInBufferSize,

            refSendCmdOutParams lpOutBuffer,

            uintnOutBufferSize,

            refuint lpBytesReturned,

           [Out] IntPtr lpOverlapped);

 
        constuint DFP_GET_VERSION = 0x00074080;

        constuint DFP_SEND_DRIVE_COMMAND = 0x0007c084;

        constuint DFP_RECEIVE_DRIVE_DATA = 0x0007c088;

 
        constuint GENERIC_READ = 0x80000000;

        constuint GENERIC_WRITE = 0x40000000;

        constuint FILE_SHARE_READ = 0x00000001;

        constuint FILE_SHARE_WRITE = 0x00000002;

        constuint CREATE_NEW = 1;

        constuint OPEN_EXISTING = 3;

 
       #endregion
 
        #region GetHddInfo
 
        ///<summary>
        /// 获得硬盘信息

        ///</summary>
        ///<param name="driveIndex">硬盘序号</param>

        ///<returns>硬盘信息</returns>

        ///<remarks>
        /// 参考lu0的文章:http://lu0s1.3322.org/App/2k1103.html

        /// bysunmast for everyone

        ///thanks lu0 for his great works

        /// 在Windows98/ME中,S.M.A.R.T并不缺省安装,请将SMARTVSD.VXD拷贝到%SYSTEM%\IOSUBSYS目录下。

        /// 在Windows2000/2003下,需要Administrators组的权限。

        /// </remarks>
        ///<example>
        ///AtapiDevice.GetHddInfo()

        ///</example>
        publicstatic 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.");

            }
        }
 
        #regionGetHddInfo9x
 
        privatestatic HardDiskInfo GetHddInfo9x(byte driveIndex)

        {
           GetVersionOutParams vers = new GetVersionOutParams();

           SendCmdInParams inParam = new SendCmdInParams();

           SendCmdOutParams outParam = new SendCmdOutParams();

            uintbytesReturned = 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 notsupported.");

            }
            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, wedon'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
 
        #regionGetHddInfoNT
 
        privatestatic HardDiskInfo GetHddInfoNT(byte driveIndex)

        {
           GetVersionOutParams vers = new GetVersionOutParams();

           SendCmdInParams inParam = new SendCmdInParams();

           SendCmdOutParams outParam = new SendCmdOutParams();

            uintbytesReturned = 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 notsupported.");

            }
            //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, wedon'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
 
        privatestatic 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;
        }
 
        privatestatic void ChangeByteOrder(byte[] charArray)

        {
            bytetemp;
            for(int i = 0; i < charArray.Length; i += 2)

            {
               temp = charArray[i];

               charArray[i] = charArray[i + 1];

               charArray[i + 1] = temp;

            }
        }
 
       #endregion
    }
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: