【问题标题】:How to get the Hard Drive Serial number? [duplicate]如何获取硬盘序列号? [复制]
【发布时间】:2014-01-11 03:34:51
【问题描述】:

目前我正在使用下面的代码来获取硬盘的序列号:

private void GetAllDiskDrives()
{
    var searcher = new ManagementObjectSearcher("SELECT * FROM Win32_DiskDrive");

    foreach (ManagementObject wmi_HD in searcher.Get())
    {
        HardDrive hd = new HardDrive();
        hd.Model = wmi_HD["Model"].ToString();
        hd.InterfaceType = wmi_HD["InterfaceType"].ToString();
        hd.SerialNo = wmi_HD.GetPropertyValue("SerialNumber").ToString();//get the serailNumber of diskdrive
        HdCollection.Add(hd);
    }
}

public class HardDrive
{
    public string Model { get; set; }
    public string InterfaceType { get; set; }
    public string SerialNo { get; set; }
}

这段代码运行良好。

但是上面的代码返回了所有的驱动器。我只想拥有运行我的软件的特定硬盘驱动器(非分区)序列号。

那么,我如何才能获得运行我的软件的硬盘驱动器的序列号?

【问题讨论】:

  • 嗯。听起来像是另一种重新发明许可轮的尝试。那么,您的客户不能更换磁盘驱动器吗?
  • @JohnSaunders 你是对的。
  • @Khushi:有些人会称之为用户不友好
  • 用户更愿意从允许他们更改硬件的人那里购买软件。
  • 而不是HDD序列,考虑CPU ID不太可能改变。更好的是,创建系统签名:BIOS Ver、CPU ID、VIDEO Make/Model 和 Windows Serial。然后,只要 2 of 3 或 3 of 5 与原始匹配,就认为它是有效的。这样用户就可以在没有“问题”的情况下更改内容。

标签: c# wmi


【解决方案1】:

使用SELECT * FROM Win32_PhysicalMedia 查找所有物理驱动器。

要找到加载程序的物理驱动器,您必须从System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase 提取驱动器号,然后使用SELECT * FROM Win32_DiskDrive 加载所有分区,然后以某种方式将所需分区映射到来自@987654324 的物理驱动器之一@。


我进一步调查了您的问题。仅使用 WMI 来关联分区和物理驱动器似乎是不可能的。但是直接使用 WinAPI 是小菜一碟:

[DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern Boolean GetVolumeNameForVolumeMountPoint(String mountPoint, StringBuilder name, UInt32 bufferLength);

private enum FileAccess : uint
{
    None = 0
}

private enum FileShare : uint
{
    ReadWriteDelete = 0x00000001 | 0x00000002 | 0x00000004 // FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE
}

private enum FileCreation : uint
{
    OpenExisting = 3 // OPEN_EXISTING
}

private enum FileFlags : uint
{
    None = 0
}

[DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CreateFile(String fileName, FileAccess access, FileShare share, IntPtr secAttr,
    FileCreation creation, FileFlags flags, IntPtr templateFile);

[DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern Boolean CloseHandle(IntPtr handle);

private enum IoControlCode
{
    GetVolumeDiskExtents = 0x00560000 // IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS
}

[StructLayout(LayoutKind.Explicit)]
private struct VolumeDiskExtents
{
    [FieldOffset(0)]
    public UInt32 numberOfDiskExtents;
    [FieldOffset(8)]
    public UInt32 diskNumber;
    [FieldOffset(16)]
    public Int64 startingOffset;
    [FieldOffset(24)]
    public Int64 extentLength;
}

[DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern Boolean DeviceIoControl(IntPtr device, IoControlCode controlCode, IntPtr inBuffer, UInt32 inBufferSize,
    ref VolumeDiskExtents extents, UInt32 outBufferSize, ref UInt32 bytesReturned, IntPtr overlapped);

public class PhysicalDisk
{
    public PhysicalDisk(String physicalName, String model, String interfaceType, String serialNumber)
    {
        this.PhysicalName = physicalName;
        this.Model = model;
        this.InterfaceType = interfaceType;
        this.SerialNumber = serialNumber;
    }
    public String PhysicalName { get; private set; }
    public String Model { get; private set; }
    public String InterfaceType { get; private set; }
    public String SerialNumber { get; private set; }
}

public PhysicalDisk GetPhysicalDiskFromCurrentDrive()
{
    //
    // Get the drive letter of the drive the executable was loaded from.
    //
    var basePath = System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase.Replace("file:///", "");
    var driveLetter = System.IO.Path.GetPathRoot(basePath);
    // TODO: Validate driveLetter; could also be a UNC path.

    //
    // Get the volume name of the drive letter.
    //
    var volumeNameBuffer = new StringBuilder(65536);
    if (!GetVolumeNameForVolumeMountPoint(driveLetter, volumeNameBuffer, (UInt32)volumeNameBuffer.Capacity))
        throw new Win32Exception();
    var volumeName = volumeNameBuffer.ToString().TrimEnd('\\'); // Remove trailing backslash

    //
    // Open the volume and retrieve the disk number.
    //
    UInt32 diskNumber;
    IntPtr volume = IntPtr.Zero;
    try
    {
        volume = CreateFile(volumeName, FileAccess.None, FileShare.ReadWriteDelete, IntPtr.Zero,
            FileCreation.OpenExisting, FileFlags.None, IntPtr.Zero);
        if (volume == (IntPtr)(-1)) // INVALID_HANDLE_VALUE
        {
            volume = IntPtr.Zero;
            throw new Win32Exception();
        }

        VolumeDiskExtents extents = new VolumeDiskExtents();
        UInt32 bytesReturned = 0;
        if (!DeviceIoControl(volume, IoControlCode.GetVolumeDiskExtents, IntPtr.Zero, 0,
            ref extents, (UInt32)Marshal.SizeOf(extents), ref bytesReturned, IntPtr.Zero))
        {
            // Partitions can span more than one disk, we will ignore this case for now.
            // See http://msdn.microsoft.com/en-us/library/windows/desktop/aa365727(v=vs.85).aspx
            if (Marshal.GetLastWin32Error() != 234 /*ERROR_MORE_DATA*/)
                throw new Win32Exception();
        }

        diskNumber = extents.diskNumber;
    }
    finally
    {
        if (volume != IntPtr.Zero)
        {
            CloseHandle(volume);
            volume = IntPtr.Zero;
        }
    }

    //
    // Build the physical disk name from the disk number.
    //
    String physicalName = ("\\\\.\\PHYSICALDRIVE" + diskNumber).Replace("\\", "\\\\");

    //
    // Find information about the physical disk using WMI.
    //
    var searcher = new ManagementObjectSearcher("SELECT * FROM Win32_DiskDrive WHERE DeviceID = \"" + physicalName + "\"");
    foreach (ManagementObject obj in searcher.Get())
    {
        return new PhysicalDisk(
            obj["DeviceID"].ToString(),
            obj["Model"].ToString(),
            obj["InterfaceType"].ToString(),
            obj["SerialNumber"].ToString()
            );
    }

    throw new InvalidOperationException();
}

【讨论】:

  • 必须使用 0 文件访问权限调用 CreateFile 才能成功。否则会失败并拒绝访问。
  • 很可能我在多年前测试过的应用程序以管理员权限运行,因此卷本身的GENERIC_READ | GENERIC_WRITE 工作。 DeviceIoControl 呼叫在没有任何访问权限的情况下仍然有效? - 考虑一下,访问掩码没有多大意义,因为只查询范围。我改了。
  • 是的,它有效。至少用于获取卷磁盘范围。
猜你喜欢
  • 1970-01-01
  • 2011-05-04
  • 2010-12-06
  • 2011-05-10
  • 2010-11-24
  • 2011-01-02
  • 2014-12-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多