如何在 .NET 中不使用 WMI 找到硬盘设备序列号?

Posted

技术标签:

【中文标题】如何在 .NET 中不使用 WMI 找到硬盘设备序列号?【英文标题】:How can I find the Harddisk Device Serial Number without using the WMI in .NET? 【发布时间】:2010-11-13 16:42:12 【问题描述】:

我想从硬盘获取硬连线序列号,但不使用 WMI。我尝试使用 WMI 代码,但它肯定不能在我的机器上运行。那么 .NET 中是否有其他方法可以查找物理硬盘的序列号?

【问题讨论】:

打开盒子看看? 这个问题经常被问到...... 没有这个是有区别的............他需要硬盘驱动器的序列号而不是硬盘驱动器的每个卷的序列号 我也在寻找答案,因为我面临同样的问题...... 【参考方案1】:

这应该有助于开始:

How to get Physical HDD serial number without WMI

关于 WMI 不返回数据的问题;您确定如何获得从 WMI 获取数据的正确权限吗?您可以使用WMI Tools 来检查/修复此问题。

【讨论】:

我在受限账户模式下运行代码。所以我想这就是问题所在。有什么方法可以在受限帐户中提升我的权限? 我不这么认为。这不会错过为用户分配权限的全部意义吗?或者如果你知道管理员密码,你可以使用“runas”命令。【参考方案2】:

