Obter lista de dispositivos USB conectados

92

Como posso obter uma lista de todos os dispositivos USB conectados em um computador Windows?

Robert
fonte

Respostas:

119

Adicione uma referência a System.Management para seu projeto e, em seguida, tente algo assim:

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; }
  }
}
Adel Hazzah
fonte
14
Existe uma maneira de recuperar o nome amigável do dispositivo também? Por exemplo, quando vou para as propriedades do meu stick USB, vejo "Kingston DataTraveler 2.0 USB Device".
Robert
1
Qual é a diferença entre DeviceID e PNPDeviceID?
Shimmy Weitzhandler,
1
Quando executo o programa acima, recebo meus discos rígidos USB, meu teclado e mouse, mas não recebo minha câmera USB, meu USB A / D. Por que nem todos os meus dispositivos USB aparecem?
Curt
8
deve ser consultado "Win32_USBControllerDevice" e não "Win32_USBHub" para receber a lista de todos os dispositivos usb. Em seguida, use a propriedade "Dependent" para obter a string de endereço do dispositivo.
Nedko de
1
esta pesquisa leva 8 segundos para mim. Existe alguma possibilidade de prender as coisas?
daniel,
45

Sei que estou respondendo a uma pergunta antiga, mas acabei de fazer esse mesmo exercício e descobri um pouco mais de informações, que acho que vão contribuir muito para a discussão e ajudar qualquer pessoa que encontrar essa pergunta e ver onde o as respostas existentes ficam aquém.

A resposta aceita é aproximada e pode ser corrigida usando o comentário de Nedko . Uma compreensão mais detalhada das classes WMI envolvidas ajuda a completar o quadro.

Win32_USBHubretorna apenas Hubs USB . Isso parece óbvio em retrospectiva, mas a discussão acima não percebe. Não inclui todos os dispositivos USB possíveis, apenas aqueles que podem (pelo menos em teoria) funcionar como um hub para dispositivos adicionais. Ele perde alguns dispositivos que não são hubs (particularmente partes de dispositivos compostos).

Win32_PnPEntityinclui todos os dispositivos USB e centenas de outros dispositivos não USB. O conselho de Russel Gantman de usar uma cláusula WHERE Win32_PnPEntitypara procurar um DeviceID começando com "USB%" para filtrar a lista é útil, mas um pouco incompleto; falta dispositivos bluetooth, algumas impressoras / servidores de impressão e mouses e teclados compatíveis com HID. Eu vi "USB \%", "USBSTOR \%", "USBPRINT \%", "BTH \%", "SWD \%" e "HID \%". Win32_PnPEntityé, no entanto, uma boa referência "mestre" para pesquisar informações, uma vez que você tenha o PNPDeviceID de outras fontes.

O que descobri foi que a melhor maneira de enumerar os dispositivos USB foi por meio de consulta Win32_USBControllerDevice. Embora não forneça informações detalhadas para os dispositivos, ele enumera completamente seus dispositivos USB e fornece um par de antecedentes / dependentes PNPDeviceIDpara cada dispositivo USB (incluindo hubs, dispositivos não Hub e dispositivos compatíveis com HID) em seu sistema. Cada Dependente retornado da consulta será um Dispositivo USB. O Antecedente será o Controlador ao qual está atribuído, um dos Controladores USB retornados pela consulta Win32_USBController.

Como um bônus, parece que, nos bastidores, o WMI percorre a Árvore de Dispositivos ao responder à Win32_USBControllerDeviceconsulta, portanto, a ordem em que esses resultados são retornados pode ajudar a identificar as relações pai / filho. (Isso não está documentado e, portanto, é apenas uma suposição; use CM_Get_Parent da API SetupDi (ou Child + Sibling ) para resultados definitivos.) Como uma opção para a API SetupDi, parece que para todos os dispositivos listados em Win32_USBHubeles podem ser consultados no registro (at HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\ + PNPDeviceID) e terá um parâmetro ParentIdPrefixque será o prefixo do último campo no PNPDeviceID de seus filhos, de forma que também poderá ser usado em uma correspondência curinga para filtrar a Win32_PnPEntityconsulta.

Em meu aplicativo, fiz o seguinte:

  • (Opcional) Consultado Win32_PnPEntitye armazenado os resultados em um mapa de valor-chave (com PNPDeviceID como a chave) para recuperação posterior. Isso é opcional se você quiser fazer consultas individuais posteriormente.
  • Consultei Win32_USBControllerDeviceuma lista definitiva de dispositivos USB em meu sistema (todos os dependentes) e extraí os PNPDeviceIDs deles. Fui além, com base na ordem seguindo a árvore de dispositivos, para atribuir dispositivos ao hub raiz (o primeiro dispositivo retornado, em vez do controlador) e construí uma árvore baseada no parentIdPrefix. A ordem que a consulta retorna, que corresponde à enumeração da árvore de dispositivos via SetupDi, é cada hub raiz (para quem o Antecedente identifica o controlador), seguido por uma iteração de dispositivos sob ele, por exemplo, no meu sistema:
    • Hub raiz do primeiro controlador
    • Hub raiz do segundo controlador
      • Primeiro hub sob o hub raiz do segundo controlador (tem parentIdPrefix)
        • Primeiro dispositivo composto sob o primeiro hub no hub raiz do segundo controlador (PNPDeviceID corresponde acima do ParentIdPrefix do hub; tem seu próprio ParentIdPrefix)
          • Dispositivo HID parte do dispositivo composto (PNPDeviceID corresponde acima do ParentIDPrefix do dispositivo composto)
        • Segundo dispositivo sob o primeiro hub sob o hub raiz do segundo controlador
          • Dispositivo HID parte do dispositivo composto
      • Segundo hub sob o hub raiz do segundo controlador
        • Primeiro dispositivo sob o segundo hub sob o hub raiz do segundo controlador
      • Terceiro hub sob o hub raiz do segundo controlador
      • etc.
  • Consultado Win32_USBController. Isso me deu informações detalhadas dos PNPDeviceIDs dos meus controladores que estão no topo da árvore de dispositivos (que eram os antecedentes da consulta anterior). Usando a árvore derivada na etapa anterior, iterou recursivamente sobre seus filhos (os hubs raiz) e seus filhos (os outros hubs) e seus filhos (dispositivos não hub e dispositivos compostos) e seus filhos, etc.
    • Detalhes recuperados para cada dispositivo em minha árvore fazendo referência ao mapa armazenado na primeira etapa. (Opcionalmente, pode-se pular a primeira etapa e consultar Win32_PnPEntityindividualmente usando o PNPDeviceId para obter as informações nesta etapa; provavelmente uma compensação de CPU x memória determinando qual pedido é melhor.)

