Public
Class
PhysicalDriveDemo
Public
Shared
Sub
Run()
Console.WriteLine(PhysicalDrive.GetSerialNumber(
0
))
End Sub
End Class
Imports
System
Imports
System.Collections.Generic
Imports
System.Text
Imports
System.Runtime.InteropServices
Public
Class
PhysicalDrive
'
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _
'
Friend Structure IDSECTOR
'
Public wGenConfig As Int16
'
Public wNumCyls As Int16
'
Public wReserved As Int16
'
Public wNumHeads As Int16
'
Public wBytesPerTrack As Int16
'
Public wBytesPerSector As Int16
'
Public wSectorsPerTrack As Int16
'
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=3)> _
'
Public wVendorUnique() As Int16
'
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=20)> _
'
Public sSerialNumber As String
'
Public wBufferType As Int16
'
Public wBufferSize As Int16
'
Public wECCSize As Int16
'
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=8)> _
'
Public sFirmwareRev As String
'
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=40)> _
'
Public sModelNumber As String
'
Public wMoreVendorUnique As Int16
'
Public wDoubleWordIO As Int16
'
Public wCapabilities As Int16
'
Public wReserved1 As Int16
'
Public wPIOTiming As Int16
'
Public wDMATiming As Int16
'
Public wBS As Int16
'
Public wNumCurrentCyls As Int16
'
Public wNumCurrentHeads As Int16
'
Public wNumCurrentSectorsPerTrack As Int16
'
Public ulCurrentSectorCapacity As Int32
'
Public wMultSectorStuff As Int16
'
Public ulTotalAddressableSectors As Int32
'
Public wSingleWordDMA As Int16
'
Public wMultiWordDMA As Int16
'
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=128)> _
'
Public bReserved() As Byte
'
End Structure
<
StructLayout(LayoutKind.Sequential)
>
_
Friend
Structure
DRIVERSTATUS
Public
bDriverError
As
Byte
Public
bIDEStatus
As
Byte
<
MarshalAs(UnmanagedType.ByValArray, SizeConst:
=
2
)
>
_
Public
bReserved()
As
Byte
<
MarshalAs(UnmanagedType.ByValArray, SizeConst:
=
2
)
>
_
Public
dwReserved()
As
Int32
End Structure
<
StructLayout(LayoutKind.Sequential)
>
_
Friend
Structure
SENDCMDOUTPARAMS
Public
cBufferSize
As
Int32
Public
DriverStatus
As
DRIVERSTATUS
<
MarshalAs(UnmanagedType.ByValArray, SizeConst:
=
513
)
>
_
Public
bBuffer()
As
Byte
End Structure
'
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _
'
Friend Structure SRB_IO_CONTROL
'
Public HeaderLength As Int32
'
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=8)> _
'
Public Signature As String
'
Public Timeout As Int32
'
Public ControlCode As Int32
'
Public ReturnCode As Int32
'
Public Length As Int32
'
End Structure
<
StructLayout(LayoutKind.Sequential)
>
_
Friend
Structure
IDEREGS
Public
bFeaturesReg
As
Byte
Public
bSectorCountReg
As
Byte
Public
bSectorNumberReg
As
Byte
Public
bCylLowReg
As
Byte
Public
bCylHighReg
As
Byte
Public
bDriveHeadReg
As
Byte
Public
bCommandReg
As
Byte
Public
bReserved
As
Byte
End Structure
<
StructLayout(LayoutKind.Sequential)
>
_
Friend
Structure
SENDCMDINPARAMS
Public
cBufferSize
As
Int32
Public
irDriveRegs
As
IDEREGS
Public
bDriveNumber
As
Byte
<
MarshalAs(UnmanagedType.ByValArray, SizeConst:
=
3
)
>
_
Public
bReserved()
As
Byte
<
MarshalAs(UnmanagedType.ByValArray, SizeConst:
=
4
)
>
_
Public
dwReserved()
As
Int32
Public
bBuffer
As
Byte
End Structure
<
StructLayout(LayoutKind.Sequential)
>
_
Friend
Structure
GETVERSIONOUTPARAMS
Public
bVersion
As
Byte
Public
bRevision
As
Byte
Public
bReserved
As
Byte
Public
bIDEDeviceMap
As
Byte
Public
fCapabilities
As
Int32
<
MarshalAs(UnmanagedType.ByValArray, SizeConst:
=
4
)
>
_
Public
dwReserved()
As
Int32
End Structure
<
DllImport(
"
kernel32.dll
"
, SetLastError:
=
True
)
>
_
Private
Shared
Function
CloseHandle( _
ByVal
hObject
As
Int32 _
)
As
Integer
End Function
<
DllImport(
"
kernel32.dll
"
)
>
_
Private
Overloads
Shared
Function
DeviceIoControl( _
ByVal
hDevice
As
Int32, _
ByVal
dwIoControlCode
As
Int32, _
ByRef
lpInBuffer
As
SENDCMDINPARAMS, _
ByVal
nInBufferSize
As
Integer
, _
ByRef
lpOutBuffer
As
SENDCMDOUTPARAMS, _
ByVal
nOutBufferSize
As
Integer
, _
ByRef
lpbytesReturned
As
Int32, _
ByVal
lpOverlapped
As
Integer
_
)
As
Integer
End Function
<
DllImport(
"
kernel32.dll
"
)
>
_
Private
Overloads
Shared
Function
DeviceIoControl( _
ByVal
hDevice
As
Int32, _
ByVal
dwIoControlCode
As
Int32, _
ByVal
lpInBuffer
As
Integer
, _
ByVal
nInBufferSize
As
Integer
, _
ByRef
lpOutBuffer
As
GETVERSIONOUTPARAMS, _
ByVal
nOutBufferSize
As
Integer
, _
ByRef
lpbytesReturned
As
Int32, _
ByVal
lpOverlapped
As
Integer
_
)
As
Integer
End Function
<
DllImport(
"
kernel32.dll
"
)
>
_
Private
Shared
Function
CreateFile( _
ByVal
lpFileName
As
String
, _
ByVal
dwDesiredAccess
As
Int32, _
ByVal
dwShareMode
As
Int32, _
ByVal
lpSecurityAttributes
As
Integer
, _
ByVal
dwCreationDisposition
As
Int32, _
ByVal
dwFlagsAndAttributes
As
Int32, _
ByVal
hTemplateFile
As
Integer
_
)
As
Int32
End Function
Private
Const
GENERIC_READ
As
Int32
=
&
H80000000
Private
Const
GENERIC_WRITE
As
Int32
=
&
H40000000
Private
Const
FILE_SHARE_READ
As
Int32
=
&
H1
Private
Const
FILE_SHARE_WRITE
As
Int32
=
&
H2
Private
Const
OPEN_EXISTING
As
Int32
=
3
Private
Const
INVALID_HANDLE_VALUE
As
Int32
=
&
HFFFFFFFF
Private
Const
DFP_GET_VERSION
As
Int32
=
&
H74080
Private
Const
IDE_ATAPI_IDENTIFY
As
Integer
=
&
HA1
Private
Const
IDE_ATA_IDENTIFY
As
Integer
=
&
HEC
Private
Const
IDENTIFY_BUFFER_SIZE
As
Integer
=
512
Private
Const
DFP_RECEIVE_DRIVE_DATA
As
Int32
=
&
H7C088
'
'' <summary>
'
'' 获取物理序列号
'
'' </summary>
'
'' <param name="id">系统硬盘序号,0-255</param>
Public
Shared
Function
GetSerialNumber(
ByVal
id
As
Byte
)
As
String
Dim
os
As
OperatingSystem
=
Environment.OSVersion
If
os.Platform
<>
PlatformID.Win32NT
Then
Throw
New
NotSupportedException(
"
仅支持2000/XP/2003
"
)
End
If
If
os.Version.Major
<
5
Then
Throw
New
NotSupportedException(
"
仅支持2000/XP/2003
"
)
End
If
Return
Read(id)
End Function
Private
Shared
Function
Read(
ByVal
drive
As
Byte
)
As
String
Dim
driveName
As
String
=
String
.Concat(
"
\\.\PhysicalDrive
"
, drive.ToString())
Dim
device
As
Int32
=
CreateFile( _
driveName, _
GENERIC_READ
Or
GENERIC_WRITE, _
FILE_SHARE_READ
Or
FILE_SHARE_WRITE, _
0
, _
OPEN_EXISTING, _
0
, _
0
)
If
device
=
INVALID_HANDLE_VALUE
Then
Return
""
End
If
Dim
verPara
As
New
GETVERSIONOUTPARAMS()
Dim
bytRv
As
Int32
=
0
If
DeviceIoControl( _
device, _
DFP_GET_VERSION, _
0
, _
0
, _
verPara, _
Marshal.SizeOf(verPara), _
bytRv, _
0
_
)
<>
0
Then
If
verPara.bIDEDeviceMap
>
0
Then
Dim
bIDCmd
As
Byte
=
CByte
(
IIf
((verPara.bIDEDeviceMap
>>
drive
And
&
H10)
<>
0
, IDE_ATAPI_IDENTIFY, IDE_ATA_IDENTIFY))
Dim
scip
As
New
SENDCMDINPARAMS()
Dim
scop
As
New
SENDCMDOUTPARAMS()
With
scip
.cBufferSize
=
IDENTIFY_BUFFER_SIZE
.bDriveNumber
=
drive
With
.irDriveRegs
.bFeaturesReg
=
0
.bSectorCountReg
=
1
.bCylLowReg
=
0
.bCylHighReg
=
0
.bDriveHeadReg
=
CByte
((
&
HA0
Or
((drive
And
1
)
<<
4
)))
.bCommandReg
=
bIDCmd
End
With
End
With
If
DeviceIoControl(device, DFP_RECEIVE_DRIVE_DATA, scip, Marshal.SizeOf(scip), scop, Marshal.SizeOf(scop), bytRv,
0
)
<>
0
Then
Dim
s
As
New
StringBuilder()
Dim
i
As
Integer
For
i
=
20
To
40
-
2
Step
2
s.Append(
ChrW
(scop.bBuffer((i
+
1
))))
s.Append(
ChrW
(scop.bBuffer(i)))
Next
i
CloseHandle(device)
Return
s.ToString().Trim()
End
If
End
If
End
If
CloseHandle(device)
Return
""
End Function
End Class