在 vb.net 中从 HDD 获取 RPM 以及磁盘是否为 SSD
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21921973/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Getting RPM from HDD and if disk is SSD or not in vb.net
提问by Mr-HaXx
As the title says it, i am working in vb.net and trying to get the RPM of my hard disk in a textbox. Next to that i am trying to figure out if my disk is a HDD or SSD.
正如标题所说,我在 vb.net 中工作并试图在文本框中获取硬盘的 RPM。接下来,我想弄清楚我的磁盘是 HDD 还是 SSD。
I have been searching the web a full week now on anything i can think of and all i can find is temperature reading using:
我已经在网上搜索了整整一周我能想到的任何东西,我能找到的只是温度读数:
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
I know Byte 115 is hdd temp, but i cannot find out what all other Bytes represent. Anybody any idea?
我知道字节 115 是硬盘温度,但我无法找出所有其他字节代表什么。有人有什么想法吗?
I need to know how i can search for SSD specific Values that a normal HDD doesn't have. I know there are, but i can't seem to find anything.
我需要知道如何搜索普通 HDD 没有的特定于 SSD 的值。我知道有,但我似乎找不到任何东西。
And next to that i need to find out what the RPM is of a HDD(not ssd)
接下来我需要找出硬盘(不是固态硬盘)的转速是多少
采纳答案by Mr-HaXx
Solved it.
解决了。
If anybody needs to know
如果有人需要知道
Use Visual Studio to create a dll containing the following code:
使用 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();
}
}
}
Then you call this dll in vb.net with:
然后你在 vb.net 中调用这个 dll:
Imports DetectSsd
And then anywhere you can call it using:
然后在任何你可以使用的地方调用它:
textbox.text = DetectSsd.Program.HasNominalMediaRotationRate()
Source for c#: emoacht.wordpress.com/2012/11/06/csharp-ssd
c# 来源:emoacht.wordpress.com/2012/11/06/csharp-ssd
Edited it for vb.net
为 vb.net 编辑它
回答by Filip Skakun
There seems to be a better way these days (C#):
这些天似乎有更好的方法(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)); ;
}
}
Based on same underlying types, but somewhat simpler in PowerShell:
基于相同的底层类型,但在 PowerShell 中稍微简单一些:
$is_disk_C_SSD = (Get-PhysicalDisk | ?{$_.DeviceId -eq (Get-Partition -DriveLetter 'C')[0].DiskNumber})[0].MediaType -eq 'SSD'
回答by émile Pettersen-Coulombe
@Mr-HaXx When you call HasNominalMediaRotationRate(), you need to give a drive number. How to know if drive C or D are drive number 0, 1 or 2?
@Mr-HaXx 当您调用 HasNominalMediaRotationRate() 时,您需要提供驱动器编号。如何知道驱动器 C 或 D 是驱动器号 0、1 还是 2?
I have a computer with an ssd(C) and an hdd(D).
我有一台带有 ssd(C) 和一个 hdd(D) 的计算机。
When I start the code with 0, it says to me that is a ROTATE device. So it should be the D: drive, but would like to know which number of drive is my C drive or my D drive.
当我以 0 开始代码时,它告诉我这是一个 ROTATE 设备。所以应该是D:盘,但是想知道哪个盘是我的C盘还是我的D盘。
Thanks
谢谢
Edited:
编辑:
In addition, this is a code in C# to find a physical drive number from a logical drive letter. (Bottom of the page)
另外,这是C#中的代码,用于从逻辑驱动器号中查找物理驱动器号。(页面底部)

