2009-04-23 24 views
10

Tôi đã từng tìm kiếm số sê-ri HDD mà không sử dụng WMI và tôi đã tìm thấy nó. The code I found and posted on StackOverFlow.com hoạt động rất tốt trên Windows 32 bit, cả XP và Vista. Sự cố chỉ bắt đầu khi tôi cố gắng lấy số sê-ri trên hệ điều hành 64 bit (Vista Ultimate 64, cụ thể). Mã này trả về String.Empty hoặc không gian mọi lúc.Nhận số sê-ri HDD (và KHÔNG Khối lượng) trên Vista Ultimate 64 bit

Bất kỳ ai cũng có ý tưởng khắc phục sự cố này?

EDIT:

tôi đã sử dụng các công cụ Dave Cluderay đề nghị, với những kết quả thú vị:

Đây là kết quả từ DiskId32, trên Windows XP SP2 32-bit:

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 

Và DiskId32 chạy trên Windows Vista Ultimate 64 bit:

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___________: 

Lưu ý số tiền ít hơn xóa thông tin trên Vista và cách số sê-ri không được trả lại. Ngoài ra công cụ khác, EnumDisk, đề cập đến đĩa cứng của tôi trên Vista là "SCSI" trái ngược với "ATA" trên Windows XP.

Bất kỳ ý tưởng nào?

EDIT 2:

tôi đăng các kết quả từ EnumDisks:

Trên Windows XP SP2 32-bit:

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 *** 

Và trên Vista 64 cuối cùng:

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

Một số thông tin khác có thể có liên quan - là hai hệ điều hành trên cùng một máy vật lý (tức là khởi động kép) hoặc các máy riêng biệt? Là một máy ảo? Bất cứ điều gì đáng chú ý về các đĩa, ví dụ: (RAID, v.v.)? –

+0

Cả hai hệ điều hành đều trên cùng một máy vật lý. Không có máy ảo nào được sử dụng. Không có gì đặc biệt về ổ cứng của tôi, một ổ cứng ATA MAXTOR 160 GB điển hình. – TheAgent

+0

Xin chào một lần nữa. Có lẽ EnumDisk1 cũng không nhận được số sê-ri trên Vista 64? –

Trả lời

-1

Bạn có thể muốn sử dụng API không được quản lý của Windows để thực hiện việc này:

gọi GetVolumeInformation api với cấu trúc phù hợp và tìm trường Số lượngSerialNumber.

API này có ở mọi lứa tuổi và đang hoạt động cho tôi kể từ Windows 98. Rất tiếc, không thể kiểm tra trên x64.

Bạn có thể thấy số sê-ri chính xác bằng các công cụ Windows khác không? Nhân tiện: '0' là số sê-ri hợp lệ! Điều này có thể xảy ra nếu hình ảnh đĩa được khôi phục từ bản sao lưu hoặc một cái gì đó tương tự.

+0

Cảm ơn bạn đã trả lời, nhưng tôi không tìm số sê-ri Số lượng, nhưng số sêri của ổ đĩa cứng, số kiểu, v.v. – TheAgent

2

This code sẽ cung cấp cho bạn số sêri đĩa cứng. Nó tương tự (ReadPhysicalDriveInNTWithAdminRights) với mã của bạn mà bạn đã liên kết nhưng với một số chức năng bổ sung.

+2

Anh ấy đang làm việc trong VB.NET không phải C++ – joshperry

2

Bạn cần phải đảm bảo rằng P/Gọi các định nghĩa của bạn là 64-bit thân thiện. Ngoài ra, hãy thử đặt CPU mục tiêu của các dự án trong giải pháp của bạn thành 32-bit. Thông tin thêm về P/Invoke và 64-bit có thể được tìm thấy here.

EDIT:

Mã viết lại sau đây có thể làm việc tốt hơn cho bạn - về cơ bản tôi đã sắp xếp gọn gàng lên P/Gọi các định nghĩa và bổ sung xử lý lỗi tốt hơn. Mã này thực hiện hai lần thử để lấy số sê-ri. Việc sử dụng đầu tiên IOCTL_STORAGE_QUERY_PROPERTY và sử dụng thứ hai 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 

Đây là mã để gọi nó là:

' 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 

tôi chỉ có một máy 64-bit để kiểm tra chống lại, nhưng mã này làm việc trên đó.

+0

Một Vista 64 bit? Vì tôi đã thử nghiệm mã này trên Vista Ultimate 64-bit của mình và nó vẫn trả về một chuỗi rỗng. (Tôi sử dụng String.Trim trên kết quả vì có các ký tự khoảng trống bổ sung được trả lại trước số sê-ri thực sự trên các hệ điều hành 32 bit) Không có mã .NET có vẻ đã trả về SN. Làm thế nào tôi có thể liên lạc với một lập trình viên từ MS để thảo luận về vấn đề này? – TheAgent

+0

Tôi đã thử nghiệm mã này trên máy chủ Windows 7 RC x64 HP ML-115. Có một số mẫu C++ có sẵn, bạn có thể tải xuống ở dạng thực thi đã biên dịch. Các mẫu mà tôi đang nghĩ đến đặc biệt là diskid32 (http://www.winsim.com/diskid32/diskid32.html) và EnumDisk1 (http://support.microsoft.com/kb/264203). Tôi đề nghị bạn thử chạy các tập tin thực thi trên máy tính 64-bit của bạn. Nếu họ có thể truy xuất số sê-ri, có thể tôi hoặc người khác có thể giúp bạn thực hiện các kỹ thuật tương tự trong mã VB.net của riêng bạn. –

0

Modified từ mã 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(); 
     } 
    } 
} 

Trên hệ thống của tôi chạy Vista Home Premium x64, mang lại cho tôi một chuỗi hex 40 ký tự mà tôi giả sử là số serial của tôi. Tôi sẽ mở hộp và xác nhận sau, nhưng hãy thử và xem đó là những gì bạn đang tìm kiếm.

+0

Tôi đã thử nghiệm trước đó. WMI để nhận số sê-ri HDD có một số vấn đề, bao gồm không hoạt động trên một số phiên bản Windows và lỗi liên tục, do đó sẽ không phải là câu trả lời. – TheAgent

+0

Trên máy tính xách tay của tôi (DELL Latitude E6400 chạy XP), truy cập thuộc tính "SerialNumber" ném ngoại lệ "không tìm thấy". – newman

8

Mã này làm cho ba nỗ lực thu thập số serial:

  1. Sử dụng IOCTL_STORAGE_QUERY_PROPERTY.
  2. Sử dụng SMART_RCV_DRIVE_DATA.
  3. Sử dụng IOCTL_SCSI_PASS_THROUGH.

Mã này làm việc cho tôi trên Windows 64-bit:

' 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 

Và đây là đoạn code để gọi nó là:

' 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 

EDIT - Tôi đã thay đổi phương pháp chính để hiển thị kết quả của mỗi lần so sánh. Điều này hy vọng sẽ minh họa cách nhấn và bỏ lỡ những kỹ thuật này có thể được.

+0

Xin chào! Tôi chuyển đổi mã của bạn thành C# nhưng sử dụng SCSI PassThrough Tôi nhận được một kết quả lạ (số mô hình thay vì số sê-ri). Tôi đăng một câu hỏi ở đây về điều đó và tôi sẽ được plased nếu bạn có thể có một cái nhìn vào nó bởi vì bạn có thể biết những gì đang xảy ra: http://stackoverflow.com/questions/16443215/c-native-reading-hdd-serial- using-scsi-passthrough –

+0

Cuối cùng là một số mã để đọc s/n vật lý của hdd dưới xp. thx – nelek

1

Got làm việc trên 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"] 
     } 

Có lẽ lớp Win32_PhysicalMedia không được phục vụ trên nền tảng 64 bit.

Ngay cả Disk32, tại thời điểm này, đang hoạt động (ngoài lỗi khi lật byte số sê-ri), bởi vì dựa trên cùng một khái niệm.

+0

Tôi vừa thử mã này trên máy tính của mình (XP, sử dụng .NET 4.0) và truy cập obj.Properties ["SerialiNumber"] ném ngoại lệ "không tìm thấy". – newman

+0

Tôi vừa thử mã này trên máy của mình (XP, sử dụng .NET 4.0) và truy cập obj.Properties ["SerialiNumber"] ném ngoại lệ "không tìm thấy". – newman

+0

Trên Windows XP, bạn sẽ truy vấn Win32_PhysicalMedia. Mã này hoạt động trên Windows 7. – Luca

Các vấn đề liên quan