Получить список подключенных USB-устройств

93

Как я могу получить список всех подключенных USB-устройств на компьютере с Windows?

Роберт
источник

Ответы:

122

Добавьте ссылку на 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-накопителя, я вижу «USB-устройство Kingston DataTraveler 2.0».
Роберт
2
В чем разница между DeviceID и PNPDeviceID?
Шимми Вайцхандлер
1
Когда я запускаю указанную выше программу, я получаю свои жесткие диски USB, клавиатуру и мышь, но не получаю USB-камеру и USB A / D. Почему не отображаются все мои USB-устройства?
Curt
8
он должен быть запрошен «Win32_USBControllerDevice», а не «Win32_USBHub», чтобы получить список всех USB-устройств. Затем используйте свойство «Зависимый», чтобы получить строку адреса устройства.
Nedko
1
у меня этот поиск занимает 8 секунд. Есть ли возможность скрепить вещи?
Даниель
44

Я знаю, что отвечаю на старый вопрос, но я просто проделал то же самое упражнение и узнал немного больше информации, которая, я думаю, внесет большой вклад в обсуждение и поможет всем, кто найдет этот вопрос и увидит, где существующие ответы не соответствуют действительности.

Общепринятый ответ близок, и может быть исправлено с помощью комментария Недко в к нему. Более подробное понимание задействованных классов WMI помогает завершить картину.

Win32_USBHub возвращает только USB концентраторы . Оглядываясь назад, это кажется очевидным, но приведенное выше обсуждение упускает из виду. Он не включает все возможные USB-устройства, только те, которые могут (по крайней мере теоретически) выступать в качестве концентратора для дополнительных устройств. Он пропускает некоторые устройства, которые не являются концентраторами (особенно части составных устройств).

Win32_PnPEntity включает в себя все USB-устройства и сотни других не-USB-устройств. Совет Рассела Гантмана использовать поиск с помощью предложения WHERE Win32_PnPEntityдля DeviceID, начинающегося с «USB%» для фильтрации списка, полезен, но немного неполон; в нем отсутствуют устройства Bluetooth, некоторые принтеры / серверы печати, а также HID-совместимые мыши и клавиатуры. Я видел «USB \%», «USBSTOR \%», «USBPRINT \%», «BTH \%», «SWD \%» и «HID \%». Win32_PnPEntityтем не менее, это хорошая «основная» ссылка для поиска информации, когда вы получаете PNPDeviceID из других источников.

Я обнаружил, что лучший способ перечислить USB-устройства - это запросить Win32_USBControllerDevice . Хотя он не дает подробной информации об устройствах, он полностью перечисляет ваши USB-устройства и дает вам пару Antecedent / Dependent PNPDeviceIDдля каждого USB-устройства (включая концентраторы, устройства, не являющиеся концентраторами, и устройства, совместимые с HID) на вашем система. Каждый зависимый, возвращенный из запроса, будет USB-устройством. Антецедентом будет контроллер, которому он назначен, один из контроллеров USB, возвращенный запросом Win32_USBController.

В качестве бонуса оказывается, что под капотом WMI просматривает дерево устройств при ответе на Win32_USBControllerDeviceзапрос, поэтому порядок, в котором возвращаются эти результаты, может помочь определить отношения родитель / потомок. (Это не задокументировано и, таким образом, является лишь предположением; для окончательных результатов используйте CM_Get_Parent (или Child + Sibling ) API SetupDi .) Как вариант для API SetupDi, похоже, что для всех устройств, перечисленных в разделе, Win32_USBHubони могут быть найдены в реестре (at HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\ + PNPDeviceID) и будет иметь параметр, ParentIdPrefixкоторый будет префиксом последнего поля в PNPDeviceID его дочерних элементов, поэтому его также можно использовать в сопоставлении с подстановочными знаками для фильтрации Win32_PnPEntityзапроса.

