硬盤序列號(hào)(Serial Number)不等于卷標(biāo)號(hào)(Volume Name),后者雖然很容易得到,但是格式化分區(qū)后就會(huì)重寫,不可靠。遺憾的是很多朋友往往分不清這一點(diǎn)。
要得到硬盤的物理序列號(hào),可以通過WMI,也就是Win32_PhysicalMedia.SerialNumber。可惜的是Windows 98/ME的WMI并不支持這個(gè)類,訪問時(shí)會(huì)出現(xiàn)異常。
受陸麟的例子的啟發(fā),我們還可以通過S.M.A.R.T.接口,直接從RING3調(diào)用API DeviceIoControl()來獲取硬盤信息,而不需要寫VXD或者DRIVER。這樣這個(gè)問題就解決了,我對(duì)它進(jìn)行了封裝,大量使用了P/Invoke技術(shù),一個(gè)完整的Library。支持Windows 98-2003。
使用上很簡(jiǎn)單:
HardDiskInfo hdd = AtapiDevice.GetHddInfo(0); // 第一個(gè)硬盤
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
{
///
/// 型號(hào)
///
public string ModuleNumber;
///
/// 固件版本
///
public string Firmware;
///
/// 序列號(hào)
///
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驅(qū)動(dòng)器相關(guān)
///
public class AtapiDevice
{
要得到硬盤的物理序列號(hào),可以通過WMI,也就是Win32_PhysicalMedia.SerialNumber。可惜的是Windows 98/ME的WMI并不支持這個(gè)類,訪問時(shí)會(huì)出現(xiàn)異常。
受陸麟的例子的啟發(fā),我們還可以通過S.M.A.R.T.接口,直接從RING3調(diào)用API DeviceIoControl()來獲取硬盤信息,而不需要寫VXD或者DRIVER。這樣這個(gè)問題就解決了,我對(duì)它進(jìn)行了封裝,大量使用了P/Invoke技術(shù),一個(gè)完整的Library。支持Windows 98-2003。
使用上很簡(jiǎn)單:
HardDiskInfo hdd = AtapiDevice.GetHddInfo(0); // 第一個(gè)硬盤
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
{
///
/// 型號(hào)
///
public string ModuleNumber;
///
/// 固件版本
///
public string Firmware;
///
/// 序列號(hào)
///
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驅(qū)動(dòng)器相關(guān)
///
public class AtapiDevice
{