分享
 
 
 

如何得到硬盘序列号?.NET版本[C#]

王朝asp·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

硬盘序列号(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硬盘根本不存在序列号。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有