几种读取硬盘序列号的方法
- 使用WMI的方法
using System.Management;
ManagementClass mc=new ManagementClass("Win32_PhysicalMedia");
foreach(ManagementObject mb in aa.GetInstances())

{
MessageBox.Show(
bb.Properties["SerialNumber"].Value.Tostring();
}
- 使用API的方法,这是从网上找到的,可以编译,但运行时有异常,因为是VB的,没有搞定

Option Strict On
Option Explicit On
Imports System.Runtime.InteropServices
Public Class DriveInfoClass DriveInfo
Public Enum DriveTypesEnum DriveTypes
Fixed
Removable
Unknown
End Enum
Private _serialNumber As String
Private _model As String
Private _firmware As String
Private _driveType As DriveTypes = DriveTypes.Unknown
Private _numberCylinders As Integer
Private _numberHeads As Integer
Private _sectorsPerTrack As Integer
Private _bufferSize As Integer
#Region "Win32 Interop"
Private Class IDEREGSClass IDEREGS
Public Features As Byte
Public SectorCount As Byte
Public SectorNumber As Byte
Public CylinderLow As Byte
Public CylinderHigh As Byte
Public DriveHead As Byte
Public Command As Byte
Public Reserved As Byte
End Class
Private Class SENDCMDINPARAMSClass SENDCMDINPARAMS
Public BufferSize As Integer
Public DriveRegs As IDEREGS
Public DriveNumber As Byte
Public Reserved() As Byte
Public Reserved2() As Integer
Public Sub New()Sub New()
DriveRegs = New IDEREGS
Reserved = New Byte(2) {}
Reserved2 = New Integer(3) {}
End Sub
End Class
Private Class DRIVERSTATUSClass DRIVERSTATUS
Public DriveError As Byte
Public IDEStatus As Byte
Public Reserved() As Byte
Public Reserved2() As Integer
Public Sub New()Sub New()
Reserved = New Byte(1) {}
Reserved2 = New Integer(1) {}
End Sub
End Class
Private Class IDSECTORClass IDSECTOR
Public GenConfig As Short '0
Public NumberCylinders As Short '1
Public Reserved As Short '2
Public NumberHeads As Short '3
Public BytesPerTrack As Short '4
Public BytesPerSector As Short '5
Public SectorsPerTrack As Short '6
Public VendorUnique() As Short '7
Public SerialNumber() As Char '10
Public BufferClass As Short '20
Public BufferSize As Short '21
Public ECCSize As Short '22
Public FirmwareRevision() As Char '23
Public ModelNumber() As Char '27
Public MoreVendorUnique As Short '47
Public DoubleWordIO As Short '48
Public Capabilities As Short '49
Public Reserved1 As Short '50
Public PIOTiming As Short '51
Public DMATiming As Short '52
Public BS As Short '53
Public NumberCurrentCyls As Short '54
Public NumberCurrentHeads As Short '55
Public NumberCurrentSectorsPerTrack As Short '56
Public CurrentSectorCapacity As Integer '57
Public MultipleSectorCapacity As Short '59
Public MultipleSectorStuff As Short '60
Public TotalAddressableSectors As Integer '61
Public SingleWordDMA As Short '63
Public MultiWordDMA As Short '64
Public Reserved2() As Byte '65
Public Sub New()Sub New()
VendorUnique = New Short(2) {}
Reserved2 = New Byte(381) {}
FirmwareRevision = New Char(7) {}
SerialNumber = New Char(19) {}
ModelNumber = New Char(39) {}
End Sub
End Class
Private Class SENDCMDOUTPARAMSClass SENDCMDOUTPARAMS
Public BufferSize As Integer
Public Status As DRIVERSTATUS
Public IDS As IDSECTOR
Public Sub New()Sub New()
Status = New DRIVERSTATUS
IDS = New IDSECTOR
End Sub
End Class
Private Declare Function CloseHandle()Function CloseHandle Lib "kernel32" (ByVal hObject As Integer) As Integer
Private Declare Function CreateFile()Function CreateFile Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName As String, ByVal dwDesiredAccess As Integer, ByVal dwShareMode As Integer, ByVal lpSecurityAttributes As Integer, ByVal dwCreationDisposition As Integer, ByVal dwFlagsAndAttributes As Integer, ByVal hTemplateFile As Integer) As Integer
Private Declare Function DeviceIoControl()Function DeviceIoControl Lib "kernel32" (ByVal hDevice As Integer, ByVal dwIoControlCode As Integer, <[In](), Out()> ByVal lpInBuffer As SENDCMDINPARAMS, ByVal nInBufferSize As Integer, <[In](), Out()> ByVal lpOutBuffer As SENDCMDOUTPARAMS, ByVal nOutBufferSize As Integer, ByRef lpBytesReturned As Integer, ByVal lpOverlapped As Integer) As Integer
Private Const CREATE_NEW As Integer = 1
Private Const OPEN_EXISTING As Integer = 3
Private Const GENERIC_READ As Integer = &H80000000
Private Const GENERIC_WRITE As Integer = &H40000000
Private Const FILE_SHARE_READ As Integer = &H1
Private Const FILE_SHARE_WRITE As Integer = &H2
Private Const VER_PLATFORM_WIN32_NT As Integer = 2
Private Const DFP_RECEIVE_DRIVE_DATA As Integer = &H7C088
'Private Const IOCTL_STORAGE_MEDIA_REMOVAL As Long = &H2D4804
Private Const INVALID_HANDLE_VALUE As Integer = -1
Private Shared Function SwapChars()Function SwapChars(ByVal chars() As Char) As String
For i As Integer = 0 To chars.Length - 2 Step 2
chars.Reverse(chars, i, 2)
Next
Return New String(chars).Trim
End Function
#End Region

Public Sub New()Sub New(ByVal driveNumber As Integer)
Dim result As Boolean
Dim handle As Integer
Dim returnSize As Integer
Dim sci As New SENDCMDINPARAMS
Dim sco As New SENDCMDOUTPARAMS
If Environment.OSVersion.Platform = PlatformID.Win32NT Then
'handle = CreateFile("\\.\PhysicalDrive" & CStr(driveNumber), GENERIC_READ Or GENERIC_WRITE, FILE_SHARE_READ Or FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0)
handle = CreateFile("\\.\PhysicalDrive" & CStr(driveNumber), GENERIC_READ Or GENERIC_WRITE, FILE_SHARE_READ Or FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0)
' handle = CreateFile("\\.\PhysicalDrive", GENERIC_READ Or GENERIC_WRITE, FILE_SHARE_READ Or FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0)
Else ' 9X
handle = CreateFile("\\.\Smartvsd", 0, 0, 0, CREATE_NEW, 0, 0)
End If
If handle <> INVALID_HANDLE_VALUE Then
sci.DriveNumber = CType(driveNumber, Byte)
sci.BufferSize = Marshal.SizeOf(sco)
sci.DriveRegs.DriveHead = CType(&HA0 Or (driveNumber << 5), Byte)
sci.DriveRegs.Command = &HEC
sci.DriveRegs.SectorCount = 1
sci.DriveRegs.SectorNumber = 1
If DeviceIoControl(handle, DFP_RECEIVE_DRIVE_DATA, sci, Marshal.SizeOf(sci), sco, Marshal.SizeOf(sco), returnSize, 0) <> 0 Then
_serialNumber = SwapChars(sco.IDS.SerialNumber)
_model = SwapChars(sco.IDS.ModelNumber)
_firmware = SwapChars(sco.IDS.FirmwareRevision)
_numberCylinders = sco.IDS.NumberCylinders
_numberHeads = sco.IDS.NumberHeads
_sectorsPerTrack = sco.IDS.SectorsPerTrack
_bufferSize = sco.IDS.BufferSize * 512
If (sco.IDS.GenConfig And &H80) = &H80 Then
_driveType = DriveTypes.Removable
ElseIf (sco.IDS.GenConfig And &H40) = &H40 Then
_driveType = DriveTypes.Fixed
Else
_driveType = DriveTypes.Unknown
End If
End If
CloseHandle(handle)
End If
End Sub
Public ReadOnly Property SerialNumber()Property SerialNumber() As String
Get
Return _serialNumber
End Get
End Property
Public ReadOnly Property Model()Property Model() As String
Get
Return _model
End Get
End Property
Public ReadOnly Property Firmware()Property Firmware() As String
Get
Return _firmware
End Get
End Property
Public ReadOnly Property NumberCylinders()Property NumberCylinders() As Integer
Get
Return _numberCylinders
End Get
End Property
Public ReadOnly Property NumberHeads()Property NumberHeads() As Integer
Get
Return _numberHeads
End Get
End Property
Public ReadOnly Property SectorsPerTrack()Property SectorsPerTrack() As Integer
Get
Return _sectorsPerTrack
End Get
End Property
Public ReadOnly Property BufferSize()Property BufferSize() As Integer
Get
Return _bufferSize
End Get
End Property
Public ReadOnly Property DriveType()Property DriveType() As DriveTypes
Get
Return _driveType
End Get
End Property
End Class
Class DriveInfoAppClass DriveInfoApp
Shared Sub Main()Sub Main()
For drive As Integer = 0 To 4
Dim info As New DriveInfo(drive)
If Not info.SerialNumber Is Nothing Then
Select Case drive
Case 0 : Console.WriteLine("Primary Controller - Master drive")
Case 1 : Console.WriteLine("Primary Controller - Slave drive")
Case 2 : Console.WriteLine("Secondary Controller - Master drive")
Case 3 : Console.WriteLine("Secondary Controller - Slave drive")
End Select
Console.WriteLine()
Console.WriteLine("Drive Model Number________________: " & info.Model)
Console.WriteLine("Drive Serial Number_______________: " & info.SerialNumber)
Console.WriteLine("Drive Controller Revision Number__: " & info.Firmware)
Console.WriteLine("Controller Buffer Size on Drive___: " & info.BufferSize)
Console.WriteLine("Drive Type________________________: " & info.DriveType.ToString)
Console.Write("Physical Geometry: ")
Console.Write(info.NumberCylinders & " Cylinders ")
Console.Write(info.NumberHeads & " Heads ")
Console.WriteLine(info.SectorsPerTrack & " Sectors per track")
Console.WriteLine()
End If
Next
Console.ReadLine()
End Sub
End Class
- 使用读取RING3的方法。这种方法没有办法用C#实现,起码我不知道,下面别人写的C++的方法

