如何使用WMI获取USB设备的盘符
How to get the drive letter of USB device using WMI
我需要跟踪 C# 应用程序中的 USB 插入和移除事件,因此我根据 SO 上的其他问题提出了以下想法。
我不会用这个方法
var drives = DriveInfo.GetDrives()
.Where(drive => drive.IsReady && drive.DriveType == DriveType.Removable).ToList();
因为当您需要区分已连接和已断开连接的设备时,这会导致很多麻烦(新设备可以与之前缓存的设备具有相同的驱动器号和名称)。
所以我决定使用WMI来解决这个问题,但我发现无法通过Win32_USBHub
class获取指定USB设备的盘符。然后我想我可以像这样执行另一个查询
foreach (ManagementObject device in new ManagementObjectSearcher(@"SELECT * FROM Win32_USBHub").Get())
{
string deviceID = (string)device.GetPropertyValue("DeviceID");
Console.WriteLine("{0}", deviceID);
string query = string.Format("SELECT * FROM Win32_LogicalDisk WHERE DeviceID='{0}'", deviceID);
foreach (ManagementObject o in new ManagementObjectSearcher(query).Get())
{
string name = (string)o.GetPropertyValue("Name");
Console.WriteLine("{0}", name);
}
Console.WriteLine("==================================");
}
但它根本不起作用——每次我尝试执行与 Win32_LogicalDisk
table.[=14 一起使用的查询时,我都会收到异常 "Invalid query" =]
为什么?我究竟做错了什么?我该如何解决?也许有更好的方法来解决这个问题?
提前致谢。
您收到异常,因为您的 deviceID
包含需要转义的字符(反斜杠)。使用简单的替换你不应该得到异常。
string query = string.Format("SELECT * FROM Win32_LogicalDisk WHERE DeviceID='{0}'", deviceID.Replace(@"\", @"\"));
但是,从 WMI 获取 USB 盘符有点复杂。正如@MSalters 在他的评论中发布的 link 中所述,您需要经历一些 类:
Win32_DiskDrive-> Win32_DiskDriveToDiskPartition -> Win32_DiskPartition -> Win32_LogicalDiskToPartition -> Win32_LogicalDisk.
发现 here 代码的一个小修改版本对我有用:
foreach (ManagementObject device in new ManagementObjectSearcher(@"SELECT * FROM Win32_DiskDrive WHERE InterfaceType LIKE 'USB%'").Get())
{
Console.WriteLine((string)device.GetPropertyValue("DeviceID"));
Console.WriteLine((string)device.GetPropertyValue("PNPDeviceID"));
foreach (ManagementObject partition in new ManagementObjectSearcher(
"ASSOCIATORS OF {Win32_DiskDrive.DeviceID='" + device.Properties["DeviceID"].Value
+ "'} WHERE AssocClass = Win32_DiskDriveToDiskPartition").Get())
{
foreach (ManagementObject disk in new ManagementObjectSearcher(
"ASSOCIATORS OF {Win32_DiskPartition.DeviceID='"
+ partition["DeviceID"]
+ "'} WHERE AssocClass = Win32_LogicalDiskToPartition").Get())
{
Console.WriteLine("Drive letter " + disk["Name"]);
}
}
}
这是 michalk 对 C# 8 的回答的重构版本。
我将它与相关问题Detecting USB drive insertion and removal using windows service and c#的答案结合使用
static IEnumerable<(string deviceId, string pnpDeviceId, string driveLetter)> SelectDeviceInformation()
{
foreach (ManagementObject device in SelectDevices())
{
var deviceId = (string)device.GetPropertyValue("DeviceID");
var pnpDeviceId = (string)device.GetPropertyValue("PNPDeviceID");
var driveLetter = (string)SelectPartitions(device).SelectMany(SelectDisks).Select(disk => disk["Name"]).Single();
yield return (deviceId, pnpDeviceId, driveLetter);
}
static IEnumerable<ManagementObject> SelectDevices() => new ManagementObjectSearcher(
@"SELECT * FROM Win32_DiskDrive WHERE InterfaceType LIKE 'USB%'").Get()
.Cast<ManagementObject>();
static IEnumerable<ManagementObject> SelectPartitions(ManagementObject device) => new ManagementObjectSearcher(
"ASSOCIATORS OF {Win32_DiskDrive.DeviceID=" +
"'" + device.Properties["DeviceID"].Value + "'} " +
"WHERE AssocClass = Win32_DiskDriveToDiskPartition").Get()
.Cast<ManagementObject>();
static IEnumerable<ManagementObject> SelectDisks(ManagementObject partition) => new ManagementObjectSearcher(
"ASSOCIATORS OF {Win32_DiskPartition.DeviceID=" +
"'" + partition["DeviceID"] + "'" +
"} WHERE AssocClass = Win32_LogicalDiskToPartition").Get()
.Cast<ManagementObject>();
}
我需要跟踪 C# 应用程序中的 USB 插入和移除事件,因此我根据 SO 上的其他问题提出了以下想法。
我不会用这个方法
var drives = DriveInfo.GetDrives()
.Where(drive => drive.IsReady && drive.DriveType == DriveType.Removable).ToList();
因为当您需要区分已连接和已断开连接的设备时,这会导致很多麻烦(新设备可以与之前缓存的设备具有相同的驱动器号和名称)。
所以我决定使用WMI来解决这个问题,但我发现无法通过Win32_USBHub
class获取指定USB设备的盘符。然后我想我可以像这样执行另一个查询
foreach (ManagementObject device in new ManagementObjectSearcher(@"SELECT * FROM Win32_USBHub").Get())
{
string deviceID = (string)device.GetPropertyValue("DeviceID");
Console.WriteLine("{0}", deviceID);
string query = string.Format("SELECT * FROM Win32_LogicalDisk WHERE DeviceID='{0}'", deviceID);
foreach (ManagementObject o in new ManagementObjectSearcher(query).Get())
{
string name = (string)o.GetPropertyValue("Name");
Console.WriteLine("{0}", name);
}
Console.WriteLine("==================================");
}
但它根本不起作用——每次我尝试执行与 Win32_LogicalDisk
table.[=14 一起使用的查询时,我都会收到异常 "Invalid query" =]
为什么?我究竟做错了什么?我该如何解决?也许有更好的方法来解决这个问题?
提前致谢。
您收到异常,因为您的 deviceID
包含需要转义的字符(反斜杠)。使用简单的替换你不应该得到异常。
string query = string.Format("SELECT * FROM Win32_LogicalDisk WHERE DeviceID='{0}'", deviceID.Replace(@"\", @"\"));
但是,从 WMI 获取 USB 盘符有点复杂。正如@MSalters 在他的评论中发布的 link 中所述,您需要经历一些 类:
Win32_DiskDrive-> Win32_DiskDriveToDiskPartition -> Win32_DiskPartition -> Win32_LogicalDiskToPartition -> Win32_LogicalDisk.
发现 here 代码的一个小修改版本对我有用:
foreach (ManagementObject device in new ManagementObjectSearcher(@"SELECT * FROM Win32_DiskDrive WHERE InterfaceType LIKE 'USB%'").Get())
{
Console.WriteLine((string)device.GetPropertyValue("DeviceID"));
Console.WriteLine((string)device.GetPropertyValue("PNPDeviceID"));
foreach (ManagementObject partition in new ManagementObjectSearcher(
"ASSOCIATORS OF {Win32_DiskDrive.DeviceID='" + device.Properties["DeviceID"].Value
+ "'} WHERE AssocClass = Win32_DiskDriveToDiskPartition").Get())
{
foreach (ManagementObject disk in new ManagementObjectSearcher(
"ASSOCIATORS OF {Win32_DiskPartition.DeviceID='"
+ partition["DeviceID"]
+ "'} WHERE AssocClass = Win32_LogicalDiskToPartition").Get())
{
Console.WriteLine("Drive letter " + disk["Name"]);
}
}
}
这是 michalk 对 C# 8 的回答的重构版本。
我将它与相关问题Detecting USB drive insertion and removal using windows service and c#的答案结合使用
static IEnumerable<(string deviceId, string pnpDeviceId, string driveLetter)> SelectDeviceInformation()
{
foreach (ManagementObject device in SelectDevices())
{
var deviceId = (string)device.GetPropertyValue("DeviceID");
var pnpDeviceId = (string)device.GetPropertyValue("PNPDeviceID");
var driveLetter = (string)SelectPartitions(device).SelectMany(SelectDisks).Select(disk => disk["Name"]).Single();
yield return (deviceId, pnpDeviceId, driveLetter);
}
static IEnumerable<ManagementObject> SelectDevices() => new ManagementObjectSearcher(
@"SELECT * FROM Win32_DiskDrive WHERE InterfaceType LIKE 'USB%'").Get()
.Cast<ManagementObject>();
static IEnumerable<ManagementObject> SelectPartitions(ManagementObject device) => new ManagementObjectSearcher(
"ASSOCIATORS OF {Win32_DiskDrive.DeviceID=" +
"'" + device.Properties["DeviceID"].Value + "'} " +
"WHERE AssocClass = Win32_DiskDriveToDiskPartition").Get()
.Cast<ManagementObject>();
static IEnumerable<ManagementObject> SelectDisks(ManagementObject partition) => new ManagementObjectSearcher(
"ASSOCIATORS OF {Win32_DiskPartition.DeviceID=" +
"'" + partition["DeviceID"] + "'" +
"} WHERE AssocClass = Win32_LogicalDiskToPartition").Get()
.Cast<ManagementObject>();
}