我曾经在寻找获取硬盘序列号而不使用WMI,我找到了它。 The code I found and posted on StackOverFlow.com在32位Windows上运行良好,包括XP和Vista。只有当我尝试在64位操作系统(特别是Vista Ultimate 64)上获取序列号时才会出现问题。代码一直返回String.Empty或Space。
任何人都知道如何解决这个问题?
编辑:
我使用了Dave Cluderay建议的工具,结果很有趣:
以下是DiskId32的输出,在Windows XP SP2 32位上:
To get all details use "diskid32 /d"
Trying to read the drive IDs using physical access with admin rights
Drive 0 - Primary Controller - - Master drive
Drive Model Number________________: [MAXTOR STM3160215AS]
Drive Serial Number_______________: [ 6RA26XK3]
Drive Controller Revision Number__: [3.AAD]
Controller Buffer Size on Drive___: 2097152 bytes
Drive Type________________________: Fixed
Drive Size________________________: 160041885696 bytes
Trying to read the drive IDs using the SCSI back door
Drive 4 - Tertiary Controller - - Master drive
Drive Model Number________________: [MAXTOR STM3160215AS]
Drive Serial Number_______________: [ 6RA26XK3]
Drive Controller Revision Number__: [3.AAD]
Controller Buffer Size on Drive___: 2097152 bytes
Drive Type________________________: Fixed
Drive Size________________________: 160041885696 bytes
Trying to read the drive IDs using physical access with zero rights
**** STORAGE_DEVICE_DESCRIPTOR for drive 0 ****
Vendor Id = []
Product Id = [MAXTOR STM3160215AS]
Product Revision = [3.AAD]
Serial Number = []
**** DISK_GEOMETRY_EX for drive 0 ****
Disk is fixed
DiskSize = 160041885696
Trying to read the drive IDs using Smart
Drive 0 - Primary Controller - - Master drive
Drive Model Number________________: [MAXTOR STM3160215AS]
Drive Serial Number_______________: [ 6RA26XK3]
Drive Controller Revision Number__: [3.AAD]
Controller Buffer Size on Drive___: 2097152 bytes
Drive Type________________________: Fixed
Drive Size________________________: 160041885696 bytes
Hard Drive Serial Number__________: 6RA26XK3
Hard Drive Model Number___________: MAXTOR STM3160215AS
DiskId32在Windows Vista Ultimate 64位上运行:
To get all details use "diskid32 /d"
Trying to read the drive IDs using physical access with admin rights
Trying to read the drive IDs using the SCSI back door
Trying to read the drive IDs using physical access with zero rights
**** STORAGE_DEVICE_DESCRIPTOR for drive 0 ****
Vendor Id = [MAXTOR S]
Product Id = [TM3160215AS]
Product Revision = [3.AA]
Serial Number = []
**** DISK_GEOMETRY_EX for drive 0 ****
Disk is fixed
DiskSize = 160041885696
Trying to read the drive IDs using Smart
Hard Drive Serial Number__________:
Hard Drive Model Number___________:
请注意Vista上的信息有多少,以及如何返回序列号。此外,另一个工具EnumDisk将我在Vista上的硬盘称为“SCSI”而不是Windows XP上的“ATA”。
有什么想法吗?
编辑2:
我发布了EnumDisks的结果:
在Windows XP SP2 32位上:
Properties for Device 1
Device ID: IDE\DiskMAXTOR_STM3160215AS_____________________3.AAD___
Adapter Properties
------------------
Bus Type : ATA
Max. Tr. Length: 0x20000
Max. Phy. Pages: 0xffffffff
Alignment Mask : 0x1
Device Properties
-----------------
Device Type : Direct Access Device (0x0)
Removable Media : No
Product ID : MAXTOR STM3160215AS
Product Revision: 3.AAD
Inquiry Data from Pass Through
------------------------------
Device Type: Direct Access Device (0x0)
Vendor ID : MAXTOR S
Product ID : TM3160215AS
Product Rev: 3.AA
Vendor Str :
*** End of Device List ***
在Vista 64 Ultimate上:
Properties for Device 1
Device ID: SCSI\DiskMAXTOR_STM3160215AS_____3.AA
Adapter Properties
------------------
Bus Type : FIBRE
Max. Tr. Length: 0x20000
Max. Phy. Pages: 0x11
Alignment Mask : 0x0
Device Properties
-----------------
Device Type : Direct Access Device (0x0)
Removable Media : No
Vendor ID : MAXTOR S
Product ID : TM3160215AS
Product Revision: 3.AA
Inquiry Data from Pass Through
------------------------------
Device Type: Direct Access Device (0x0)
Vendor ID : MAXTOR S
Product ID : TM3160215AS
Product Rev: 3.AA
Vendor Str :
*** End of Device List ***
答案 0 :(得分:8)
此代码尝试三次获取序列号:
IOCTL_STORAGE_QUERY_PROPERTY
。SMART_RCV_DRIVE_DATA
。IOCTL_SCSI_PASS_THROUGH
。此代码适用于64位:
' PhysicalDrive.vb
Option Strict On
Option Explicit On
Imports System.Runtime.InteropServices
Imports System.Text
Imports System.ComponentModel
Imports Microsoft.Win32.SafeHandles
Public Class PhysicalDrive
#Region "Win32 Definitions"
<StructLayout(LayoutKind.Sequential)> _
Private 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)> _
Private 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()
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=1)> _
Public bBuffer As Byte()
End Structure
<StructLayout(LayoutKind.Sequential)> _
Private Structure DRIVERSTATUS
Public bDriverError As Byte
Public bIDEError 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)> _
Private Structure SENDCMDOUTPARAMS
Public cBufferSize As Int32
Public DriverStatus As DRIVERSTATUS
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=IDENTIFY_BUFFER_SIZE)> _
Public bBuffer As Byte()
End Structure
<StructLayout(LayoutKind.Sequential)> _
Private Structure GETVERSIONINPARAMS
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
<StructLayout(LayoutKind.Sequential)> _
Private Structure STORAGE_PROPERTY_QUERY
Public PropertyId As Int32
Public QueryType As Int32
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=1)> _
Public AdditionalParameters As Byte()
End Structure
<StructLayout(LayoutKind.Sequential)> _
Private Structure STORAGE_DEVICE_DESCRIPTOR
Public Version As Int32
Public Size As Int32
Public DeviceType As Byte
Public DeviceTypeModifier As Byte
Public RemovableMedia As Byte
Public CommandQueueing As Byte
Public VendorIdOffset As Int32
Public ProductIdOffset As Int32
Public ProductRevisionOffset As Int32
Public SerialNumberOffset As Int32
Public BusType As Byte
Public RawPropertiesLength As Int32
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=10240)> _
Public RawDeviceProperties As Byte()
End Structure
<StructLayout(LayoutKind.Sequential)> _
Private Structure SCSI_PASS_THROUGH
Public Length As Int16
Public ScsiStatus As Byte
Public PathId As Byte
Public TargetId As Byte
Public Lun As Byte
Public CdbLength As Byte
Public SenseInfoLength As Byte
Public DataIn As Byte
Public DataTransferLength As Int32
Public TimeOutValue As Int32
Public DataBufferOffset As IntPtr
Public SenseInfoOffset As Int32
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=16)> _
Public Cdb As Byte()
End Structure
<StructLayout(LayoutKind.Sequential)> _
Private Structure SCSI_PASS_THROUGH_WITH_BUFFER
Public Spt As SCSI_PASS_THROUGH
Public Filler As Int32
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=64)> _
Public Buffer As Byte()
End Structure
<DllImport("kernel32.dll", SetLastError:=True)> _
Private Shared Function CreateFile(ByVal lpFileName As String, ByVal dwDesiredAccess As Int32, ByVal dwShareMode As Int32, ByVal lpSecurityAttributes As IntPtr, ByVal dwCreationDisposition As Int32, ByVal dwFlagsAndAttributes As Int32, ByVal hTemplateFile As IntPtr) As SafeFileHandle
End Function
<DllImport("kernel32.dll", SetLastError:=True)> _
Private Shared Function DeviceIoControl(ByVal hDevice As SafeFileHandle, ByVal dwIoControlCode As Int32, <[In]()> ByRef lpInBuffer As SENDCMDINPARAMS, ByVal nInBufferSize As Int32, <[In](), Out()> ByRef lpOutBuffer As SENDCMDOUTPARAMS, ByVal nOutBufferSize As Int32, ByRef lpBytesReturned As Int32, ByVal lpOverlapped As Int32) As Int32
End Function
<DllImport("kernel32.dll", SetLastError:=True)> _
Private Shared Function DeviceIoControl(ByVal hDevice As SafeFileHandle, ByVal dwIoControlCode As Int32, ByVal lpInBuffer As IntPtr, ByVal nInBufferSize As Int32, <[In](), Out()> ByRef lpOutBuffer As GETVERSIONINPARAMS, ByVal nOutBufferSize As Int32, ByRef lpBytesReturned As Int32, ByVal lpOverlapped As Int32) As Int32
End Function
<DllImport("kernel32.dll", SetLastError:=True)> _
Private Shared Function DeviceIoControl(ByVal hDevice As SafeFileHandle, ByVal dwIoControlCode As Int32, <[In]()> ByRef lpInBuffer As STORAGE_PROPERTY_QUERY, ByVal nInBufferSize As Int32, <[In](), Out()> ByRef lpOutBuffer As STORAGE_DEVICE_DESCRIPTOR, ByVal nOutBufferSize As Int32, ByRef lpBytesReturned As Int32, ByVal lpOverlapped As Int32) As Int32
End Function
<DllImport("kernel32.dll", SetLastError:=True)> _
Private Shared Function DeviceIoControl(ByVal hDevice As SafeFileHandle, ByVal dwIoControlCode As Int32, <[In]()> ByRef lpInBuffer As SCSI_PASS_THROUGH_WITH_BUFFER, ByVal nInBufferSize As Int32, <[In](), Out()> ByRef lpOutBuffer As SCSI_PASS_THROUGH_WITH_BUFFER, ByVal nOutBufferSize As Int32, ByRef lpBytesReturned As Int32, ByVal lpOverlapped As Int32) As Int32
End Function
Private Const OPEN_EXISTING As Int32 = 3
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 FILE_SHARE_DELETE As Int32 = &H4
Private Const SMART_GET_VERSION As Int32 = &H74080
Private Const SMART_RCV_DRIVE_DATA As Int32 = &H7C088
Private Const ID_CMD As Int32 = &HEC
Private Const IDENTIFY_BUFFER_SIZE As Int32 = 512
Private Const CAP_SMART_CMD As Int32 = &H4
Private Const IOCTL_STORAGE_QUERY_PROPERTY As Int32 = &H2D1400
Private Const IOCTL_SCSI_PASS_THROUGH As Int32 = &H4D004
Private Const SCSI_IOCTL_DATA_IN As Int32 = &H1
Private Const PropertyStandardQuery As Int32 = 0
Private Const StorageDeviceProperty As Int32 = 0
Private Const ERROR_INVALID_FUNCTION As Int32 = &H1
#End Region
Public Shared Function GetSerialNumberUsingStorageQuery(ByVal diskNumber As Integer) As String
Using hDisk As SafeFileHandle = OpenDisk(diskNumber)
Dim iBytesReturned As Int32
Dim spq As New STORAGE_PROPERTY_QUERY()
Dim sdd As New STORAGE_DEVICE_DESCRIPTOR()
spq.PropertyId = StorageDeviceProperty
spq.QueryType = PropertyStandardQuery
If DeviceIoControl(hDisk, IOCTL_STORAGE_QUERY_PROPERTY, spq, Marshal.SizeOf(spq), sdd, Marshal.SizeOf(sdd), iBytesReturned, 0) = 0 Then
Throw CreateWin32Exception(Marshal.GetLastWin32Error(), "DeviceIoControl(IOCTL_STORAGE_QUERY_PROPERTY)")
End If
Dim result As New StringBuilder()
If sdd.SerialNumberOffset > 0 Then
Dim rawDevicePropertiesOffset As Integer = Marshal.SizeOf(sdd) - sdd.RawDeviceProperties.Length
Dim pos As Integer = sdd.SerialNumberOffset - rawDevicePropertiesOffset
While pos < iBytesReturned And sdd.RawDeviceProperties(pos) <> 0
result.Append(Encoding.ASCII.GetString(sdd.RawDeviceProperties, pos, 1))
pos += 1
End While
End If
Return result.ToString().Trim()
End Using
End Function
Public Shared Function GetSerialNumberUsingSmart(ByVal diskNumber As Integer) As String
Using hDisk As SafeFileHandle = OpenDisk(diskNumber)
If IsSmartSupported(hDisk) Then
Dim iBytesReturned As Int32
Dim sci As New SENDCMDINPARAMS
Dim sco As New SENDCMDOUTPARAMS
sci.irDriveRegs.bCommandReg = ID_CMD
sci.bDriveNumber = CByte(diskNumber)
sci.cBufferSize = IDENTIFY_BUFFER_SIZE
If DeviceIoControl(hDisk, SMART_RCV_DRIVE_DATA, sci, Marshal.SizeOf(sci), sco, Marshal.SizeOf(sco), iBytesReturned, 0) = 0 Then
Throw CreateWin32Exception(Marshal.GetLastWin32Error(), "DeviceIoControl(SMART_RCV_DRIVE_DATA)")
End If
Dim result As New StringBuilder()
For index As Integer = 20 To 39 Step 2
result.Append(Encoding.ASCII.GetString(sco.bBuffer, index + 1, 1))
result.Append(Encoding.ASCII.GetString(sco.bBuffer, index, 1))
Next
Return result.ToString().Trim()
Else
Return String.Empty
End If
End Using
End Function
Public Shared Function GetSerialNumberUsingScsiPassThrough(ByVal diskNumber As Integer) As String
Using hDisk As SafeFileHandle = OpenDisk(diskNumber)
Dim iBytesReturned As Int32
Dim spt As New SCSI_PASS_THROUGH_WITH_BUFFER
spt.Spt.Length = CShort(Marshal.SizeOf(spt.Spt))
spt.Spt.CdbLength = 16
spt.Spt.DataIn = SCSI_IOCTL_DATA_IN
spt.Spt.DataTransferLength = 64
spt.Spt.DataBufferOffset = New IntPtr(Marshal.SizeOf(spt) - 64)
spt.Spt.TimeOutValue = 60
Dim cdb(15) As Byte
cdb(0) = &H12 ' INQUIRY
cdb(1) = &H1 ' EVPD bit
cdb(2) = &H80 ' Page code (indicates Serial Number)
cdb(4) = 64 ' Allocation length
spt.Spt.Cdb = cdb
If DeviceIoControl(hDisk, IOCTL_SCSI_PASS_THROUGH, spt, Marshal.SizeOf(spt), spt, Marshal.SizeOf(spt), iBytesReturned, 0) = 0 Then
Dim iErrorCode As Int32 = Marshal.GetLastWin32Error()
If iErrorCode <> ERROR_INVALID_FUNCTION Then
Throw CreateWin32Exception(iErrorCode, "DeviceIoControl(IOCTL_SCSI_PASS_THROUGH)")
End If
End If
Dim result As New StringBuilder()
Dim pos As Integer = IntPtr.Size
While pos < spt.Spt.DataTransferLength And spt.Buffer(pos) <> 0
result.Append(Encoding.ASCII.GetString(spt.Buffer, pos, 1))
pos += 1
End While
Return result.ToString().Trim()
End Using
End Function
Private Shared Function CreateWin32Exception(ByVal errorCode As Int32, ByVal context As String) As Win32Exception
Dim win32Exception As New Win32Exception(errorCode)
win32Exception.Data("Context") = context
Return win32Exception
End Function
Private Shared Function OpenDisk(ByVal diskNumber As Integer) As SafeFileHandle
Dim hDevice As SafeFileHandle = CreateFile(String.Format("\\.\PhysicalDrive{0}", diskNumber), GENERIC_READ Or GENERIC_WRITE, FILE_SHARE_READ Or FILE_SHARE_WRITE Or FILE_SHARE_DELETE, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero)
If (Not hDevice.IsInvalid) Then
Return hDevice
Else
Throw CreateWin32Exception(Marshal.GetLastWin32Error(), "CreateFile")
End If
End Function
Private Shared Function IsSmartSupported(ByVal hDisk As SafeFileHandle) As Boolean
Dim iBytesReturned As Int32
Dim gvi As New GETVERSIONINPARAMS
If DeviceIoControl(hDisk, SMART_GET_VERSION, IntPtr.Zero, 0, gvi, Marshal.SizeOf(gvi), iBytesReturned, 0) = 0 Then
Return False
End If
Return (gvi.fCapabilities And CAP_SMART_CMD) > 0
End Function
End Class
以下是调用它的代码:
' MainModule.vb
Module MainModule
Sub Main()
Console.WriteLine("{0}-bit runtime.", IntPtr.Size * 8)
For drive As Integer = 0 To 4
Try
Console.WriteLine("Drive {0}, SMART: [{1}]", drive, PhysicalDrive.GetSerialNumberUsingSmart(drive))
Console.WriteLine("Drive {0}, Storage Query: [{1}]", drive, PhysicalDrive.GetSerialNumberUsingStorageQuery(drive))
Console.WriteLine("Drive {0}, SCSI Pass Through: [{1}]", drive, PhysicalDrive.GetSerialNumberUsingScsiPassThrough(drive))
Catch ex As Exception
If ex.Data("Context") IsNot Nothing Then Console.Error.Write("{0} failed: ", ex.Data("Context"))
Console.Error.WriteLine(ex.Message)
End Try
Next
End Sub
End Module
编辑 - 我更改了主要方法,以显示每次比较尝试的结果。这将有希望说明这些技术的成功与否。
答案 1 :(得分:3)
将DeviceIoControl与IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER
一起使用答案 2 :(得分:2)
This code应该为您提供硬盘序列号。它与您链接到的代码类似(ReadPhysicalDriveInNTWithAdminRights
),但有几个附加功能。
答案 3 :(得分:2)
您需要确保您的P / Invoke定义是64位友好的。或者,尝试将解决方案中项目的目标CPU设置为32位。有关P / Invoke和64位的更多信息可以在here找到。
修改强>
以下重写代码可能对您更有效 - 基本上我已经整理了P / Invoke定义并添加了更好的错误处理。该代码尝试两次获取序列号。第一个使用IOCTL_STORAGE_QUERY_PROPERTY
,第二个使用SMART_RCV_DRIVE_DATA
。
' PhysicalDrive.vb
Option Strict On
Option Explicit On
Imports System.Runtime.InteropServices
Imports System.Text
Imports System.ComponentModel
Imports Microsoft.Win32.SafeHandles
Public Class PhysicalDrive
#Region "Win32 Definitions"
<StructLayout(LayoutKind.Sequential)> _
Private 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)> _
Private 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()
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=1)> _
Public bBuffer As Byte()
End Structure
<StructLayout(LayoutKind.Sequential)> _
Private Structure DRIVERSTATUS
Public bDriverError As Byte
Public bIDEError 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)> _
Private Structure SENDCMDOUTPARAMS
Public cBufferSize As Int32
Public DriverStatus As DRIVERSTATUS
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=IDENTIFY_BUFFER_SIZE)> _
Public bBuffer As Byte()
End Structure
<StructLayout(LayoutKind.Sequential)> _
Private 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
<StructLayout(LayoutKind.Sequential)> _
Private Structure STORAGE_PROPERTY_QUERY
Public PropertyId As Int32
Public QueryType As Int32
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=1)> _
Public AdditionalParameters As Byte()
End Structure
<StructLayout(LayoutKind.Sequential)> _
Private Structure STORAGE_DEVICE_DESCRIPTOR
Public Version As Int32
Public Size As Int32
Public DeviceType As Byte
Public DeviceTypeModifier As Byte
Public RemovableMedia As Byte
Public CommandQueueing As Byte
Public VendorIdOffset As Int32
Public ProductIdOffset As Int32
Public ProductRevisionOffset As Int32
Public SerialNumberOffset As Int32
Public BusType As Byte
Public RawPropertiesLength As Int32
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=10240)> _
Public RawDeviceProperties As Byte()
End Structure
<DllImport("kernel32.dll", SetLastError:=True)> _
Private Shared Function CreateFile(ByVal lpFileName As String, ByVal dwDesiredAccess As Int32, ByVal dwShareMode As Int32, ByVal lpSecurityAttributes As IntPtr, ByVal dwCreationDisposition As Int32, ByVal dwFlagsAndAttributes As Int32, ByVal hTemplateFile As IntPtr) As SafeFileHandle
End Function
<DllImport("kernel32.dll", SetLastError:=True)> _
Private Shared Function DeviceIoControl(ByVal hDevice As SafeFileHandle, ByVal dwIoControlCode As Int32, <[In](), Out()> ByRef lpInBuffer As SENDCMDINPARAMS, ByVal nInBufferSize As Int32, <[In](), Out()> ByRef lpOutBuffer As SENDCMDOUTPARAMS, ByVal nOutBufferSize As Int32, ByRef lpBytesReturned As Int32, ByVal lpOverlapped As Int32) As Int32
End Function
<DllImport("kernel32.dll", SetLastError:=True)> _
Private Shared Function DeviceIoControl(ByVal hDevice As SafeFileHandle, ByVal dwIoControlCode As Int32, ByVal lpInBuffer As IntPtr, ByVal nInBufferSize As Int32, <[In](), Out()> ByRef lpOutBuffer As GETVERSIONOUTPARAMS, ByVal nOutBufferSize As Int32, ByRef lpBytesReturned As Int32, ByVal lpOverlapped As Int32) As Int32
End Function
<DllImport("kernel32.dll", SetLastError:=True)> _
Private Shared Function DeviceIoControl(ByVal hDevice As SafeFileHandle, ByVal dwIoControlCode As Int32, <[In](), Out()> ByRef lpInBuffer As STORAGE_PROPERTY_QUERY, ByVal nInBufferSize As Int32, <[In](), Out()> ByRef lpOutBuffer As STORAGE_DEVICE_DESCRIPTOR, ByVal nOutBufferSize As Int32, ByRef lpBytesReturned As Int32, ByVal lpOverlapped As Int32) As Int32
End Function
Private Const OPEN_EXISTING As Int32 = 3
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 FILE_SHARE_DELETE As Int32 = &H4
Private Const SMART_GET_VERSION As Int32 = &H74080
Private Const SMART_RCV_DRIVE_DATA As Int32 = &H7C088
Private Const ID_CMD As Int32 = &HEC
Private Const IDENTIFY_BUFFER_SIZE As Int32 = 512
Private Const CAP_SMART_CMD As Int32 = &H4
Private Const IOCTL_STORAGE_QUERY_PROPERTY As Int32 = &H2D1400
Private Const PropertyStandardQuery As Int32 = 0
Private Const StorageDeviceProperty As Int32 = 0
#End Region
Public Shared Function GetSerialNumber(ByVal diskNumber As Integer) As String
Dim result As String = GetSerialNumberUsingStorageQuery(diskNumber)
If String.IsNullOrEmpty(result) Then
result = GetSerialNumberUsingSmart(diskNumber)
End If
Return result
End Function
Public Shared Function GetSerialNumberUsingStorageQuery(ByVal diskNumber As Integer) As String
Using hDisk As SafeFileHandle = OpenDisk(diskNumber)
Dim iBytesReturned As Int32
Dim spq As New STORAGE_PROPERTY_QUERY()
Dim sdd As New STORAGE_DEVICE_DESCRIPTOR()
spq.PropertyId = StorageDeviceProperty
spq.QueryType = PropertyStandardQuery
If DeviceIoControl(hDisk, IOCTL_STORAGE_QUERY_PROPERTY, spq, Marshal.SizeOf(spq), sdd, Marshal.SizeOf(sdd), iBytesReturned, 0) = 0 Then
Throw CreateWin32Exception(Marshal.GetLastWin32Error(), "DeviceIoControl(IOCTL_STORAGE_QUERY_PROPERTY)")
End If
Dim result As New StringBuilder()
If sdd.SerialNumberOffset > 0 Then
Dim rawDevicePropertiesOffset As Integer = Marshal.SizeOf(sdd) - sdd.RawDeviceProperties.Length
Dim pos As Integer = sdd.SerialNumberOffset - rawDevicePropertiesOffset
While pos < iBytesReturned And sdd.RawDeviceProperties(pos) <> 0
result.Append(Encoding.ASCII.GetString(sdd.RawDeviceProperties, pos, 1))
pos += 1
End While
End If
Return result.ToString()
End Using
End Function
Public Shared Function GetSerialNumberUsingSmart(ByVal diskNumber As Integer) As String
Using hDisk As SafeFileHandle = OpenDisk(diskNumber)
If IsSmartSupported(hDisk) Then
Dim iBytesReturned As Int32
Dim sci As New SENDCMDINPARAMS
Dim sco As New SENDCMDOUTPARAMS
sci.irDriveRegs.bCommandReg = ID_CMD
sci.bDriveNumber = CByte(diskNumber)
sci.cBufferSize = IDENTIFY_BUFFER_SIZE
If DeviceIoControl(hDisk, SMART_RCV_DRIVE_DATA, sci, Marshal.SizeOf(sci), sco, Marshal.SizeOf(sco), iBytesReturned, 0) = 0 Then
Throw CreateWin32Exception(Marshal.GetLastWin32Error(), "DeviceIoControl(SMART_RCV_DRIVE_DATA)")
End If
Dim result As New StringBuilder()
For index As Integer = 20 To 39 Step 2
result.Append(Encoding.ASCII.GetString(sco.bBuffer, index + 1, 1))
result.Append(Encoding.ASCII.GetString(sco.bBuffer, index, 1))
Next
Return result.ToString()
Else
Return String.Empty
End If
End Using
End Function
Private Shared Function CreateWin32Exception(ByVal errorCode As Int32, ByVal context As String) As Win32Exception
Dim win32Exception As New Win32Exception(errorCode)
win32Exception.Data("Context") = context
Return win32Exception
End Function
Private Shared Function OpenDisk(ByVal diskNumber As Integer) As SafeFileHandle
Dim hDevice As SafeFileHandle = CreateFile(String.Format("\\.\PhysicalDrive{0}", diskNumber), GENERIC_READ Or GENERIC_WRITE, FILE_SHARE_READ Or FILE_SHARE_WRITE Or FILE_SHARE_DELETE, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero)
If (Not hDevice.IsInvalid) Then
Return hDevice
Else
Throw CreateWin32Exception(Marshal.GetLastWin32Error(), "CreateFile")
End If
End Function
Private Shared Function IsSmartSupported(ByVal hDisk As SafeFileHandle) As Boolean
Dim iBytesReturned As Int32
Dim gvo As New GETVERSIONOUTPARAMS
If DeviceIoControl(hDisk, SMART_GET_VERSION, IntPtr.Zero, 0, gvo, Marshal.SizeOf(gvo), iBytesReturned, 0) = 0 Then
Return False
End If
Return (gvo.fCapabilities And CAP_SMART_CMD) > 0
End Function
End Class
这是调用它的代码:
' MainModule.vb
Module MainModule
Sub Main()
Console.WriteLine("{0}-bit runtime.", IntPtr.Size * 8)
For drive As Integer = 0 To 4
Try
Console.WriteLine("Drive {0} - serial number: [{1}]", drive, PhysicalDrive.GetSerialNumber(drive))
Catch ex As Exception
If ex.Data("Context") IsNot Nothing Then Console.Error.Write("{0} failed: ", ex.Data("Context"))
Console.Error.WriteLine(ex.Message)
End Try
Next
End Sub
End Module
我只有一台要测试的64位计算机,但是这段代码可以正常运行。
答案 4 :(得分:1)
开始使用Windows 7 64:
ManagementObjectSearcher mos = new ManagementObjectSearcher("SELECT * FROM Win32_DiskDrive");
foreach (ManagementObject obj in mos.Get()) {
Trace.TraceInformation("Information about disk drive {0}:", obj["Name"]);
Trace.Indent();
foreach (PropertyData pd in obj.Properties)
Trace.TraceInformation("Name \"{0}\": \"{1}\"", pd.Name, pd.Value);
Trace.Unindent();
obj.Properties["SerialNumber"]
}
可能在64位平台上没有提供Win32_PhysicalMedia类。
此时甚至Disk32正在工作(在翻转序列号字节时除了错误),因为它基于相同的概念。
答案 5 :(得分:0)
从代码here修改:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Management;
using System.Text;
namespace Console_DiskDrive
{
class Program
{
static void Main(string[] args)
{
String query = "SELECT * FROM Win32_DiskDrive";
foreach (ManagementObject item in new ManagementObjectSearcher(query).Get())
{
string serialNumber = Convert.ToString(item["SerialNumber"]);
Console.WriteLine(serialNumber);
}
Console.ReadLine();
}
}
}
在运行Vista Home Premium x64的系统上,给我一个40个字符的十六进制字符串,我假设是我的序列号。我打开盒子并稍后确认,但试一试,看看它是不是你想要的。
答案 6 :(得分:-1)
您可能希望使用Windows非托管API执行此操作:
使用正确的结构调用GetVolumeInformation api并找到VolumeSerialNumber整数字段。
此API已经存在很长时间了,自从Windows 98以来一直在为我工作。不幸的是,无法在x64上查看它。
您能否使用其他Windows工具查看正确的序列号? 顺便说一下:'0'是一个有效的序列号!如果从备份或类似的东西恢复磁盘映像,则可能会发生这种情况。