使用createfile,如下所示。它可能需要管理权限。在您的代码中添加 4 个文本框和一个按钮。

 private const int CREATE_NEW = 1;
    private const int OPEN_EXISTING = 3;
    private const uint GENERIC_READ = 0x80000000; 
    private const uint GENERIC_WRITE = 0x40000000;
    // 10000000000000000000000000000000 --- GENERIC_READ
    // 01000000000000000000000000000000 --- GENERIC_WRITE
    // 00100000000000000000000000000000 --- GENERIC_EXECUTE
    // 00010000000000000000000000000000 --- GENERIC_ALL       

    //Securable objects use an access mask format in which the 
    //four high-order bits specify generic access rights


    private const int FILE_SHARE_READ = 0x1;      
    private const int FILE_SHARE_WRITE = 0x2;
    // 00000000000000000000000000000001 --- FILE_SHARE_READ
    // 00000000000000000000000000000010 --- FILE_SHARE_WRITE
    // 00000000000000000000000000000100 --- FILE_SHARE_DELETE 

    private const int VER_PLATFORM_WIN32_NT = 2;
    private const int DFP_RECEIVE_DRIVE_DATA = 0x7C088;
    //     0         000000000000111         11                  0               00000100010         00
    //     Common    Device Type             Required Access     Custom          Function Code       Transfer Type

    private const int INVALID_HANDLE_VALUE = -1;

    public enum DriveTypes  Fixed, Removable, Unknown ;
    public string[] DriveStrings =  "Fixed", "Removable", "Unknown" ;

    [StructLayout(LayoutKind.Sequential, Size = 8)]
    private class IDEREGS
    
        public byte Features;
        public byte SectorCount;
        public byte SectorNumber;
        public byte CylinderLow;
        public byte CylinderHigh;
        public byte DriveHead;
        public byte Command;
        public byte Reserved;
    

    [StructLayout(LayoutKind.Sequential, Size = 32)]
    private class SENDCMDINPARAMS
    
        public int BufferSize;
        public IDEREGS DriveRegs;
        public byte DriveNumber;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
        public byte[] Reserved;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
        public int[] Reserved2;
        public SENDCMDINPARAMS()
        
            DriveRegs = new IDEREGS();
            Reserved = new byte[3];
            Reserved2 = new int[4];
        
    
    [StructLayout(LayoutKind.Sequential, Size = 12)]
    private class DRIVERSTATUS
    
        public byte DriveError;
        public byte IDEStatus;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
        public byte[] Reserved;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
        public int[] Reserved2;
        public DRIVERSTATUS()
        
            Reserved = new byte[2];
            Reserved2 = new int[2];
        
    

    [StructLayout(LayoutKind.Sequential)]
    private class IDSECTOR
    
        public short GenConfig;
        public short NumberCylinders;
        public short Reserved;
        public short NumberHeads;
        public short BytesPerTrack;
        public short BytesPerSector;
        public short SectorsPerTrack;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
        public short[] VendorUnique;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
        public char[] SerialNumber;
        public short BufferClass;
        public short BufferSize;
        public short ECCSize;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
        public char[] FirmwareRevision;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
        public char[] ModelNumber;
        public short MoreVendorUnique;
        public short DoubleWordIO;
        public short Capabilities;
        public short Reserved1;
        public short PIOTiming;
        public short DMATiming;
        public short BS;
        public short NumberCurrentCyls;
        public short NumberCurrentHeads;
        public short NumberCurrentSectorsPerTrack;
        public int CurrentSectorCapacity;
        public short MultipleSectorCapacity;
        public short MultipleSectorStuff;
        public int TotalAddressableSectors;
        public short SingleWordDMA;
        public short MultiWordDMA;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 382)]
        public byte[] Reserved2;
        public IDSECTOR()
        
            VendorUnique = new short[3];
            Reserved2 = new byte[382];
            FirmwareRevision = new char[8];
            SerialNumber = new char[20];
            ModelNumber = new char[40];
        
    

    [StructLayout(LayoutKind.Sequential)]
    private class SENDCMDOUTPARAMS
    
        public int BufferSize;
        public DRIVERSTATUS Status;
        public IDSECTOR IDS;
        public SENDCMDOUTPARAMS()
        
            Status = new DRIVERSTATUS();
            IDS = new IDSECTOR();
        
    

    [System.Runtime.InteropServices.DllImport("kernel32.dll")]
    private static extern int CloseHandle(int hObject);

    [System.Runtime.InteropServices.DllImport("kernel32.dll")]
    private static extern int CreateFile(
                string lpFileName,
                uint dwDesiredAccess,
                int dwShareMode,
                int lpSecurityAttributes,
                int dwCreationDisposition,
                int dwFlagsAndAttributes,
                int hTemplateFile
            );

    [System.Runtime.InteropServices.DllImport("kernel32.dll")]
    private static extern int DeviceIoControl(
            int hDevice,
            int dwIoControlCode,
            [In(), Out()] SENDCMDINPARAMS lpInBuffer,
            int lpInBufferSize,
            [In(), Out()] SENDCMDOUTPARAMS lpOutBuffer,
            int lpOutBufferSize,
            ref int lpBytesReturned,
            int lpOverlapped
        );

    private string SwapChars(char[] chars)
    
        for (int i = 0; i <= chars.Length - 2; i += 2)
        
            char t;
            t = chars[i];
            chars[i] = chars[i + 1];
            chars[i + 1] = t;
        
        string s = new string(chars);
        return s;
    


     private void button1_Click(object sender, System.EventArgs e)
    

        string serialNumber = " ", model = " ", firmware = " ";
        bool result;
        DriveTypes driveType = DriveTypes.Unknown;
        int handle, returnSize = 0;
        int driveNumber = 0;
        SENDCMDINPARAMS sci = new SENDCMDINPARAMS();
        SENDCMDOUTPARAMS sco = new SENDCMDOUTPARAMS();

        if (Environment.OSVersion.Platform == PlatformID.Win32NT)
            //               \\.\PhysicalDrive0    Opens the first physical drive.
            //               \\.\PhysicalDrive2    Opens the third physical drive.
            // see more info on http://msdn.microsoft.com/en-us/library/aa365247%28VS.85%29.aspx
            handle = CreateFile("\\\\.\\PhysicalDrive" + "0", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
        else // for win'9x
            handle = CreateFile("\\\\.\\Smartvsd", 0, 0, 0, CREATE_NEW, 0, 0);
        if (handle != INVALID_HANDLE_VALUE)
        
            sci.DriveNumber = (byte)driveNumber;
            sci.BufferSize = Marshal.SizeOf(sco);
            sci.DriveRegs.DriveHead = (byte)(0xA0 | driveNumber << 4);
            sci.DriveRegs.Command = 0xEC;
            sci.DriveRegs.SectorCount = 1;
            sci.DriveRegs.SectorNumber = 1;
            if (DeviceIoControl(handle, DFP_RECEIVE_DRIVE_DATA, sci, Marshal.SizeOf(sci), sco, Marshal.SizeOf(sco), ref returnSize, 0) != 0)
            
                serialNumber = SwapChars(sco.IDS.SerialNumber);
                model = SwapChars(sco.IDS.ModelNumber);
                firmware = SwapChars(sco.IDS.FirmwareRevision);
            

            textBox1.Text = serialNumber;
            textBox2.Text = model;
            textBox3.Text = firmware;
            if ((sco.IDS.GenConfig & 0x80) == 0x40)
                driveType = DriveTypes.Removable;
            else if ((sco.IDS.GenConfig & 0x40) == 0x40)
                driveType = DriveTypes.Fixed;
            else
                driveType = DriveTypes.Unknown;
            CloseHandle(handle);
            textBox4.Text = DriveStrings[(int)driveType];
        
    

【讨论】:

【参考方案3】:

可以在这里找到完美的解决方案:

http://www.codeproject.com/Articles/16941/Get-Physical-HDD-Serial-Number-without-WMI

[编辑] 抱歉,错过了已提交对此的引用。

【讨论】:

【参考方案4】:

您可以使用:

GetVolumeInformation

Win32 API 函数获取此信息,如果您必须避免 WMI。链接页面提供了 API 函数的完整声明签名(VB 和 C#)以及示例代码。

【讨论】:

不是返回 Volume 序列号吗?我想要不随格式改变的设备序列号 @Xinxua - 对不起,你是对的。它返回卷而不是设备序列号。我认为在不使用 WMI 的情况下实现此目的的唯一方法是调用由 C++/非托管代码调用的低级操作系统函数(根据其他 Espo 的答案),但是,如果您使用有限的 Windows 帐户权限和 WMI 运行失败(可能是因为这个)然后我怀疑从.NET应用程序调用C++ dll的函数是否会起作用,除非您可以以更高的权限运行/执行代码,并且需要相关的访问权限/密码才能这样做。 【参考方案5】:

你最好的选择是 windows api,

我做了一个简单的搜索,得到了这个

General processor info 和read this post

【讨论】:

【参考方案6】:

我在我的项目中使用硬盘固件轨道。我在 mdi 表单后面进行编程以查找硬盘固件编号,然后在公司计算机的所有提供的硬盘数量上循环,如果它与这些提供的硬盘固件编号中的任何一个匹配,然后运行应用程序并加载 mdi 表单以其他方式提供message "该应用程序未在此机器上注册,请致电 Afridi 先生在 00923339176357 上注册此应用程序。我的电子邮件地址是 munawar_s_afridi@yahoo.com。我将发送获取如何编程专业硬盘固件编号以及如何编程的完整源代码阻止他人非法使用您的应用。

你应该一次指定所有公司计算机的硬盘固件,让应用程序首先选择硬盘固件编号,将它存储在一个变量中,然后选择这个变量的值(一个字符串值)并循环它使用 OR 逻辑运算符与每个硬盘编号一一对应。如果在具有可变值的公司硬盘编号中找到匹配的编号,则应用应加载主表单(mdi),否则通知用户进行注册。

示例代码将使用 vb6 提供。只需了解如何将非托管代码调用到托管 .net 应用程序中,您就可以稍后在 vb.net 中轻松编程。在这种情况下是一个 .dll。

【讨论】:

以上是关于如何在 .NET 中不使用 WMI 找到硬盘设备序列号?的主要内容,如果未能解决你的问题,请参考以下文章

windows wmi

WMI:在插入时获取 USB 设备描述

如何在 C#(无 WMI)中获取硬盘序列号?

c# 获取移动硬盘信息监听移动设备的弹出与插入事件

c# WMI获取机器硬件信息(硬盘,cpu,内存等)

检测硬盘是通过 USB 还是通过其他没有 WMI 的方式连接的