本文介绍了如何获得硬盘的SerialNumber在C#中(不WMI)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道在$ C $的CProject两篇文章(一个使用WMI和其他没有WMI但在C ++)。我试过WMI方式,不仅是缓慢的,但也是不可靠的。所以,这就是为什么我决定放弃这种方式。我想通过的PInvoke做到这一点在C#。我尝试过,但陷入了DeviceIoControl的API。任何人都可以给我一个提示?这里是我的code:

 使用系统;
使用System.ComponentModel;
使用System.Collections.Generic;
使用System.Linq的;
使用System.Text;
使用System.Runtime.InteropServices;
使用Microsoft.Win32.SafeHandles;命名空间Chemulator.Common
{
    公共类HDSerialNumber
    {
        [StructLayout(LayoutKind.Sequential)]
        私人结构IDEREGS
        {
            公共字节bFeaturesReg;
            公共字节bSectorCountReg;
            公共字节bSectorNumberReg;
            公共字节bCylLowReg;
            公共字节bCylHighReg;
            公共字节bDriveHeadReg;
            公共字节bCommandReg;
            公共字节bReserved;
        }        [StructLayout(LayoutKind.Sequential)]
        私人结构SENDCMDINPARAMS
        {
            公众的Int32 cBufferSize;
            公共IDEREGS irDriveRegs;
            公共字节bDriveNumber;
            [的MarshalAs(UnmanagedType.ByValArray,SizeConst = 3)]
            公众的byte [] bReserved;
            [的MarshalAs(UnmanagedType.ByValArray,SizeConst = 4)]
            公众的Int32 [] dwReserved;
            [的MarshalAs(UnmanagedType.ByValArray,SizeConst = 1)]
            公众的byte [] bBuffer;
        }
        [StructLayout(LayoutKind.Sequential)]
        私人结构DRIVERSTATUS
        {
            公共字节bDriverError;
            公共字节bIDEError;
            [的MarshalAs(UnmanagedType.ByValArray,SizeConst = 2)]
            公众的byte [] bReserved;
            [的MarshalAs(UnmanagedType.ByValArray,SizeConst = 2)]
            公众的Int32 [] dwReserved;
        }        [StructLayout(LayoutKind.Sequential)]
        私人结构SENDCMDOUTPARAMS
        {
            公众的Int32 cBufferSize;
            公共DRIVERSTATUS DriverStatus;
            [的MarshalAs(UnmanagedType.ByValArray,SizeConst = IDENTIFY_BUFFER_SIZE)
            公众的byte [] bBuffer;
        }        [StructLayout(LayoutKind.Sequential)]
        私人结构GETVERSIONOUTPARAMS
        {
            公共字节bVersion;
            公共字节bRevision;
            公共字节bReserved;
            公共字节bIDEDeviceMap;
            公众的Int32 fCapabilities;
            [的MarshalAs(UnmanagedType.ByValArray,SizeConst = 4)]
            公众的Int32 dwReserved;
        }        [StructLayout(LayoutKind.Sequential)]
        私人结构STORAG​​E_PROPERTY_QUERY
        {
            公众的Int32属性ID;
            公众的Int32查询类型;
            [的MarshalAs(UnmanagedType.ByValArray,SizeConst = 1)]
            公众的byte [] AdditionalParameters;
        }        [StructLayout(LayoutKind.Sequential)]
        私人结构STORAG​​E_DEVICE_DESCRIPTOR
        {
            公众的Int32版本;
            公众的Int32大小;
            公共字节的devicetype;
            公共字节DeviceTypeModifier;
            公共字节RemovableMedia;
            公共字节CommandQueueing;
            公众的Int32 VendorIdOffset;
            公众的Int32 ProductIdOffset;
            公众的Int32 ProductRevisionOffset;
            公众的Int32 SerialNumberOffset;
            公共字节BusType;
            公众的Int32 RawPropertiesLength;
            [的MarshalAs(UnmanagedType.ByValArray,SizeConst = 10240)
            公众的byte [] RawDeviceProperties;
        }        函数[DllImport(KERNEL32.DLL,SetLastError = TRUE)]
        私人静态外部SafeFileHandle的CreateFile(字符串lpFileName的对象,的Int32 dwDesiredAccess,的Int32 dwShareMode,IntPtr的lpSecurityAttributes,的Int32 CREATE_NEW标志,的Int32 dwFlagsAndAttributes,IntPtr的hTemplateFile);        函数[DllImport(KERNEL32)]
        私人静态的extern BOOL DeviceIoControl的(SafeFileHandle hDevice,UINT dwIoControl code,IntPtr的lpInBuffer,UINT nInBufferSize,IntPtr的lpOutBuffer,UINT nOutBufferSize,裁判UINT lpBytesReturned,IntPtr的lpOverlapped的);
        私人常量的Int32 OPEN_EXISTING = 3;
        私人常量的Int32 GENERIC_READ =选中((INT)为0x80000000);
        私人常量的Int32 GENERIC_WRITE = 0x40000000之后;
        私人常量的Int32 FILE_SHARE_READ =为0x1;
        私人常量的Int32 FILE_SHARE_WRITE = 0X2;
        私人常量的Int32 FILE_SHARE_DELETE =为0x4;
        私人常量的Int32 SMART_GET_VERSION = 0x74080;
        私人常量的Int32 SMART_RCV_DRIVE_DATA = 0x7C088;
        私人常量的Int32 ID_CMD = 0xEC;
        私人常量的Int32 IDENTIFY_BUFFER_SIZE = 512;
        私人常量的Int32 CAP_SMART_CMD =为0x4;
        私人常量的Int32 IOCTL_STORAG​​E_QUERY_PROPERTY = 0x2D1400;
        私人常量的Int32 PropertyStandardQuery = 0;
        私人常量的Int32 StorageDeviceProperty会= 0;        公共静态字符串GetSerialNumber(INT diskNumber)
        {
            字符串str = GetSerialNumberUsingStorageQuery(diskNumber);
            如果(string.IsNullOrEmpty(STR))
               海峡= GetSerialNumberUsingSmart(diskNumber);
            返回海峡;
        }        公共静态字符串GetSerialNumberUsingStorageQuery(INT diskNumber)
        {
            使用(SafeFileHandle HDISK = OpenDisk(diskNumber))
            {
                UINT iBytesReturned = 0;
                VAR SPQ =新STORAG​​E_PROPERTY_QUERY();
                VAR SDD =新STORAG​​E_DEVICE_DESCRIPTOR();
                spq.PropertyId = StorageDeviceProperty会;
                spq.QueryType = PropertyStandardQuery;
                如果(DeviceIoControl的(HDISK,IOCTL_STORAG​​E_QUERY_PROPERTY,SPQ,(UINT)Marshal.SizeOf(SPQ),SDD(UINT)Marshal.SizeOf(SDD),REF iBytesReturned,IntPtr.Zero))
                    扔CreateWin32Exception(Marshal.GetLastWin32Error(),的DeviceIoControl(IOCTL_STORAG​​E_QUERY_PROPERTY));                VAR的结果=新的StringBuilder();
                如果(sdd.SerialNumberOffset大于0)
                {
                    变种rawDevicePropertiesOffset = Marshal.SizeOf(SDD) - sdd.RawDeviceProperties.Length;
                    INT POS = sdd.SerialNumberOffset - rawDevicePropertiesOffset;
                    而(POS&L​​T; iBytesReturned&放大器;&安培;!sdd.RawDeviceProperties [POS] = 0)
                    {
                        result.Append(Encoding.ASCII.GetString(sdd.RawDeviceProperties,POS,1));
                        POS + = 1;
                    }
                }
                返回result.ToString();
            }
        }        公共静态字符串GetSerialNumberUsingSmart(INT diskNumber)
        {
            使用(SafeFileHandle HDISK = OpenDisk(diskNumber))
            {
                如果(IsSmartSupported(HDISK))
                {
                    INT32 iBytesReturned = 0;
                    VAR SCI =新SENDCMDINPARAMS();
                    VAR SCO =新SENDCMDOUTPARAMS();
                    sci.irDriveRegs.bCommandReg = ID_CMD;
                    sci.bDriveNumber =(字节)diskNumber;
                    sci.cBufferSize = IDENTIFY_BUFFER_SIZE;
                    如果(DeviceIoControl的(HDISK,SMART_RCV_DRIVE_DATA,SCI(UINT)Marshal.SizeOf(SCI),SCO(UINT)Marshal.SizeOf(SCO),REF iBytesReturned,IntPtr.Zero))
                        扔CreateWin32Exception(Marshal.GetLastWin32Error(),的DeviceIoControl(SMART_RCV_DRIVE_DATA));                    VAR的结果=新的StringBuilder();
                    对于(INT指数= 20;指数< 39;指数+ = 2)
                    {
                        result.Append(Encoding.ASCII.GetString(sco.bBuffer,索引+ 1,1));
                        result.Append(Encoding.ASCII.GetString(sco.bBuffer,指数,1));
                    }
                    返回result.ToString();
                }
                返回的String.Empty;
            }
        }        私有静态Win32Exception CreateWin32Exception(的Int32错误code,字符串上下文中)
        {
            VAR win32Exception =新Win32Exception(错误code);
            win32Exception.Data [上下文] =背景;
            返回win32Exception;
        }        私有静态SafeFileHandle OpenDisk(IN​​T 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);
            如果(!hDevice.IsInvalid)
                返回hDevice;
            其他
                扔CreateWin32Exception(Marshal.GetLastWin32Error(),的CreateFile);
        }        私人静态布尔IsSmartSupported(SafeFileHandle HDISK)
        {
            UINT iBytesReturned = 0;
            VAR GVO =新GETVERSIONOUTPARAMS();
            IntPtr的pGVO = Marshal.AllocHGlobal(512);
            如果(DeviceIoControl的(HDISK,SMART_GET_VERSION,IntPtr.Zero,0,pGVO,512,参考iBytesReturned,IntPtr.Zero))
                返回false;
            回报(gvo.fCapabilities&安培; CAP_SMART_CMD)GT; 0;
        }
    }
}


解决方案

退房有关的。

向下滚动页面,在这里你可以看到的 VB .NET 3.0完整的例子(感谢bogdandaniel)的编辑pPumkiN 。这是访问不同影响IO设备的完整的例子。我beleieve有DRIVE_INFO了。

另外我没有任何这方面的经验。自己尝试一下。

I know there are two articles in CodeProject (one uses WMI and the other no WMI but in C++). I tried the WMI way, not only it's slow, but it is also unreliable. So, that's why I decided not to pursue that way. I want to do it in C# through pInvoke. I tried it but got stuck in DeviceIoControl API. Can anybody give me a hint? Here is my code:

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;
        }
    }
}
解决方案

Check out the pinvoke.net tutorial about DeviceIOcontrol.

Scroll down the page where you can see VB .NET 3.0 Full Example (Thanks to "bogdandaniel") Edited by pPumkiN. It is a complete example of accessing diffferent IO devices. I beleieve there is DRIVE_INFO too.

Also i dont have any experience with this. Try it yourself

这篇关于如何获得硬盘的SerialNumber在C#中(不WMI)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-28 19:50