获取连接的USB设备列表


92

如何获得Windows计算机上所有已连接USB设备的列表?

Answers:


119

为您的项目添加对System.Management的引用,然后尝试执行以下操作:

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

14
有没有办法检索设备的友好名称?例如,当我进入USB记忆棒的属性时,我会看到“ Kingston DataTraveler 2.0 USB Device”。
罗伯特2010年

1
DeviceID和PNPDeviceID有什么区别?
Shimmy Weitzhandler,2011年

1
当我运行上述程序时,我得到了USB硬盘,键盘和鼠标,但没有得到我的USB摄像头,我的USB A / D。为什么我的所有USB设备都没有出现?
Curt

8
为了接收所有USB设备的列表,应该查询“ Win32_USBControllerDevice”而不是“ Win32_USBHub”。然后使用“ Dependent”属性获取设备地址字符串。
Nedko

1
此搜索对我来说需要8秒。有什么办法可以固定东西吗?
丹尼尔(Daniel)

45

我知道我要回答一个老问题,但是我只是通过相同的练习,发现了更多信息,我认为这将为讨论做出很大贡献,并帮助发现此问题并找出问题所在的其他人。现有的答案不足。

接受的答案是接近的,并且可以使用修正Nedko的评论吧。对所涉及的WMI类的更详细的了解有助于完成操作。

Win32_USBHub仅返回USB 集线器。在事后看来,这似乎是显而易见的,但上面的讨论却忽略了它。它不包括所有可能的USB设备,仅包括可以(至少在理论上)充当其他设备集线器的USB设备。它会错过一些不是集线器的设备(尤其是复合设备的一部分)。

Win32_PnPEntity确实包括所有USB设备以及数百个非USB设备。 Russel Gantman的建议是使用WHERE子句搜索Win32_PnPEntity以“ USB%”开头的DeviceID来过滤列表,这很有帮助,但有点不完整。它错过了蓝牙设备,某些打印机/打印服务器以及符合HID的鼠标和键盘。我已经看到“ USB \%”,“ USBSTOR \%”,“ USBPRINT \%”,“ BTH \%”,“ SWD \%”和“ HID \%”。 Win32_PnPEntity但是,当您拥有其他来源的PNPDeviceID时,它是一个很好的“主”参考来查找信息。

我发现枚举USB设备的最佳方法是查询Win32_USBControllerDevice。虽然它没有提供有关设备的详细信息,但它会完全枚举您的USB设备,并为您的PNPDeviceID每个USB设备(包括集线器,非Hub设备和HID兼容设备)提供一对先行/从属对。系统。查询返回的每个从属都是USB设备。前一个将是分配给它的控制器,是通过查询返回的USB控制器之一Win32_USBController

另外,似乎在幕后,WMI 在响应查询时会遍历“ 设备树Win32_USBControllerDevice,因此返回这些结果的顺序可以帮助识别父子关系。(这不是记录,因此只是一种猜测;使用的SetupDi API的CM_Get_Parent(或儿童 + 同级)的最终结果),作为一个选项的SetupDi API,似乎所有设备列出的下Win32_USBHub它们可以抬头在注册表中(位于HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\ + PNPDeviceID),并将有一个参数ParentIdPrefix,该参数将为其子项的PNPDeviceID中最后一个字段的前缀,因此也可以在通配符匹配中使用此参数来过滤Win32_PnPEntity查询。

