2010-12-30 2 views
0

CodeProject에는 두 개의 기사가 있습니다 (하나는 WMI를 사용하고 다른 하나는 WMI가 아니라 C++을 사용함). WMI 방식을 시도했지만 속도가 느릴뿐만 아니라 신뢰할 수 없습니다. 그래서 나는 그 길을 추구하지 않기로 결정했습니다. 나는 C#에서 pInvoke를 통해 그것을하고 싶다. 나는 그것을 시도했지만 DeviceIoControl API에 붙어있어. 아무도 나에게 힌트를 줄 수 있니? 여기 내 코드는 다음과 같습니다.C#에서 하드 디스크 SerialNumber를 얻는 방법 (WMI 없음)?

using System; 
using System.ComponentModel; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Runtime.InteropServices; 
using Microsoft.Win32.SafeHandles; 

namespace Chemulator.Common 
{ 
    public class HDSerialNumber 
    { 
     [StructLayout(LayoutKind.Sequential)] 
     private struct IDEREGS 
     { 
      public byte bFeaturesReg; 
      public byte bSectorCountReg; 
      public byte bSectorNumberReg; 
      public byte bCylLowReg; 
      public byte bCylHighReg; 
      public byte bDriveHeadReg; 
      public byte bCommandReg; 
      public byte bReserved; 
     } 