/**//*+++
HDID.CPP
Written by Lu Lin
http://lu0.126.com
2000.11.3
---*/
#include <windows.h>
#include <iostream.h>
#include <stdio.h> 
#define DFP_GET_VERSION 0x00074080
#define DFP_SEND_DRIVE_COMMAND 0x0007c084
#define DFP_RECEIVE_DRIVE_DATA 0x0007c088 
#pragma pack(1) 
typedef struct _GETVERSIONOUTPARAMS
{
BYTE bVersion; // Binary driver version.
BYTE bRevision; // Binary driver revision.
BYTE bReserved; // Not used.
BYTE bIDEDeviceMap; // Bit map of IDE devices.
DWORD fCapabilities; // Bit mask of driver capabilities.
DWORD dwReserved[4]; // For future use.
} GETVERSIONOUTPARAMS, *PGETVERSIONOUTPARAMS, *LPGETVERSIONOUTPARAMS; 

typedef struct _IDEREGS
{
BYTE bFeaturesReg; // Used for specifying SMART "commands".
BYTE bSectorCountReg; // IDE sector count register
BYTE bSectorNumberReg; // IDE sector number register
BYTE bCylLowReg; // IDE low order cylinder value
BYTE bCylHighReg; // IDE high order cylinder value
BYTE bDriveHeadReg; // IDE drive/head register
BYTE bCommandReg; // Actual IDE command.
BYTE bReserved; // reserved for future use. Must be zero.
} IDEREGS, *PIDEREGS, *LPIDEREGS; 

typedef struct _SENDCMDINPARAMS
{
DWORD cBufferSize; // Buffer size in bytes
IDEREGS irDriveRegs; // Structure with drive register values.
BYTE bDriveNumber; // Physical drive number to send
// command to (0,1,2,3).
BYTE bReserved[3]; // Reserved for future expansion.
DWORD dwReserved[4]; // For future use.
//BYTE bBuffer[1]; // Input buffer.
} SENDCMDINPARAMS, *PSENDCMDINPARAMS, *LPSENDCMDINPARAMS; 

typedef struct _DRIVERSTATUS
{
BYTE bDriverError; // Error code from driver,
// or 0 if no error.
BYTE bIDEStatus; // Contents of IDE Error register.
// Only valid when bDriverError
// is SMART_IDE_ERROR.
BYTE bReserved[2]; // Reserved for future expansion.
DWORD dwReserved[2]; // Reserved for future expansion.
} DRIVERSTATUS, *PDRIVERSTATUS, *LPDRIVERSTATUS; 

typedef struct _SENDCMDOUTPARAMS
{
DWORD cBufferSize; // Size of bBuffer in bytes
DRIVERSTATUS DriverStatus; // Driver status structure.
BYTE bBuffer[512]; // Buffer of arbitrary length
// in which to store the data read from the drive.
} SENDCMDOUTPARAMS, *PSENDCMDOUTPARAMS, *LPSENDCMDOUTPARAMS; 

typedef struct _IDSECTOR
{
USHORT wGenConfig;
USHORT wNumCyls;
USHORT wReserved;
USHORT wNumHeads;
USHORT wBytesPerTrack;
USHORT wBytesPerSector;
USHORT wSectorsPerTrack;
USHORT wVendorUnique[3];
CHAR sSerialNumber[20];
USHORT wBufferType;
USHORT wBufferSize;
USHORT wECCSize;
CHAR sFirmwareRev[8];
CHAR sModelNumber[40];
USHORT wMoreVendorUnique;
USHORT wDoubleWordIO;
USHORT wCapabilities;
USHORT wReserved1;
USHORT wPIOTiming;
USHORT wDMATiming;
USHORT wBS;
USHORT wNumCurrentCyls;
USHORT wNumCurrentHeads;
USHORT wNumCurrentSectorsPerTrack;
ULONG ulCurrentSectorCapacity;
USHORT wMultSectorStuff;
ULONG ulTotalAddressableSectors;
USHORT wSingleWordDMA;
USHORT wMultiWordDMA;
BYTE bReserved[128];
} IDSECTOR, *PIDSECTOR; 

/**//*+++
Global vars
---*/
GETVERSIONOUTPARAMS vers;
SENDCMDINPARAMS in;
SENDCMDOUTPARAMS out;
HANDLE h;
DWORD i;
BYTE j; 

void CopyRight()
{
cerr<<endl<<"HDD identifier v1.0 for WIN95/98/Me/NT/2000. written by Lu Lin"<<endl;
cerr<<"For more information, please visit Inside Programming: http://lu0.126.com"<<endl;
cerr<<"2000.11.3"<<endl<<endl;
}
VOID ChangeByteOrder(PCHAR szString, USHORT uscStrSize) 

{ 
USHORT i;
CHAR temp; 
for (i = 0; i < uscStrSize; i+=2) 
{
temp = szString[i];
szString[i] = szString[i+1];
szString[i+1] = temp;
}
} 

void DetectIDE(BYTE bIDEDeviceMap)
{ 
if (bIDEDeviceMap&1)
{ 
if (bIDEDeviceMap&16)
{
cout<<"ATAPI device is attached to primary controller, drive 0."<<endl; 
}else
{
cout<<"IDE device is attached to primary controller, drive 0."<<endl;
}
} 
if (bIDEDeviceMap&2)
{ 
if (bIDEDeviceMap&32)
{
cout<<"ATAPI device is attached to primary controller, drive 1."<<endl; 
}else
{
cout<<"IDE device is attached to primary controller, drive 1."<<endl;
}
} 
if (bIDEDeviceMap&4)
{ 
if (bIDEDeviceMap&64)
{
cout<<"ATAPI device is attached to secondary controller, drive 0."<<endl; 
}else
{
cout<<"IDE device is attached to secondary controller, drive 0."<<endl;
}
} 
if (bIDEDeviceMap&8)
{ 
if (bIDEDeviceMap&128)
{
cout<<"ATAPI device is attached to secondary controller, drive 1."<<endl; 
}else
{
cout<<"IDE device is attached to secondary controller, drive 1."<<endl;
}
}
} 

void hdid9x()
{
ZeroMemory(&vers,sizeof(vers));
//We start in 95/98/Me
h=CreateFile("\\\\.\\Smartvsd",0,0,0,CREATE_NEW,0,0); 
if (!h)
{
cout<<"open smartvsd.vxd failed"<<endl;
exit(0);
} 

if (!DeviceIoControl(h,DFP_GET_VERSION,0,0,&vers,sizeof(vers),&i,0))
{
cout<<"DeviceIoControl failed:DFP_GET_VERSION"<<endl;
CloseHandle(h);
return;
}
//If IDE identify command not supported, fails 
if (!(vers.fCapabilities&1))
{
cout<<"Error: IDE identify command not supported.";
CloseHandle(h);
return;
}
//Display IDE drive number detected
DetectIDE(vers.bIDEDeviceMap);
//Identify the IDE drives 
for (j=0;j<4;j++)
{
PIDSECTOR phdinfo;
char s[41]; 
ZeroMemory(&in,sizeof(in));
ZeroMemory(&out,sizeof(out)); 
if (j&1)
{
in.irDriveRegs.bDriveHeadReg=0xb0; 
}else
{
in.irDriveRegs.bDriveHeadReg=0xa0;
} 
if (vers.fCapabilities&(16>>j))
{
//We don't detect a ATAPI device.
cout<<"Drive "<<(int)(j+1)<<" is a ATAPI device, we don't detect it"<<endl;
continue; 
}else
{
in.irDriveRegs.bCommandReg=0xec;
}
in.bDriveNumber=j;
in.irDriveRegs.bSectorCountReg=1;
in.irDriveRegs.bSectorNumberReg=1;
in.cBufferSize=512; 
if (!DeviceIoControl(h,DFP_RECEIVE_DRIVE_DATA,&in,sizeof(in),&out,sizeof(out),&i,0))
{
cout<<"DeviceIoControl failed:DFP_RECEIVE_DRIVE_DATA"<<endl;
CloseHandle(h);
return;
}
phdinfo=(PIDSECTOR)out.bBuffer;
memcpy(s,phdinfo->sModelNumber,40);
s[40]=0;
ChangeByteOrder(s,40);
cout<<endl<<"Module Number:"<<s<<endl;
memcpy(s,phdinfo->sFirmwareRev,8);
s[8]=0;
ChangeByteOrder(s,8);
cout<<"\tFirmware rev:"<<s<<endl;
memcpy(s,phdinfo->sSerialNumber,20);
s[20]=0;
ChangeByteOrder(s,20);
cout<<"\tSerial Number:"<<s<<endl;
cout<<"\tCapacity:"<<phdinfo->ulTotalAddressableSectors/2/1024<<"M"<<endl<<endl;
} 
//Close handle before quit
CloseHandle(h);
CopyRight(); 
} 

