如何获取硬盘序列号?

时间:2013-12-22 22:22:02

标签: c# wmi

目前我使用以下代码获取硬盘的序列号:

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; }
}

此代码工作正常。

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

那么,如何获取运行我的软件的硬盘序列号?

1 个答案:

答案 0 :(得分:6)

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

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


我进一步研究了你的问题。使用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
{
    GenericReadWrite = 0x80000000 | 0x40000000 // GENERIC_READ | GENERIC_WRITE
}

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.GenericReadWrite, 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();
}