     [StructLayout(LayoutKind.Sequential)] 
     private struct SENDCMDINPARAMS 
     { 
      public Int32 cBufferSize; 
      public IDEREGS irDriveRegs; 
      public byte bDriveNumber; 
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] 
      public byte[] bReserved; 
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] 
      public Int32[] dwReserved; 
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] 
      public byte[] bBuffer; 
     } 


     [StructLayout(LayoutKind.Sequential)] 
     private struct DRIVERSTATUS 
     { 
      public byte bDriverError; 
      public byte bIDEError; 
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] 
      public byte[] bReserved; 
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] 
      public Int32[] dwReserved; 
     } 

     [StructLayout(LayoutKind.Sequential)] 
     private struct SENDCMDOUTPARAMS 
     { 
      public Int32 cBufferSize; 
      public DRIVERSTATUS DriverStatus; 
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = IDENTIFY_BUFFER_SIZE)] 
      public byte[] bBuffer; 
     } 

     [StructLayout(LayoutKind.Sequential)] 
     private struct GETVERSIONOUTPARAMS 
     { 
      public byte bVersion; 
      public byte bRevision; 
      public byte bReserved; 
      public byte bIDEDeviceMap; 
      public Int32 fCapabilities; 
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] 
      public Int32 dwReserved; 
     } 

     [StructLayout(LayoutKind.Sequential)] 
     private struct STORAGE_PROPERTY_QUERY 
     { 
      public Int32 PropertyId; 
      public Int32 QueryType; 
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] 
      public byte[] AdditionalParameters; 
     } 

     [StructLayout(LayoutKind.Sequential)] 
     private struct STORAGE_DEVICE_DESCRIPTOR 
     { 
      public Int32 Version; 
      public Int32 Size; 
      public byte DeviceType; 
      public byte DeviceTypeModifier; 
      public byte RemovableMedia; 
      public byte CommandQueueing; 
      public Int32 VendorIdOffset; 
      public Int32 ProductIdOffset; 
      public Int32 ProductRevisionOffset; 
      public Int32 SerialNumberOffset; 
      public byte BusType; 
      public Int32 RawPropertiesLength; 
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10240)] 
      public byte[] RawDeviceProperties; 
     } 

     [DllImport("kernel32.dll", SetLastError = true)] 
     private static extern SafeFileHandle CreateFile(string lpFileName, Int32 dwDesiredAccess, Int32 dwShareMode, IntPtr lpSecurityAttributes, Int32 dwCreationDisposition, Int32 dwFlagsAndAttributes, IntPtr hTemplateFile); 

     [DllImport("kernel32")] 
     private static extern bool DeviceIoControl(SafeFileHandle hDevice, uint dwIoControlCode, IntPtr lpInBuffer, uint nInBufferSize, IntPtr lpOutBuffer, uint nOutBufferSize, ref uint lpBytesReturned, IntPtr lpOverlapped); 


     private const Int32 OPEN_EXISTING = 3; 
     private const Int32 GENERIC_READ = unchecked((int)0x80000000); 
     private const Int32 GENERIC_WRITE = 0x40000000; 
     private const Int32 FILE_SHARE_READ = 0x1; 
     private const Int32 FILE_SHARE_WRITE = 0x2; 
     private const Int32 FILE_SHARE_DELETE = 0x4; 
     private const Int32 SMART_GET_VERSION = 0x74080; 
     private const Int32 SMART_RCV_DRIVE_DATA = 0x7C088; 
     private const Int32 ID_CMD = 0xEC; 
     private const Int32 IDENTIFY_BUFFER_SIZE = 512; 
     private const Int32 CAP_SMART_CMD = 0x4; 
     private const Int32 IOCTL_STORAGE_QUERY_PROPERTY = 0x2D1400; 
     private const Int32 PropertyStandardQuery = 0; 
     private const Int32 StorageDeviceProperty = 0; 

     public static string GetSerialNumber(int diskNumber) 
     { 
      string str = GetSerialNumberUsingStorageQuery(diskNumber); 
      if (string.IsNullOrEmpty(str)) 
       str = GetSerialNumberUsingSmart(diskNumber); 
      return str; 
     } 

     public static string GetSerialNumberUsingStorageQuery(int diskNumber) 
     { 
      using (SafeFileHandle hDisk = OpenDisk(diskNumber)) 
      { 
       uint iBytesReturned = 0; 
       var spq = new STORAGE_PROPERTY_QUERY(); 
       var sdd = new STORAGE_DEVICE_DESCRIPTOR(); 
       spq.PropertyId = StorageDeviceProperty; 
       spq.QueryType = PropertyStandardQuery; 
       if (DeviceIoControl(hDisk, IOCTL_STORAGE_QUERY_PROPERTY, spq, (uint)Marshal.SizeOf(spq), sdd, (uint)Marshal.SizeOf(sdd), ref iBytesReturned, IntPtr.Zero)) 
        throw CreateWin32Exception(Marshal.GetLastWin32Error(), "DeviceIoControl(IOCTL_STORAGE_QUERY_PROPERTY)"); 

       var result = new StringBuilder(); 
       if (sdd.SerialNumberOffset > 0) 
       { 
        var rawDevicePropertiesOffset = Marshal.SizeOf(sdd) - sdd.RawDeviceProperties.Length; 
        int pos = sdd.SerialNumberOffset - rawDevicePropertiesOffset; 
        while (pos < iBytesReturned && sdd.RawDeviceProperties[pos] != 0) 
        { 
         result.Append(Encoding.ASCII.GetString(sdd.RawDeviceProperties, pos, 1)); 
         pos += 1; 
        } 
       } 
       return result.ToString(); 
      } 
     } 

     public static string GetSerialNumberUsingSmart(int diskNumber) 
     { 
      using (SafeFileHandle hDisk = OpenDisk(diskNumber)) 
      { 
       if (IsSmartSupported(hDisk)) 
       { 
        Int32 iBytesReturned = 0; 
        var sci = new SENDCMDINPARAMS(); 
        var sco = new SENDCMDOUTPARAMS(); 
        sci.irDriveRegs.bCommandReg = ID_CMD; 
        sci.bDriveNumber = (byte)diskNumber; 
        sci.cBufferSize = IDENTIFY_BUFFER_SIZE; 
        if (DeviceIoControl(hDisk, SMART_RCV_DRIVE_DATA, sci, (uint)Marshal.SizeOf(sci), sco, (uint)Marshal.SizeOf(sco), ref iBytesReturned, IntPtr.Zero)) 
         throw CreateWin32Exception(Marshal.GetLastWin32Error(), "DeviceIoControl(SMART_RCV_DRIVE_DATA)"); 

        var result = new StringBuilder(); 
        for (int index = 20; index < 39; index += 2) 
        { 
         result.Append(Encoding.ASCII.GetString(sco.bBuffer, index + 1, 1)); 
         result.Append(Encoding.ASCII.GetString(sco.bBuffer, index, 1)); 
        } 
        return result.ToString(); 
       } 
       return string.Empty; 
      } 
     } 

     private static Win32Exception CreateWin32Exception(Int32 errorCode, string context) 
     { 
      var win32Exception = new Win32Exception(errorCode); 
      win32Exception.Data["Context"] = context; 
      return win32Exception; 
     } 

     private static SafeFileHandle OpenDisk(int diskNumber) 
     { 
      SafeFileHandle hDevice = CreateFile(string.Format(@"\\.\PhysicalDrive{0}", diskNumber), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero); 
      if (!hDevice.IsInvalid) 
       return hDevice; 
      else 
       throw CreateWin32Exception(Marshal.GetLastWin32Error(), "CreateFile"); 
     } 

     private static bool IsSmartSupported(SafeFileHandle hDisk) 
     { 
      uint iBytesReturned = 0; 
      var gvo = new GETVERSIONOUTPARAMS(); 
      IntPtr pGVO = Marshal.AllocHGlobal(512); 
      if (DeviceIoControl(hDisk, SMART_GET_VERSION, IntPtr.Zero, 0, pGVO, 512, ref iBytesReturned, IntPtr.Zero)) 
       return false; 
      return (gvo.fCapabilities & CAP_SMART_CMD) > 0; 
     } 
    } 
} 
+3

컴퓨터가 고장 나서 집이 고장 났거나 그게 무슨 문제입니까? –

+0

왜 WMI가 없습니까? 호기심과 마찬가지로 ... – turtlepick

+0

@ Flavio : WMI가 느리고 신뢰할 수 없기 때문입니다. – newman

답변

1

DeviceIOcontrol에 관한 pinvoke.net 튜토리얼을 확인하십시오.

볼 수있는 페이지 아래로 스크롤 VB .NET 3.0 전체 예제 (감사합니다 "bogdandaniel") pPumkiN에 의해 편집 됨. 다른 IO 장치에 액세스하는 완전한 예입니다. 나는 거기 DRIVE_INFO도있다 beleieve.

나는 또한 이것에 어떤 경험도 없다. 직접 사용해보십시오

+0

링크를 제공해 주셔서 감사합니다. 사실, 내 코드는 주로 VB 코드를 기반으로, 나는 너무 많은 서명과 함께 DeviceIoControl의 5 오버로드 된 버전 혼란스러워. – newman

관련 문제