在我的应用程序中,我执行了以下操作:

  • (可选)Win32_PnPEntity查询结果并将其存储在键值映射(以PNPDeviceID作为键)中,以供以后检索。如果您以后要进行单个查询,则这是可选的。
  • 查询Win32_USBControllerDevice我的系统上的USB设备的定义列表(所有的受养人)和提取这些的PNPDeviceIDs。我根据设备树的顺序,进一步将设备分配给根集线器(返回的第一个设备,而不是控制器),并基于parentIdPrefix构建了一棵树。查询返回的顺序与通过SetupDi进行的设备树枚举匹配的顺序是每个根集线器(前者为其标识控制器),然后是其下的设备迭代,例如,在我的系统上:
    • 第一控制器的根集线器
    • 第二个控制器的根集线器
      • 第二个控制器的根集线器下的第一个集线器(具有parentIdPrefix)
        • 在第二个控制器的根集线器下的第一个集线器下的第一个复合设备(PNPDeviceID与集线器的ParentIdPrefix匹配;具有自己的ParentIdPrefix)
          • 复合设备的HID设备部分(PNPDeviceID与复合设备的ParentIDPrefix匹配)
        • 第二个控制器的根集线器下的第一个集线器下的第二个设备
          • 复合设备的HID设备部分
      • 第二个控制器的根集线器下的第二个集线器
        • 第二个控制器的根集线器下的第二个集线器下的第一个设备
      • 第二个控制器的根集线器下的第三个集线器
      • 等等
  • 受到质疑Win32_USBController。这给了我控制器的PNPDeviceID的详细信息,这些信息位于设备树的顶部(这是上一个查询的前身)。使用上一步中派生的树,递归遍历其子代(根集线器)及其子代(其他集线器)及其子代(非集线器设备和复合设备)及其子代等。
    • 通过引用第一步中存储的映射,检索了我树中每个设备的详细信息。(可选地,可以跳过第一步,并Win32_PnPEntity在此步骤中使用PNPDeviceId单独查询以获取信息;可能是CPU与内存的折衷决定了哪个顺序更好。)

总而言之,Win32USBControllerDevice从属是系统上USB设备的完整列表(控制器本身除外,控制器是同一查询中的前身),并且通过将这些PNPDeviceId对与注册表和提到的其他查询中的信息交叉引用,可以构造一张详细的图片。


如果一个人连接了4个相同的扫描仪,例如,如果在4个不同的操作中使用它们,您将如何区分是哪个?
热门照片,2016年

2
@topshot只要已连接,PNPDeviceID就是唯一的。没有办法告诉您是否断开了连接,然后又连接了另一个相同的连接。该ID在其他区域也被交叉引用,以希望标识使用了哪个操作。
丹尼尔·维迪斯

3
如果设备具有内置的序列号,则可以区分设备(这是序列号的目的)。序列号用作PnP“实例ID”。如果设备不包含一个序列号,则该实例ID是基本上通过从根设备树到设备的路径(和包含“&”字符)
布赖恩

作为备用,总是在观察更改的同时观察设备列表并拔出并重新插入。
Technophile

14

要查看我感兴趣的设备,基于这篇文章,我已经用Adel Hazzah的代码替换Win32_USBHub了。这对我有用:Win32_PnPEntity

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

这很棒。为了使您轻松确定刚插入的设备,将其编写为以一定间隔运行,将条目写入字典并报告自上次运行以来的所有添加,这很容易。
nixkuroi

7

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的答案。


5

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

using System.IO;

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

2
也会返回一张软盘,可能是USB卡读卡器,可能还有Zip,Jazz和Orb驱动器
Mad Myche

对于只想匹配USB友好名称的人来说,这是理想的解决方案。我使用此示例进行数据备份,由于驱动器号发生更改,因此我需要查找名称(此处为drive.VolumeLabel)
Bio42,19年

3

如果将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设备(而不是系统上的所有类型)


1
搜索USB开头的deviceID的where子句会丢失某些项目。最好迭代“ Win32_USBControllerDevice”的依赖项
Daniel Widdis

2

您可能会发现此线程很有用。这是一个Google代码项目,举例说明了这一点(它P / Invokes into setupapi.dll)。


您是否知道即使我正在使用System.Management,为什么ObjectQuery类也没有引用?
罗伯特2010年

@Robert您是否已将引用添加到项目中?您可以通过右键单击项目中的引用>添加引用...>搜索并检查System.Management>确定来完成此操作。
欧内斯特(Ernest)2014年

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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.