How can I read HDD volume serial number using VB.NET but without any third party addons for Visual Studio or any external libraries – I neeed native VB.NET code for this if possible.
Vb.net – How to read HDD volume serial number using VB.NET
hard drivevb.net
Related Solutions
I found it! Here is the equivalent VB.NET code. It's not exactly the converted version of the VB6 code, but does the same thing. Enjoy!
Public Class HDDInfo
#Region " Declatrations "
Private Declare 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
<System.Runtime.InteropServices.DllImport("kernel32.dll")> _
Private Shared Function CloseHandle(ByVal hObject As Integer) As Integer
End Function
<System.Runtime.InteropServices.DllImport("kernel32.dll")> _
Private Shared Function DeviceIoControl(ByVal hDevice As Integer, ByVal dwIoControlCode As Integer, <[In](), Out()> ByVal lpInBuffer As SENDCMDINPARAMS, ByVal lpInBufferSize As Integer, <[In](), Out()> ByVal lpOutBuffer As SENDCMDOUTPARAMS, ByVal lpOutBufferSize As Integer, _
ByRef lpBytesReturned As Integer, ByVal lpOverlapped As Integer) As Integer
End Function
Private Const FILE_SHARE_READ As Short = &H1
Private Const FILE_SHARE_WRITE As Short = &H2
Private Const GENERIC_READ As Integer = &H80000000
Private Const GENERIC_WRITE As Integer = &H40000000
Private Const OPEN_EXISTING As Short = 3
Private Const CREATE_NEW As Short = 1
Private Const VER_PLATFORM_WIN32_NT As Integer = 2
Private Const DFP_RECEIVE_DRIVE_DATA As Integer = &H7C088
Private Const INVALID_HANDLE_VALUE As Integer = -1
#End Region
#Region " Classes "
<StructLayout(LayoutKind.Sequential, Size:=8)> _
Private Class 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
<StructLayout(LayoutKind.Sequential, Size:=32)> _
Private Class SENDCMDINPARAMS
Public BufferSize As Integer
Public DriveRegs As IDEREGS
Public DriveNumber As Byte
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=3)> _
Public Reserved As Byte()
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=4)> _
Public Reserved2 As Integer()
Public Sub New()
DriveRegs = New IDEREGS()
Reserved = New Byte(2) {}
Reserved2 = New Integer(3) {}
End Sub
End Class
<StructLayout(LayoutKind.Sequential, Size:=12)> _
Private Class DRIVERSTATUS
Public DriveError As Byte
Public IDEStatus As Byte
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=2)> _
Public Reserved As Byte()
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=2)> _
Public Reserved2 As Integer()
Public Sub New()
Reserved = New Byte(1) {}
Reserved2 = New Integer(1) {}
End Sub
End Class
<StructLayout(LayoutKind.Sequential)> _
Private Class IDSECTOR
Public GenConfig As Short
Public NumberCylinders As Short
Public Reserved As Short
Public NumberHeads As Short
Public BytesPerTrack As Short
Public BytesPerSector As Short
Public SectorsPerTrack As Short
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=3)> _
Public VendorUnique As Short()
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=20)> _
Public SerialNumber As Char()
Public BufferClass As Short
Public BufferSize As Short
Public ECCSize As Short
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=8)> _
Public FirmwareRevision As Char()
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=40)> _
Public ModelNumber As Char()
Public MoreVendorUnique As Short
Public DoubleWordIO As Short
Public Capabilities As Short
Public Reserved1 As Short
Public PIOTiming As Short
Public DMATiming As Short
Public BS As Short
Public NumberCurrentCyls As Short
Public NumberCurrentHeads As Short
Public NumberCurrentSectorsPerTrack As Short
Public CurrentSectorCapacity As Integer
Public MultipleSectorCapacity As Short
Public MultipleSectorStuff As Short
Public TotalAddressableSectors As Integer
Public SingleWordDMA As Short
Public MultiWordDMA As Short
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=382)> _
Public Reserved2 As Byte()
End Class
<StructLayout(LayoutKind.Sequential)> _
Private Class SENDCMDOUTPARAMS
Public BufferSize As Integer
Public Status As DRIVERSTATUS
Public IDS As IDSECTOR
Public Sub New()
Status = New DRIVERSTATUS()
IDS = New IDSECTOR()
End Sub
End Class
#End Region
#Region " Methods and Functions "
Private Shared Function SwapChars(ByVal chars As Char()) As String
For i As Integer = 0 To chars.Length - 2 Step 2
Dim t As Char
t = chars(i)
chars(i) = chars(i + 1)
chars(i + 1) = t
Next
Dim s As New String(chars)
Return s
End Function
Public Shared Function GetHDDInfoString() As String
Dim serialNumber As String = " ", model As String = " ", firmware As String = " "
Dim handle As Integer, returnSize As Integer = 0
Dim driveNumber As Integer = 0
Dim sci As New SENDCMDINPARAMS()
Dim sco As New SENDCMDOUTPARAMS()
If Environment.OSVersion.Platform = PlatformID.Win32NT Then
handle = CreateFile("\\.\PhysicalDrive" & "0", GENERIC_READ + GENERIC_WRITE, FILE_SHARE_READ + FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0)
Else
handle = CreateFile("\\.\Smartvsd", 0, 0, 0, CREATE_NEW, 0, 0)
End If
If handle <> INVALID_HANDLE_VALUE Then
sci.DriveNumber = CByte(driveNumber)
sci.BufferSize = Marshal.SizeOf(sco)
sci.DriveRegs.DriveHead = CByte((&HA0 Or driveNumber << 4))
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)
End If
CloseHandle(handle)
End If
Return model.Trim & " " & serialNumber.Trim
End Function
#End Region
End Class
You can use WMI (Windows Management Instrumentation) like this:
Dim mos As New ManagementObjectSearcher("SELECT * FROM Win32_PhysicalMedia")
For Each mo As ManagementObject In mos.Get()
Dim serial As String = mo("SerialNumber").ToString()
Next
Although, I've read about cases in which no serial number is returned using WMI. Another way to accomplish this would be through Platform Invocation Services (PInvoke).
This article includes a download in which the author implements CreateFile() and DeviceIoControl() to extract drive information through Interop services in VB .NET.
To use either of the above outlined methods you will need ADMIN rights, a utility which seems to circumvent this can be found here. If your feeling adventurous the C++/Win32 source code is available for you to peruse. (Check out the function 'ReadPhysicalDriveInNTWithZeroRights()')
Best Answer