void hdidnt()
{
char hd[80];
PIDSECTOR phdinfo;
char s[41]; 
ZeroMemory(&vers,sizeof(vers));
//We start in NT/Win2000 
for (j=0;j<4;j++)
{
sprintf(hd,"\\\\.\\PhysicalDrive%d",j);
h=CreateFile(hd,GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,0,OPEN_EXISTING,0,0); 
if (!h)
{
continue;
} 
if (!DeviceIoControl(h,DFP_GET_VERSION,0,0,&vers,sizeof(vers),&i,0))
{
CloseHandle(h);
continue;
}
//If IDE identify command not supported, fails 
if (!(vers.fCapabilities&1))
{
cout<<"Error: IDE identify command not supported.";
CloseHandle(h);
return;
}
//Identify the IDE drives
ZeroMemory(&in,sizeof(in));
ZeroMemory(&out,sizeof(out)); 
if (j&1)
{
in.irDriveRegs.bDriveHeadReg=0xb0; 
}else
{
in.irDriveRegs.bDriveHeadReg=0xa0;
} 
if (vers.fCapabilities&(16>>j))
{
//We don't detect a ATAPI device.
cout<<"Drive "<<(int)(j+1)<<" is a ATAPI device, we don't detect it"<<endl;
continue; 
}else
{
in.irDriveRegs.bCommandReg=0xec;
}
in.bDriveNumber=j;
in.irDriveRegs.bSectorCountReg=1;
in.irDriveRegs.bSectorNumberReg=1;
in.cBufferSize=512; 
if (!DeviceIoControl(h,DFP_RECEIVE_DRIVE_DATA,&in,sizeof(in),&out,sizeof(out),&i,0))
{
cout<<"DeviceIoControl failed:DFP_RECEIVE_DRIVE_DATA"<<endl;
CloseHandle(h);
return;
}
phdinfo=(PIDSECTOR)out.bBuffer;
memcpy(s,phdinfo->sModelNumber,40);
s[40]=0;
ChangeByteOrder(s,40);
cout<<endl<<"Module Number:"<<s<<endl;
memcpy(s,phdinfo->sFirmwareRev,8);
s[8]=0;
ChangeByteOrder(s,8);
cout<<"\tFirmware rev:"<<s<<endl;
memcpy(s,phdinfo->sSerialNumber,20);
s[20]=0;
ChangeByteOrder(s,20);
cout<<"\tSerial Number:"<<s<<endl;
cout<<"\tCapacity:"<<phdinfo->ulTotalAddressableSectors/2/1024<<"M"<<endl<<endl;
CloseHandle(h);
}
CopyRight();
} 

void main()
{
OSVERSIONINFO VersionInfo; 
ZeroMemory(&VersionInfo,sizeof(VersionInfo));
VersionInfo.dwOSVersionInfoSize=sizeof(VersionInfo);
GetVersionEx(&VersionInfo); 

switch (VersionInfo.dwPlatformId)
{
case VER_PLATFORM_WIN32s:
cout<<"Win32s is not supported by this programm."<<endl;
return;
case VER_PLATFORM_WIN32_WINDOWS:
hdid9x();
return;
case VER_PLATFORM_WIN32_NT:
hdidnt();
return;
}
} 

还有以下疑问:
1. C#中如何通过上文API的方法来读取硬盘序列号
2. win98不支持WMI,那为什么在.net frameowork SDK中说,
ManagementClass.GetInstances()和ManagementClass.Get()都
可以在win98平台运行 - 使用API的方法,这是从网上找到的,可以编译,但运行时有异常,因为是VB的,没有搞定
程序员问答社区,解决您的IT难题