В своем приложении я сделал следующее:

  • (Необязательно) Запрошено Win32_PnPEntity и сохранены результаты в карте значения ключа (с PNPDeviceID в качестве ключа) для последующего извлечения. Это необязательно, если вы хотите выполнять отдельные запросы позже.
  • Запрошено Win32_USBControllerDevice список USB-устройств в моей системе (все зависимые) и извлечены их PNPDeviceID. Я пошел дальше, основываясь на порядке следования дерева устройств, чтобы назначить устройства корневому концентратору (первое возвращенное устройство, а не контроллер) и построил дерево на основе parentIdPrefix. Порядок, возвращаемый запросом, который соответствует перечислению дерева устройств через SetupDi, представляет собой каждый корневой концентратор (для которого Antecedent идентифицирует контроллер), за которым следует итерация устройств под ним, например, в моей системе:
    • Корневой концентратор первого контроллера
    • Корневой хаб второго контроллера
      • Первый концентратор под корневым концентратором второго контроллера (имеет parentIdPrefix)
        • Первое составное устройство под первым концентратором под корневым концентратором второго контроллера (PNPDeviceID совпадает с указанным выше ParentIdPrefix концентратора; имеет свой собственный ParentIdPrefix)
          • HID Device - часть составного устройства (PNPDeviceID совпадает с указанным выше ParentIDPrefix составного устройства)
        • Второе устройство под первым концентратором под корневым концентратором второго контроллера
          • HID Device часть составного устройства
      • Второй хаб под корневым хабом второго контроллера
        • Первое устройство под вторым концентратором под корневым концентратором второго контроллера
      • Третий хаб под корневым хабом второго контроллера
      • и т.п.
  • Запрошено Win32_USBController. Это дало мне подробную информацию о PNPDeviceID моих контроллеров, которые находятся наверху дерева устройств (которые были антецедентами предыдущего запроса). Используя дерево, полученное на предыдущем шаге, рекурсивно перебирает его дочерние элементы (корневые концентраторы) и их дочерние элементы (другие концентраторы) и их дочерние элементы (устройства, не являющиеся концентраторами и составные устройства) и их дочерние элементы и т. Д.
    • Получил сведения о каждом устройстве в моем дереве, обратившись к карте, сохраненной на первом шаге. (При желании можно пропустить первый шаг и запросить Win32_PnPEntityиндивидуально, используя PNPDeviceId, чтобы получить информацию на этом шаге; возможно, компромисс между процессором и памятью определяет, какой порядок лучше.)

Таким образом, Win32USBControllerDeviceзависимые элементы представляют собой полный список USB-устройств в системе (кроме самих контроллеров, которые являются предшественниками в том же запросе), и путем перекрестной ссылки на эти PNPDeviceIdпары с информацией из реестра и из других упомянутых запросов, можно построить подробную картину.

Дэниел Виддис
источник
Если бы к одному было подключено 4 идентичных сканера, как бы вы различили, какой из них был, если бы они использовались, например, для 4 разных операций?
topshot
2
@topshot PNPDeviceID уникален, пока он подключен. Невозможно будет определить, отключили ли вы один и подключили ли второй идентичный позже. На этот идентификатор также есть перекрестные ссылки в других областях, чтобы можно было надеяться определить, какая операция используется.
Дэниел Уиддис,
3
Если бы устройства имели встроенные серийные номера, то устройства можно было бы дифференцировать (для этого используются серийные номера). Серийный номер используется как «идентификатор экземпляра» PnP. Если устройство не содержит серийного номера, то идентификатор экземпляра - это, по сути, путь через дерево устройств от корня к устройству (и содержит символы '&')
Брайан
В качестве запасного варианта всегда есть наблюдение за списком устройств и отключение и повторное подключение, наблюдая за изменениями.
технофилов
14

Чтобы увидеть интересующие меня устройства, я заменил их 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,
8

Adel Hazzah в ответ дает рабочий код, Daniel Widdis - х и Недко в комментарии упомянуть , что вам нужно запросить Win32_USBControllerDevice и использовать его Dependent собственности, и Дэниел ответа дает много деталей без кода.

Вот синтез приведенного выше обсуждения, чтобы предоставить рабочий код, который перечисляет напрямую доступные свойства устройства PNP всех подключенных USB-устройств:

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

    }

}

Вам нужно будет добавить обработку исключений, если вы этого хотите. Обратитесь к ответу Дэниела, если вы хотите выяснить дерево устройств и тому подобное.

Тидей
источник
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));
    }
}
Baddack
источник
2
Также вернет дискету, возможно, USB-устройства чтения карт, возможно, Zip, Jazz и Orb-приводы
Mad Myche
Это идеальное решение для людей, которые просто хотят сопоставить понятное имя USB. Я использую этот пример для резервного копирования данных, и, поскольку буква диска меняется, мне нужно искать имя (здесь drive.VolumeLabel)
Bio42,
4

Если вы измените 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
Предложение where для поиска идентификаторов устройств, начинающихся с USB, пропускает некоторые элементы. Лучше перебирать зависимые от "Win32_USBControllerDevice"
Дэниел Виддис,
2

Вы можете найти эту ветку полезной. И вот проект кода Google, иллюстрирующий это (он P / вызывает setupapi.dll).

Дарин Димитров
источник
Вы хоть представляете, почему у класса ObjectQuery нет ссылки, хотя я использую System.Management?
Роберт
@Robert вы добавили ссылку на проект? Вы можете сделать это, щелкнув правой кнопкой мыши «Ссылки в вашем проекте»> «Добавить ссылку ...»> «Найти» и отметив «System.Management»> «OK».
Ernest
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);
                  }
             }
        }
   }
JxDarkAngel
источник
что это object valueделает?
newbieguy
Ознакомьтесь