Получите жесткий диск (и НЕ Объем) Порядковый номер на Vista Окончательные 64 бита

Поместите блок try catch вокруг теста.

[TestMethod]
  public void TestMethod1()
  {
     try
     {
         Class1 class1 = new Class1();
         class1 = null;
         // force Garbage Collection for finalizer to run
         GC.Collect();
     }

     catch(Win32Exception w) 
     {
         Console.WriteLine(w.Message);
         Console.WriteLine(w.ErrorCode.ToString());
         Console.WriteLine(w.NativeErrorCode.ToString());
         Console.WriteLine(w.StackTrace);
         Console.WriteLine(w.Source);
         Exception e=w.GetBaseException();
         Console.WriteLine(e.Message);
     }
  }

Это даст вам точное сообщение об ошибке.


Это может быть что-то столь же простое, как не заданный путь Если это так. Возвращенная ошибка будет file not found. В этом случае это можно решить, изменив "cmd.exe" на @"C:\windows\system32\cmd.exe"

10
задан Community 23 May 2017 в 11:54
поделиться

7 ответов

Этот код должен содержать серийный номер жесткого диска. Он похож ( ReadPhysicalDriveInNTWithAdminRights ) на ваш код, на который вы ссылаетесь, но с несколькими дополнительными функциями.

2
ответ дан 3 December 2019 в 22:39
поделиться

Вы должны убедиться, что ваши определения P / Invoke являются 64-битными. В качестве альтернативы попробуйте установить целевой процессор проектов в вашем решении на 32-разрядный. Более подробную информацию о P / Invoke и 64-битном можно найти здесь здесь .

РЕДАКТИРОВАТЬ:

Следующий переписанный код может работать лучше для вас - в основном я привел в порядок определения 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-битная машина для проверки, но это код действительно работает над ним.

2
ответ дан 3 December 2019 в 22:39
поделиться

Возможно, вы захотите использовать неуправляемый API Windows для этого:

вызвать API-интерфейс GetVolumeInformation с правильной структурой и найти целочисленное поле VolumeSerialNumber.

Этот API есть целую вечность и работал у меня начиная с Windows 98. К сожалению, не могу проверить это на x64.

Можете ли вы увидеть правильный серийный номер, используя другие инструменты Windows? Кстати, «0» является действительным серийным номером! Это может произойти, если образ диска был восстановлен из резервной копии или что-то в этом роде.

-1
ответ дан 3 December 2019 в 22:39
поделиться

Modified from the code 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();
        }
    }
}

On my system running Vista Home Premium x64, gives me a 40-character hex string that I'm assuming is my serial number. I'll open up the box and confirm later, but give that a try and see if it's what you're looking for.

0
ответ дан 3 December 2019 в 22:39
поделиться

Этот код делает три попытки получения серийного номера:

  1. Использование IOCTL_STORAGE_QUERY_PROPERTY .
  2. Использование SMART_RCV_DRIVE_DATA .
  3. ] Использование 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

EDIT - Я изменил основной метод на отображать результаты каждой попытки для сравнения. Надеюсь, это продемонстрирует, насколько удачными могут быть эти техники.

8
ответ дан 3 December 2019 в 22:39
поделиться

используйте DeviceIoControl с IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER

или проверьте IOCTL_CHANGER_GET_PRODUCT_DATA

3
ответ дан 3 December 2019 в 22:39
поделиться

Начал работать с 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"]
        }

Вероятно, класс Win32_PhysicalMedia не обслуживается на 64-битных платформах.

Даже Disk32 в настоящее время работает (кроме ошибки при переворачивании байтов серийного номера), потому что основан на тех же концепциях.

1
ответ дан 3 December 2019 в 22:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: