【问题标题】:Getting RPM from HDD and if disk is SSD or not in vb.net从 HDD 获取 RPM 以及磁盘是否为 SSD 在 vb.net
【发布时间】:2014-02-20 23:26:48
【问题描述】:

正如标题所说,我正在 vb.net 中工作,并试图在文本框中获取硬盘的 RPM。 接下来我想弄清楚我的磁盘是 HDD 还是 SSD。

我已经在网上搜索了整整一周的时间,我能想到的都是温度读数:

Const TEMPERATURE_ATTRIBUTE As Byte = 115
Public Function GetDriveTemp() As String
    Dim retval As String = "Temp: "
    Try
        Dim searcher As New ManagementObjectSearcher("root\WMI", "SELECT * FROM MSStorageDriver_ATAPISmartData")
        'loop through all the hard disks
        For Each queryObj As ManagementObject In searcher.[Get]()
            Dim arrVendorSpecific As Byte() = DirectCast(queryObj.GetPropertyValue("VendorSpecific"), Byte())
            'Find the temperature attribute
            Dim tempIndex As Integer = Array.IndexOf(arrVendorSpecific, TEMPERATURE_ATTRIBUTE)
            retval = (arrVendorSpecific(tempIndex + 5))
        Next
    Catch err As ManagementException
        Console.WriteLine("An error occurred while querying for WMI data: " + err.Message)
    End Try
    Return retval
End Function

我知道 Byte 115 是 hdd temp,但我不知道所有其他 Bytes 代表什么。 有人知道吗?

我需要知道如何搜索普通 HDD 没有的 SSD 特定值。 我知道有,但我似乎找不到任何东西。

接下来我需要找出硬盘的 RPM(不是 ssd)

【问题讨论】:

    标签: vb.net wmi-query


    【解决方案1】:

    现在似乎有更好的方法(C#):

    using (var partitionSearcher = new ManagementObjectSearcher(
        @"\\localhost\ROOT\Microsoft\Windows\Storage",
        $"SELECT DiskNumber FROM MSFT_Partition WHERE DriveLetter='{upperCaseDiskLetter}'"))
    {
        var partition = partitionSearcher.Get().Cast<ManagementBaseObject>().Single();
    
        using (var physicalDiskSearcher = new ManagementObjectSearcher(
                    @"\\localhost\ROOT\Microsoft\Windows\Storage",
                    $"SELECT Size, Model, MediaType FROM MSFT_PhysicalDisk WHERE DeviceID='{ partition["DiskNumber"] }'"))
        {
            var physicalDisk = physicalDiskSearcher.Get().Cast<ManagementBaseObject>().Single();
            var isSsd =
                (UInt16)physicalDisk["MediaType"] == 4 ||
                SSDModelSubstrings.Any(substring => result.Model.ToLower().Contains(substring)); ;
    
        }
    }
    

    基于相同的底层类型,但在 PowerShell 中稍微简单一些:

    $is_disk_C_SSD = (Get-PhysicalDisk | ?{$_.DeviceId -eq (Get-Partition -DriveLetter 'C')[0].DiskNumber})[0].MediaType -eq 'SSD'
    

    【讨论】:

    • 小心 - 似乎 MSFT_Partition.Driveletter 有时没有填充...
    • 就像查询 VHD 驱动器一样。
    【解决方案2】:

    解决了。

    如果有人需要知道

    使用 Visual Studio 创建一个包含以下代码的 dll:

    using Microsoft.Win32.SafeHandles;
    using System;
    using System.Runtime.InteropServices;
    using System.Text;
    
    namespace DetectSsd
    {
        public class Program
        {
            // For CreateFile to get handle to drive
            public const uint GENERIC_READ = 0x80000000;
            public const uint GENERIC_WRITE = 0x40000000;
            public const uint FILE_SHARE_READ = 0x00000001;
            public const uint FILE_SHARE_WRITE = 0x00000002;
            public const uint OPEN_EXISTING = 3;
            public const uint FILE_ATTRIBUTE_NORMAL = 0x00000080;
    
            // CreateFile to get handle to drive
            [DllImport("kernel32.dll", SetLastError = true)]
            public static extern SafeFileHandle CreateFileW(
                [MarshalAs(UnmanagedType.LPWStr)]
                string lpFileName,
                uint dwDesiredAccess,
                uint dwShareMode,
                IntPtr lpSecurityAttributes,
                uint dwCreationDisposition,
                uint dwFlagsAndAttributes,
                IntPtr hTemplateFile);
    
            // For control codes
            public const uint FILE_DEVICE_MASS_STORAGE = 0x0000002d;
            public const uint IOCTL_STORAGE_BASE = FILE_DEVICE_MASS_STORAGE;
            public const uint FILE_DEVICE_CONTROLLER = 0x00000004;
            public const uint IOCTL_SCSI_BASE = FILE_DEVICE_CONTROLLER;
            public const uint METHOD_BUFFERED = 0;
            public const uint FILE_ANY_ACCESS = 0;
            public const uint FILE_READ_ACCESS = 0x00000001;
            public const uint FILE_WRITE_ACCESS = 0x00000002;
    
            public static uint CTL_CODE(uint DeviceType, uint Function,
                                         uint Method, uint Access)
            {
                return ((DeviceType << 16) | (Access << 14) |
                        (Function << 2) | Method);
            }
    
            // For DeviceIoControl to check no seek penalty
            public const uint StorageDeviceSeekPenaltyProperty = 7;
            public const uint PropertyStandardQuery = 0;
    
            [StructLayout(LayoutKind.Sequential)]
            public struct STORAGE_PROPERTY_QUERY
            {
                public uint PropertyId;
                public uint QueryType;
                [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
                public byte[] AdditionalParameters;
            }
    
            [StructLayout(LayoutKind.Sequential)]
            public struct DEVICE_SEEK_PENALTY_DESCRIPTOR
            {
                public uint Version;
                public uint Size;
                [MarshalAs(UnmanagedType.U1)]
                public bool IncursSeekPenalty;
            }
    
            // DeviceIoControl to check no seek penalty
            [DllImport("kernel32.dll", EntryPoint = "DeviceIoControl",
                       SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool DeviceIoControl(
                SafeFileHandle hDevice,
                uint dwIoControlCode,
                ref STORAGE_PROPERTY_QUERY lpInBuffer,
                uint nInBufferSize,
                ref DEVICE_SEEK_PENALTY_DESCRIPTOR lpOutBuffer,
                uint nOutBufferSize,
                out uint lpBytesReturned,
                IntPtr lpOverlapped);
    
            // For DeviceIoControl to check nominal media rotation rate
            public const uint ATA_FLAGS_DATA_IN = 0x02;
    
            [StructLayout(LayoutKind.Sequential)]
            public struct ATA_PASS_THROUGH_EX
            {
                public ushort Length;
                public ushort AtaFlags;
                public byte PathId;
                public byte TargetId;
                public byte Lun;
                public byte ReservedAsUchar;
                public uint DataTransferLength;
                public uint TimeOutValue;
                public uint ReservedAsUlong;
                public IntPtr DataBufferOffset;
                [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
                public byte[] PreviousTaskFile;
                [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
                public byte[] CurrentTaskFile;
            }
    
            [StructLayout(LayoutKind.Sequential)]
            public struct ATAIdentifyDeviceQuery
            {
                public ATA_PASS_THROUGH_EX header;
                [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
                public ushort[] data;
            }
    
            // DeviceIoControl to check nominal media rotation rate
            [DllImport("kernel32.dll", EntryPoint = "DeviceIoControl",
                       SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool DeviceIoControl(
                SafeFileHandle hDevice,
                uint dwIoControlCode,
                ref ATAIdentifyDeviceQuery lpInBuffer,
                uint nInBufferSize,
                ref ATAIdentifyDeviceQuery lpOutBuffer,
                uint nOutBufferSize,
                out uint lpBytesReturned,
                IntPtr lpOverlapped);
    
            // For error message
            public const uint FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;
    
            [DllImport("kernel32.dll", SetLastError = true)]
            static extern uint FormatMessage(
                uint dwFlags,
                IntPtr lpSource,
                uint dwMessageId,
                uint dwLanguageId,
                StringBuilder lpBuffer,
                uint nSize,
                IntPtr Arguments);
    
           static void Main(string[] args)
            {
    
    
    
                HasNominalMediaRotationRate();
            }
    
    
            // Method for nominal media rotation rate
            // (Administrative privilege is required)
            public static string HasNominalMediaRotationRate()
            {
                SafeFileHandle hDrive = CreateFileW(
                    "\\\\.\\PhysicalDrive0",
                    GENERIC_READ | GENERIC_WRITE, // Administrative privilege is required
                    FILE_SHARE_READ | FILE_SHARE_WRITE,
                    IntPtr.Zero,
                    OPEN_EXISTING,
                    FILE_ATTRIBUTE_NORMAL,
                    IntPtr.Zero);
    
                if (hDrive == null || hDrive.IsInvalid)
                {
                    string message = GetErrorMessage(Marshal.GetLastWin32Error());
                    return("CreateFile failed. " + message);
                }
    
                uint IOCTL_ATA_PASS_THROUGH = CTL_CODE(
                    IOCTL_SCSI_BASE, 0x040b, METHOD_BUFFERED,
                    FILE_READ_ACCESS | FILE_WRITE_ACCESS); // From ntddscsi.h
    
                ATAIdentifyDeviceQuery id_query = new ATAIdentifyDeviceQuery();
                id_query.data = new ushort[256];
    
                id_query.header.Length = (ushort)Marshal.SizeOf(id_query.header);
                id_query.header.AtaFlags = (ushort)ATA_FLAGS_DATA_IN;
                id_query.header.DataTransferLength =
                    (uint)(id_query.data.Length * 2); // Size of "data" in bytes
                id_query.header.TimeOutValue = 3; // Sec
                id_query.header.DataBufferOffset = (IntPtr)Marshal.OffsetOf(
                    typeof(ATAIdentifyDeviceQuery), "data");
                id_query.header.PreviousTaskFile = new byte[8];
                id_query.header.CurrentTaskFile = new byte[8];
                id_query.header.CurrentTaskFile[6] = 0xec; // ATA IDENTIFY DEVICE
    
                uint retval_size;
    
                bool result = DeviceIoControl(
                    hDrive,
                    IOCTL_ATA_PASS_THROUGH,
                    ref id_query,
                    (uint)Marshal.SizeOf(id_query),
                    ref id_query,
                    (uint)Marshal.SizeOf(id_query),
                    out retval_size,
                    IntPtr.Zero);
    
                hDrive.Close();
    
                if (result == false)
                {
                    string message = GetErrorMessage(Marshal.GetLastWin32Error());
                    return ("DeviceIoControl failed. " + message);
                }
                else
                {
                    // Word index of nominal media rotation rate
                    // (1 means non-rotate device)
                    const int kNominalMediaRotRateWordIndex = 217;
    
                    if (id_query.data[kNominalMediaRotRateWordIndex] == 1)
                    {
                        return "Disk is SSD";
                    }
                    else
                    {
                        return "Disk is non SSD";
                    }
    
                }
            } 
    
            // Method for error message
            public static string GetErrorMessage(int code)
            {
                StringBuilder message = new StringBuilder(255);
    
                FormatMessage(
                  FORMAT_MESSAGE_FROM_SYSTEM,
                  IntPtr.Zero,
                  (uint)code,
                  0,
                  message,
                  (uint)message.Capacity,
                  IntPtr.Zero);
    
                return message.ToString();
            }
        }
    
    
    
    
    }    
    

    然后你在 vb.net 中调用这个 dll:

    Imports DetectSsd
    

    然后你可以在任何地方调用它:

    textbox.text = DetectSsd.Program.HasNominalMediaRotationRate()
    

    c#来源:emoacht.wordpress.com/2012/11/06/csharp-ssd

    为 vb.net 编辑

    【讨论】:

    • 谢谢!!这是你写的吗?我可以将此代码用于正式工作吗?
    • 当然可以,这就是我与本网站分享它的原因!祝你好运,如果有任何问题,请留言。
    • 你应该引用你的来源:emoacht.wordpress.com/2012/11/06/csharp-ssd
    【解决方案3】:

    @Mr-HaXx 当你调用 HasNominalMediaRotationRate() 时,你需要提供一个驱动器号。如何知道驱动器 C 或 D 是驱动器号 0、1 还是 2?

    我有一台带 ssd(C) 和 hdd(D) 的电脑。

    当我以 0 开始代码时,它告诉我这是一个 ROTATE 设备。所以应该是D盘,但是想知道哪个盘是我的C盘还是我的D盘。

    谢谢

    已编辑:

    此外,这是 C# 中的代码,用于从逻辑驱动器号中查找物理驱动器号。 (页面底部)

    https://emoacht.wordpress.com/2012/11/06/csharp-ssd/

    【讨论】:

      猜你喜欢
      • 2019-01-05
      • 2023-04-04
      • 2017-10-04
      • 2021-01-10
      • 1970-01-01
      • 2015-07-12
      • 1970-01-01
      • 2021-08-07
      • 2014-12-21
      相关资源
      最近更新 更多