简体   繁体   English

如何使用 WMI 获取 USB 设备的驱动器号

[英]How to get the drive letter of USB device using WMI

I need to track the USB insertion and removal events from the C# application so I came up with the following ideas based on the other questions on SO.我需要跟踪 C# 应用程序中的 USB 插入和移除事件,因此我根据 SO 上的其他问题提出了以下想法。

I can't use this method我不能用这个方法

var drives = DriveInfo.GetDrives()
    .Where(drive => drive.IsReady && drive.DriveType == DriveType.Removable).ToList();

because it can lead to a lot of troubles when you need to differentiate between connected and disconnected devices (the new ones can have the same drive letter and name like the ones that was previously cached).因为当您需要区分连接的设备和断开连接的设备(新设备可以具有与以前缓存的设备相同的驱动器号和名称时),这会导致很多麻烦。

So I decided to use WMI to solve this problem but I found that it's impossible to get the drive letter of the specified USB device via Win32_USBHub class.所以我决定使用WMI来解决这个问题,但是我发现无法通过Win32_USBHub类获取指定USB设备的驱动器号。 Then I thought that I can execute another query like this然后我想我可以像这样执行另一个查询

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("==================================");
}

but it doesn't work at all -- I get an exception "Invalid query" every time when I try to execute query that works with the Win32_LogicalDisk table.但它根本不起作用——每次当我尝试执行与Win32_LogicalDisk表一起使用的查询时,我都会收到异常“无效查询”。

Why?为什么? What am I doing wrong?我究竟做错了什么? How can I fix it?我该如何解决? Maybe there is a better ways to solve this problem?也许有更好的方法来解决这个问题?

Thanks in advance.提前致谢。

You get an exception because your deviceID contains characters that need to be escaped (backslashes).您会收到异常,因为您的deviceID包含需要转义的字符(反斜杠)。 With simple replace you shouldn't get the exception.使用简单的替换,你不应该得到例外。

string query = string.Format("SELECT * FROM Win32_LogicalDisk WHERE DeviceID='{0}'", deviceID.Replace(@"\", @"\\"));

However, getting USB drive letter from WMI is a little more complicated.但是,从 WMI 获取 USB 驱动器盘符要复杂一些。 You need to go through a few classes, as stated in a link that @MSalters posted in his comment:您需要学习一些课程,如@MSalters 在他的评论中发布的链接中所述:

Win32_DiskDrive-> Win32_DiskDriveToDiskPartition -> Win32_DiskPartition -> Win32_LogicalDiskToPartition -> Win32_LogicalDisk.

A little modified version of code found here worked for me:这里找到的一些修改过的代码版本对我有用:

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"]);
        }
    }
}

This is a refactored version of michalk's answer for C# 8.这是 Michalk 对 C# 8 的回答的重构版本。

I used it in combination with the answers for this, Detecting USB drive insertion and removal using windows service and c# , related question我将它与此问题的答案结合使用, 使用 Windows 服务和 c# 检测 USB 驱动器插入和删除,相关问题

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM