获取已连接的USB设备列表

117

我该如何获取Windows电脑上所有连接的USB设备列表?

9个回答

138

在你的项目中添加对System.Management的引用,然后尝试像下面这样:

using System;
using System.Collections.Generic;
using System.Management; // need to add System.Management to your project references.

class Program
{
    static void Main(string[] args)
    {
        var usbDevices = GetUSBDevices();

        foreach (var usbDevice in usbDevices)
        {
            Console.WriteLine(
                $"Device ID: {usbDevice.DeviceID}, PNP Device ID: {usbDevice.PnpDeviceID}, Description: {usbDevice.Description}");
        }

        Console.Read();
    }

    static List<USBDeviceInfo> GetUSBDevices()
    {
        List<USBDeviceInfo> devices = new List<USBDeviceInfo>();

        using var searcher = new ManagementObjectSearcher(
            @"Select * From Win32_USBHub");
        using ManagementObjectCollection collection = searcher.Get();

        foreach (var device in collection)
        {
            devices.Add(new USBDeviceInfo(
                (string)device.GetPropertyValue("DeviceID"),
                (string)device.GetPropertyValue("PNPDeviceID"),
                (string)device.GetPropertyValue("Description")
                ));
        }
        return devices;
    }
}

class USBDeviceInfo
{
    public USBDeviceInfo(string deviceID, string pnpDeviceID, string description)
    {
        this.DeviceID = deviceID;
        this.PnpDeviceID = pnpDeviceID;
        this.Description = description;
    }
    public string DeviceID { get; private set; }
    public string PnpDeviceID { get; private set; }
    public string Description { get; private set; }
}

59

我知道我在回复一个旧问题,但我刚刚经历了同样的过程,并发现了更多的信息,我认为这将有助于讨论并帮助任何发现这个问题并看到现有答案不足之处的人。

已接受的答案是正确的,可以使用Nedko的评论进行更正。更详细地了解WMI类的相关内容有助于完善整个图片。

Win32_USBHub仅返回USB 集线器。这在事后看来似乎很明显,但上面的讨论却忽略了它。它不包括所有可能的USB设备,只包括那些(至少在理论上)可以作为其他设备的集线器的设备。它会错过一些不是集线器的设备(特别是组合设备的某些部分)。

Win32_PnPEntity 包含所有的 USB 设备,以及数百个非 USB 设备。Russel Gantman's 建议使用 WHERE 子句搜索 Win32_PnPEntity,以筛选以 "USB%" 开头的 DeviceID 列表,这对于过滤列表是有帮助的,但略微不完整;它会错过蓝牙设备、一些打印机/打印服务器和 HID 兼容的鼠标和键盘。我见过 "USB\%", "USBSTOR\%", "USBPRINT\%", "BTH\%", "SWD\%" 和 "HID\%"。然而,Win32_PnPEntity 是一个很好的 "主" 参考,可以在从其他来源获取 PNPDeviceID 后查找信息。

我发现枚举USB设备的最佳方法是查询Win32_USBControllerDevice。虽然它不会为设备提供详细信息,但它完全枚举了您系统上的USB设备,并为每个USB设备(包括集线器、非集线器设备和符合HID的设备)提供了一个PNPDeviceID的前置/后置对。查询返回的每个后置都将是一个USB设备。前置将是它所分配的控制器之一,即通过查询Win32_USBController返回的USB控制器之一。
作为一个额外的奖励,似乎在底层,WMI 在响应 Win32_USBControllerDevice 查询时遍历 设备树,因此返回结果的顺序可以帮助识别父/子关系。(这并没有记录下来,因此只是猜测;要获得确定的结果,请使用 SetupDi API 的 CM_Get_Parent(或 Child + Sibling)。)作为 SetupDi API 的一种选项,似乎对于在 Win32_USBHub 下列出的所有设备,它们可以在注册表中查找(位于 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\ + PNPDeviceID),并且将具有参数 ParentIdPrefix,该参数将是其子级 PNPDeviceID 中最后一个字段的前缀,因此这也可以用于通配符匹配以过滤 Win32_PnPEntity 查询。
在我的应用程序中,我做了以下操作:
(可选)查询了 Win32_PnPEntity,并将结果存储在键值映射中(以 PNPDeviceID 为键),以便以后检索。如果您想稍后进行单独的查询,则此项是可选的。 查询了 Win32_USBControllerDevice,获取了系统上 USB 设备的明确列表(所有 Dependents),并提取了这些设备的 PNPDeviceIDs。根据设备树的顺序,进一步分配设备到根集线器(第一个返回的设备,而不是控制器),并基于 parentIdPrefix 构建树。查询返回的顺序,与通过 SetupDi 进行的设备树枚举相匹配,每个根集线器(其 Antecedent 确定了控制器)后跟它下面的设备迭代,例如,在我的系统上:
  • 第一个控制器的根集线器
  • 第二个控制器的根集线器
    • 第二个控制器根集线器下第一个集线器(具有 parentIdPrefix)
      • 第一个集线器下第一个复合设备(PNPDeviceID 与上述集线器的 ParentIdPrefix 匹配;具有自己的 ParentIdPrefix)
        • 复合设备的 HID 设备(PNPDeviceID 与上述复合设备的 ParentIDPrefix 匹配)
      • 第一个集线器下的第二个设备
        • 复合设备的 HID 设备
    • 第二个控制器根集线器下的第二个集线器
      • 第二个控制器根集线器下的第一个设备
    • 第二个控制器根集线器下的第三个集线器
    • 等等。
查询了 Win32_USBController。这为我提供了设备树顶部的控制器的 PNPDeviceIDs 的详细信息(前一个查询的 Antecedents)。使用在上一步中导出的树,递归地迭代其子级(根集线器)及其子级(其他集线器)及其子级(非集线器设备和复合设备)及其子级等。
  • 通过引用存储在第一步中的映射,检索了树中每个设备的详细信息。(可选地,可以跳过第一步,并使用 PNPDeviceId 单独查询 Win32_PnPEntity,以在此步骤获取信息;可能是 CPU 与内存之间的权衡,确定哪个顺序更好。)
总之,Win32USBControllerDevice的依赖项是系统上USB设备的完整列表(除了控制器本身,该查询中的前置项),通过将这些PNPDeviceId对与来自注册表和其他查询提到的信息进行交叉引用,可以构建出详细的图像。

19
为了查看我感兴趣的设备,我在Adel Hazzah的代码中用Win32_PnPEntity替换了Win32_USBHub,这基于这篇帖子。对我来说这起作用了:
namespace ConsoleApplication1
{
  using System;
  using System.Collections.Generic;
  using System.Management; // need to add System.Management to your project references.

  class Program
  {
    static void Main(string[] args)
    {
      var usbDevices = GetUSBDevices();

      foreach (var usbDevice in usbDevices)
      {
        Console.WriteLine("Device ID: {0}, PNP Device ID: {1}, Description: {2}",
            usbDevice.DeviceID, usbDevice.PnpDeviceID, usbDevice.Description);
      }

      Console.Read();
    }

    static List<USBDeviceInfo> GetUSBDevices()
    {
      List<USBDeviceInfo> devices = new List<USBDeviceInfo>();

      ManagementObjectCollection collection;
      using (var searcher = new ManagementObjectSearcher(@"Select * From Win32_PnPEntity"))
        collection = searcher.Get();      

      foreach (var device in collection)
      {
        devices.Add(new USBDeviceInfo(
        (string)device.GetPropertyValue("DeviceID"),
        (string)device.GetPropertyValue("PNPDeviceID"),
        (string)device.GetPropertyValue("Description")
        ));
      }

      collection.Dispose();
      return devices;
    }
  }

  class USBDeviceInfo
  {
    public USBDeviceInfo(string deviceID, string pnpDeviceID, string description)
    {
      this.DeviceID = deviceID;
      this.PnpDeviceID = pnpDeviceID;
      this.Description = description;
    }
    public string DeviceID { get; private set; }
    public string PnpDeviceID { get; private set; }
    public string Description { get; private set; }
  }
}

18

Adel Hazzah的回答提供了可工作的代码,Daniel WiddisNedko的评论提到需要查询Win32_USBControllerDevice并使用其Dependent属性,而Daniel的回答则提供了很多细节但没有代码。

以下是上述讨论的综合,以提供列出所有已连接USB设备的可直接访问PNP设备属性的工作代码:

using System;
using System.Collections.Generic;
using System.Management; // reference required

namespace cSharpUtilities
{
    class UsbBrowser
    {

        public static void PrintUsbDevices()
        {
            IList<ManagementBaseObject> usbDevices = GetUsbDevices();

            foreach (ManagementBaseObject usbDevice in usbDevices)
            {
                Console.WriteLine("----- DEVICE -----");
                foreach (var property in usbDevice.Properties)
                {
                    Console.WriteLine(string.Format("{0}: {1}", property.Name, property.Value));
                }
                Console.WriteLine("------------------");
            }
        }

        public static IList<ManagementBaseObject> GetUsbDevices()
        {
            IList<string> usbDeviceAddresses = LookUpUsbDeviceAddresses();

            List<ManagementBaseObject> usbDevices = new List<ManagementBaseObject>();

            foreach (string usbDeviceAddress in usbDeviceAddresses)
            {
                // query MI for the PNP device info
                // address must be escaped to be used in the query; luckily, the form we extracted previously is already escaped
                ManagementObjectCollection curMoc = QueryMi("Select * from Win32_PnPEntity where PNPDeviceID = " + usbDeviceAddress);
                foreach (ManagementBaseObject device in curMoc)
                {
                    usbDevices.Add(device);
                }
            }

            return usbDevices;
        }

        public static IList<string> LookUpUsbDeviceAddresses()
        {
            // this query gets the addressing information for connected USB devices
            ManagementObjectCollection usbDeviceAddressInfo = QueryMi(@"Select * from Win32_USBControllerDevice");

            List<string> usbDeviceAddresses = new List<string>();

            foreach(var device in usbDeviceAddressInfo)
            {
                string curPnpAddress = (string)device.GetPropertyValue("Dependent");
                // split out the address portion of the data; note that this includes escaped backslashes and quotes
                curPnpAddress = curPnpAddress.Split(new String[] { "DeviceID=" }, 2, StringSplitOptions.None)[1];

                usbDeviceAddresses.Add(curPnpAddress);
            }

            return usbDeviceAddresses;
        }

        // run a query against Windows Management Infrastructure (MI) and return the resulting collection
        public static ManagementObjectCollection QueryMi(string query)
        {
            ManagementObjectSearcher managementObjectSearcher = new ManagementObjectSearcher(query);
            ManagementObjectCollection result = managementObjectSearcher.Get();

            managementObjectSearcher.Dispose();
            return result;
        }

    }

}

如果您想要,需要添加异常处理。如果您想了解设备树等内容,请参考Daniel的答案。


8
如果您将ManagementObjectSearcher更改为以下内容:
ManagementObjectSearcher searcher = 
       new ManagementObjectSearcher("root\\CIMV2", 
       @"SELECT * FROM Win32_PnPEntity where DeviceID Like ""USB%"""); 

所以,"GetUSBDevices()"看起来像这样
static List<USBDeviceInfo> GetUSBDevices()
{
  List<USBDeviceInfo> devices = new List<USBDeviceInfo>();

  ManagementObjectCollection collection;
  using (var searcher = new ManagementObjectSearcher(@"SELECT * FROM Win32_PnPEntity where DeviceID Like ""USB%"""))
    collection = searcher.Get();      

  foreach (var device in collection)
  {
    devices.Add(new USBDeviceInfo(
    (string)device.GetPropertyValue("DeviceID"),
    (string)device.GetPropertyValue("PNPDeviceID"),
    (string)device.GetPropertyValue("Description")
    ));
  }

  collection.Dispose();
  return devices;
}

您的结果将仅限于USB设备(而不是系统上的所有类型)


8

对于只寻找可移动USB驱动器的人来说,这是一个更简单的示例。

使用 System.IO;

foreach (DriveInfo drive in DriveInfo.GetDrives())
{
    if (drive.DriveType == DriveType.Removable)
    {
        Console.WriteLine(string.Format("({0}) {1}", drive.Name.Replace("\\",""), drive.VolumeLabel));
    }
}

如果您像我一样正在寻找查找所有UDisk的解决方案,那么这是一个很好的解决方案。 - Kai Wang

2

1
这是关于编程的内容。以下是翻译文本:

这个回答改进了Tydaeus写的回答:https://dev59.com/j3A75IYBdhLWcg3wYH3I#48390286

问题是“如何获取Windows计算机上所有连接的USB设备列表?”,例如,USB集线器并不是我想要的列表。

因此,我添加了一个示例,说明如何排除某类设备,例如USB集线器。

类别列表如下:

https://learn.microsoft.com/en-us/windows-hardware/drivers/install/guid-devinterface-mouse

https://learn.microsoft.com/en-us/windows-hardware/drivers/install/guid-devinterface-keyboard

这里是:https://learn.microsoft.com/en-us/windows-hardware/drivers/install/system-defined-device-setup-classes-available-to-vendors

但也有其他可能的类别,例如USB集线器:

https://learn.microsoft.com/en-us/windows-hardware/drivers/install/guid-devinterface-usb-hub

它还会显示设备的VID(供应商ID),PID(产品ID)和序列号,如果有兴趣的话。

using System;
using System.Collections.Generic;
using System.Management;

/*
ClassGuid for USB hubs: {36fc9e60-c465-11cf-8056-444553540000} The identifier is GUID_DEVINTERFACE_USB_HUB
ClassGuid for network adapters: {4d36e972-e325-11ce-bfc1-08002be10318} The identifier is GUID_DEVINTERFACE_NET
ClassGuid for HID devices: {745a17a0-74d3-11d0-b6fe-00a0c90f57da} The identifier is GUID_DEVINTERFACE_HID
ClassGuid for mice: {4d36e96f-e325-11ce-bfc1-08002be10318} The identifier is GUID_DEVINTERFACE_MOUSE
ClassGuid for keyboards: {4d36e96b-e325-11ce-bfc1-08002be10318} The identifier is GUID_DEVINTERFACE_KEYBOARD

https://learn.microsoft.com/en-us/windows-hardware/drivers/install/system-defined-device-setup-classes-available-to-vendors
/**/

class Program
{
    static void Main(string[] args)
    {
        IList<ManagementBaseObject> usbDevices = GetUsbDevices();

        foreach (ManagementBaseObject usbDevice in usbDevices)
        {
            string classGuid = (string)usbDevice["ClassGuid"];

            // you can exclude a device class, for example USB hubs:
            if (classGuid == "{36fc9e60-c465-11cf-8056-444553540000}")
                continue;

            Console.WriteLine("----- DEVICE -----");
            foreach (var property in usbDevice.Properties)
            {
                if(property.Name == "DeviceID")
                Console.WriteLine(string.Format("{0}: {1}", property.Name, property.Value));
            }

            string deviceID = (string)usbDevice["DeviceID"];

            if (deviceID.Contains("VID_") && deviceID.Contains("PID_"))
            {
                string[] splitDeviceID = deviceID.Split('\\');
                string[] splitVidPid = splitDeviceID[splitDeviceID.Length - 2].Split('&');

                string vid = splitVidPid[0].Split('_')[1];
                string pid = splitVidPid[1].Split('_')[1];
                string serialNumber = splitDeviceID[splitDeviceID.Length - 1];

                Console.WriteLine("VID: {0}", vid);
                Console.WriteLine("PID: {0}", pid);
                Console.WriteLine("Serial Number: {0}", serialNumber);
            }

            Console.WriteLine("------------------");
        }
    }

    public static IList<ManagementBaseObject> GetUsbDevices()
    {
        IList<string> usbDeviceAddresses = LookUpUsbDeviceAddresses();

        List<ManagementBaseObject> usbDevices = new List<ManagementBaseObject>();

        foreach (string usbDeviceAddress in usbDeviceAddresses)
        {
            // query MI for the PNP device info
            // address must be escaped to be used in the query; luckily, the form we extracted previously is already escaped
            ManagementObjectCollection curMoc = QueryMi("Select * from Win32_PnPEntity where PNPDeviceID = " + usbDeviceAddress);
            foreach (ManagementBaseObject device in curMoc)
            {
                usbDevices.Add(device);
            }
        }

        return usbDevices;
    }

    public static IList<string> LookUpUsbDeviceAddresses()
    {
        // this query gets the addressing information for connected USB devices
        ManagementObjectCollection usbDeviceAddressInfo = QueryMi(@"Select * from Win32_USBControllerDevice");

        List<string> usbDeviceAddresses = new List<string>();

        foreach (var device in usbDeviceAddressInfo)
        {
            string curPnpAddress = (string)device.GetPropertyValue("Dependent");
            // split out the address portion of the data; note that this includes escaped backslashes and quotes
            curPnpAddress = curPnpAddress.Split(new String[] { "DeviceID=" }, 2, StringSplitOptions.None)[1];

            usbDeviceAddresses.Add(curPnpAddress);
        }

        return usbDeviceAddresses;
    }

    // run a query against Windows Management Infrastructure (MI) and return the resulting collection
    public static ManagementObjectCollection QueryMi(string query)
    {
        ManagementObjectSearcher managementObjectSearcher = new ManagementObjectSearcher(query);
        ManagementObjectCollection result = managementObjectSearcher.Get();

        managementObjectSearcher.Dispose();
        return result;
    }
}


0
  lstResult.Clear();
  foreach (ManagementObject drive in new ManagementObjectSearcher("select * from Win32_DiskDrive where InterfaceType='USB'").Get())
  {
       foreach (ManagementObject partition in new ManagementObjectSearcher("ASSOCIATORS OF {Win32_DiskDrive.DeviceID='" + drive["DeviceID"] + "'} WHERE AssocClass = Win32_DiskDriveToDiskPartition").Get())
       {
            foreach (ManagementObject disk in new ManagementObjectSearcher("ASSOCIATORS OF {Win32_DiskPartition.DeviceID='" + partition["DeviceID"] + "'} WHERE AssocClass = Win32_LogicalDiskToPartition").Get())
            {
                  foreach (var item in disk.Properties)
                  {
                       object value = disk.GetPropertyValue(item.Name);
                  }
                  string valor = disk["Name"].ToString();
                  lstResult.Add(valor);
                  }
             }
        }
   }

那个 object value 是做什么用的? - newbieguy
浏览磁盘上的其他可用属性,并将其值保存在对象值中。 - JxDarkAngel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接