Em resumo, os Win32USBControllerDeviceDependentes são uma lista completa de Dispositivos USB em um sistema (além dos próprios Controladores, que são os Antecedentes nessa mesma consulta), e por referência cruzada desses PNPDeviceIdpares com informações do registro e de outras consultas mencionadas, uma imagem detalhada pode ser construída.

Daniel Widdis
fonte
Se um deles tivesse 4 leitores idênticos conectados, como você distinguiria qual deles se eles fossem usados ​​em 4 operações diferentes, por exemplo?
superior de
2
@topshot O PNPDeviceID é único, desde que esteja conectado. Não haveria como saber se você desconectou um e conectou outro idêntico posteriormente. Este ID também é cruzado em outras áreas para identificar qual operação é usada.
Daniel Widdis
3
Se os dispositivos tivessem números de série integrados, eles poderiam ser diferenciados (essa é a finalidade dos números de série). O número de série é usado como o "ID da instância" PnP. Se o dispositivo não contiver um número de série, o ID da instância é essencialmente o caminho através da árvore do dispositivo da raiz ao dispositivo (e contém os caracteres '&')
Brian
Como alternativa, sempre há observar a lista de dispositivos e desconectar e reconectar enquanto observa as alterações.
Technophile
14

Para ver os dispositivos que me interessavam, substituí Win32_USBHubpor Win32_PnPEntityno código de Adel Hazzah, com base neste post . Isso funciona para mim:

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; }
  }
}
ocroquete
fonte
Isso funcionou muito bem. Para facilitar a determinação de qual dispositivo você acabou de conectar, escreva-o para execução em um intervalo, escreva as entradas em um dicionário e relate quaisquer adições da última vez que você o executou.
nixkuroi
7

A resposta de Adel Hazzah fornece código funcional, os comentários de Daniel Widdis e Nedko mencionam que você precisa consultar Win32_USBControllerDevice e usar sua propriedade Dependent, e a resposta de Daniel fornece muitos detalhes sem código.

Aqui está uma síntese da discussão acima para fornecer um código de trabalho que lista as propriedades do dispositivo PNP diretamente acessíveis de todos os dispositivos USB conectados:

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

    }

}

Você precisará adicionar tratamento de exceções, se quiser. Consulte a resposta de Daniel se você quiser descobrir a árvore de dispositivos e tal.

Tydaeus
fonte
5

Este é um exemplo muito mais simples para pessoas que procuram apenas unidades USB removíveis.

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
fonte
2
Irá retornar um disquete, bem como, provavelmente, leitores de cartão USB, possível Zip, Jazz, e unidades Orb
Mad Myche
Esta é a solução ideal para pessoas que desejam apenas combinar o nome amigável de um USB. Eu uso este exemplo para backup de dados e uma vez que a letra da unidade muda, preciso procurar o nome (aqui unidade.VolumeLabel)
Bio42
3

Se você alterar o ManagementObjectSearcher para o seguinte:

ManagementObjectSearcher searcher = 
       new ManagementObjectSearcher("root\\CIMV2", 
       @"SELECT * FROM Win32_PnPEntity where DeviceID Like ""USB%"""); 

Portanto, o "GetUSBDevices () se parece com isto"

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

}

Seus resultados serão limitados a dispositivos USB (ao contrário de todos os tipos em seu sistema)

Russell Gantman
fonte
1
A cláusula where ao procurar deviceIDs começando com USB perde alguns itens. É melhor iterar os dependentes de "Win32_USBControllerDevice"
Daniel Widdis
2

Você pode achar este tópico útil. E aqui está um projeto de código do Google exemplificando isso (ele P / Invoca em setupapi.dll).

Darin Dimitrov
fonte
Você tem alguma ideia de por que a classe ObjectQuery não tem uma referência, embora eu esteja usando System.Management?
Robert
@Robert você adicionou a referência ao projeto? Você pode fazer isso clicando com o botão direito do mouse em Referências em seu projeto> Adicionar Referência ...> Pesquisar e verificar 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
fonte
o que isso object valuefaz?
newbieguy
Faça um tour pelas outras propriedades disponíveis no disco e salve seu valor no valor do objeto
JxDarkAngel