从硬盘获取 RPM,以及磁盘是否在 vb.net 中是 SSD



正如标题所说,我正在 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("rootWMI", "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

我知道字节 115 是 hdd temp,但我无法找出所有其他字节代表什么。有人知道吗?

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

接下来,我需要找出硬盘(不是固态硬盘)的 RPM 是多少

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

using (var partitionSearcher = new ManagementObjectSearcher(
    @"\localhostROOTMicrosoftWindowsStorage",
    $"SELECT DiskNumber FROM MSFT_Partition WHERE DriveLetter='{upperCaseDiskLetter}'"))
{
    var partition = partitionSearcher.Get().Cast<ManagementBaseObject>().Single();
    using (var physicalDiskSearcher = new ManagementObjectSearcher(
                @"\localhostROOTMicrosoftWindowsStorage",
                $"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'

解决了。

如果有人需要知道

使用 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();
        }
    }


}    

然后,您将此 dll vb.net 调用:

Imports DetectSsd

然后在任何地方都可以使用以下方法调用它:

textbox.text = DetectSsd.Program.HasNominalMediaRotationRate()

c# 的源代码:emoacht.wordpress.com/2012/11/06/csharp-ssd

编辑了它 vb.net

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

我有一台带有ssd(C)和hdd(D)的计算机。

当我以 0 开头的代码时,它告诉我这是一个 ROTATE 设备。所以它应该是 D: 驱动器,但想知道哪个驱动器是我的 C 驱动器或我的 D 驱动器。

谢谢

编辑:

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

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

最新更新