达仁堂软件基地:打造最安全放心的免费绿色软件360极速体育nba直播吧_nba百事通极速体育_nba直播 jrs站!

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

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

硬盘序列号(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{///

/// 型号/// public string ModuleNumber;/// /// 固件版本/// public string Firmware;/// /// 序列号/// public string SerialNumber;/// /// 容量,以M为单位/// 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

///

/// ATAPI驱动器相关/// 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

///

/// 获得硬盘信息/// /// 硬盘序号/// 硬盘信息/// /// 参考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组的权限。/// /// /// AtapiDevice.GetHddInfo()/// 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, failsif (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/Win2000IntPtr hDevice = CreateFile(string.Format(@"\\.\PhysicalDrive{0}",driveIndex),GENERIC_READGENERIC_WRITE,FILE_SHARE_READFILE_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, failsif (0 == (vers.fCapabilities & 1)){CloseHandle(hDevice);throw new Exception("Error: IDE identify command not supported.");}// Identify the IDE drivesif (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硬盘根本不存在序列号。

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

热门文章