Hardware [vb.net] Get Hard Disk Manufacture/ Factory Serial Number
페이지 정보

본문
So many question about how to get hard disk physical serial number, and mostly answered by using WMI. And it doesn't solve my problem.
I used to use HDSN code that I got from Planet Source Code when I was still using Visual Basic 6 (VB6). And now with VB.NET I need the same result but I couldn't get it with WMI. Is there any other way to get  Factory Serial Number without WMI?
Finally I got the best solution using DeviceIOControl that I got from a blog named jo0ls' .Net stuff.
And I adapt it to my code to fulfill my need.
Here are the steps. First I created a windows form project/solution named HDDSerial Number, add a module name SerialNumber.vb and type below codes:
 
Imports System.Runtime.InteropServices
ImportsMicrosoft.Win32.SafeHandles
Imports System.Security
ImportsSystem.ComponentModel
Imports System.Text
Module SerialNumber
  <SuppressUnmanagedCodeSecurity()> _
  Private Class NativeMethods
      <DllImport("kernel32", SetLastError:=True)> _
      Public Shared Function CreateFile( _
       ByVal FileName As String, _
       ByVal DesiredAccess As Integer, _
       ByVal ShareMode As Integer, _
       ByVal SecurityAttributes As IntPtr, _
       ByVal CreationDisposition As Integer, _
       ByVal FlagsAndAttributes As Integer, _
       ByVal hTemplateFile As IntPtr) As SafeFileHandle
      End Function
      <DllImport("kernel32.dll", SetLastError:=True)> _
      Friend Shared Function DeviceIoControl( _
          ByVal deviceHandle As SafeFileHandle, _
          ByVal controlCode As Integer, _
          ByRef inBuffer As ATA_PASS_THROUGH_EX_WITH_BUFFERS, _
          ByVal inBufferSize As Integer, _
          ByRef outBuffer As ATA_PASS_THROUGH_EX_WITH_BUFFERS, _
          ByVal outBufferSize As Integer, _
          ByRef bytesReturned As Integer, _
          ByVal overlapped1 As IntPtr) As Boolean
      End Function
  End Class
  <StructLayout(LayoutKind.Sequential)> _
  Private Structure ATA_PASS_THROUGH_EX
      Public Length As Short
      Public AtaFlags As Short
      Public PathId As Byte
      Public TargetId As Byte
      Public Lun As Byte
      Public ReservedAsUchar As Byte
      Public DataTransferLength As Integer
      Public TimeOutValue As Integer
      Public ReservedAsUlong As Integer
      Public DataBufferOffset As IntPtr
      <MarshalAs(UnmanagedType.ByValArray, sizeconst:=8)> _
      Public PreviousTaskFile() As Byte
      <MarshalAs(UnmanagedType.ByValArray, sizeconst:=8)> _
      Public CurrentTaskFile() As Byte
  End Structure
  <StructLayout(LayoutKind.Sequential)> _
  Private Structure ATA_PASS_THROUGH_EX_WITH_BUFFERS
      Public Apt As ATA_PASS_THROUGH_EX
      <MarshalAs(UnmanagedType.ByValArray, sizeconst:=512)> _
      Public Data() As Byte
  End Structure
  Public Enum HDINFO
      HD_MODEL_NUMBER = 0
      HD_SERIAL_NUMBER = 1
      HD_FIRMWARE_REVISION = 2
  End Enum
  Public Function HDDInfo(ByVal InfoType As HDINFO) As String
      Dim letter As Char = "c"
      Const GenericRead As Integer = &H80000000
      Const GenericWrite As Integer = &H40000000
      Const FileShareRead As Integer = 1
      Const FileShareWrite As Integer = 2
      Const OpenExisting As Integer = 3
      Dim drivePath As String = String.Concat("\\.\" & letter & ":")
      Using driveHandle As SafeFileHandle = NativeMethods.CreateFile( _
       drivePath, _
       GenericRead Or GenericWrite, _
       FileShareRead Or FileShareWrite, _
       IntPtr.Zero, _
       OpenExisting, _
       0, _
       IntPtr.Zero)
          If driveHandle.IsInvalid Then
             Return "CreateFile ERROR: " & (New Win32Exception).Message
          End If
          Dim apex As New ATA_PASS_THROUGH_EX
          apex.Length = Marshal.SizeOf(apex)
          ' ATA_FLAGS_DATA_IN
          apex.AtaFlags = 2
          ' The command returns a 512 byte package of info.
          apex.DataTransferLength = 512
          apex.TimeOutValue = 10 ' 10 second timeout.
          apex.DataBufferOffset = Marshal.OffsetOf( _
                    GetType(ATA_PASS_THROUGH_EX_WITH_BUFFERS), "Data")
          ' This contains the command we are requesting.
          apex.CurrentTaskFile = New Byte(7) {}
          'the command "IDENTIFY DEVICE"
          apex.CurrentTaskFile(6) = &HEC
          Dim apexb As New ATA_PASS_THROUGH_EX_WITH_BUFFERS
          apexb.Apt = apex
          Dim inBufferSize As Integer = Marshal.SizeOf( _
                   GetType(ATA_PASS_THROUGH_EX_WITH_BUFFERS))
          Dim bytesReturned As Integer
          Const IOCTL_ATA_PASS_THROUGH As Integer = &H4D02C
          Dim result As Boolean = NativeMethods.DeviceIoControl( _
                                  driveHandle, IOCTL_ATA_PASS_THROUGH, _
                                  apexb, inBufferSize, apexb, inBufferSize, _
                                  bytesReturned, IntPtr.Zero)
          If result = False Then
              Return "DeviceIOControl ERROR: " & (New Win32Exception).Message
          End If
          Select Case InfoType
              Case HDINFO.HD_SERIAL_NUMBER
                  Return GetString(apexb.Data, 20, 20)
              Case HDINFO.HD_FIRMWARE_REVISION
                  Return GetString(apexb.Data, 46, 8)
              Case HDINFO.HD_MODEL_NUMBER
                  Return GetString(apexb.Data, 54, 40)
              Case Else
                  Return Nothing
          End Select
      End Using
  End Function
  Private Function GetString(ByVal bytes() As Byte, _
                             ByVal offset As Integer, _
                             ByVal length As Integer) As String
      ' The strings are slightly weird - endianness? 
      ' If you use ASCII.GetBytes Then Each character 
      ' pair is reversed.
      Dim sb As New StringBuilder()
      For i As Integer = offset To offset + length - 1 Step 2
          sb.Append(Chr(bytes(i + 1)))
          sb.Append(Chr(bytes(i)))
      Next
      Return RTrim(LTrim(sb.ToString))
  End Function
End Module
Set UI of Form1 Text "Hardisk Serial Number", add 3 labels and 3 TextBoxes. Name textboxes as txtSerialNumber, txtModel, and txtFirmware.
Then type below code:
Imports System.Management
Public Class Form1
    Private Sub Form1_Load(ByVal sender As Object, _
          ByVal e As EventArgs) Handles MyBase.Load
        Try
            txtSerialNumber.Text = HDDInfo(HDINFO.HD_SERIAL_NUMBER)
            txtModel.Text = HDDInfo(HDINFO.HD_MODEL_NUMBER)
            txtFirmware.Text = HDDInfo(HDINFO.HD_FIRMWARE_REVISION)
        Catch ex As Exception
            MsgBox(ex.Message)
        End Try
    End Sub
End Class
Test run, then here is my PC result: 
Notes: Don't forget to Run as Administrator so application could work properly on Vista, Windows 7, and Windows 8.
Reference:
http://stackoverflow.com/questions/782053/get-hdd-and-not-volume-serial-number-on-vista-ultimate-64-bit
http://jo0ls-dotnet-stuff.blogspot.co.id/2011/02/getting-hard-disk-drive-info-with.html
Click here if you like this article. 
- 이전글[vb.net] DataGridView 특정 컬럼 오름차순 정렬 / 내림차순 정렬 19.07.16
 - 다음글[vb.net] 하드(HDD) 시리얼 넘버(hard drive serial number) 가지고 오기 19.07.13
 
댓글목록
등록된 댓글이 없습니다.






