Como se conectar a um dispositivo USB (aplicativo UWP)
No Windows, você pode escrever um aplicativo UWP que interaja com um dispositivo USB.
Este artigo descreve:
- Como usar o objeto DeviceWatcher para detectar dispositivos
- Como abrir o dispositivo para comunicação
- Como fechar o dispositivo quando terminar de usá-lo
APIs importantes
Quando você escreve um aplicativo UWP que interage com um dispositivo USB, o aplicativo pode enviar comandos de controle, obter informações do dispositivo e ler e gravar dados em massa e interromper pontos de extremidade. Antes de fazer tudo isso, você deve encontrar o dispositivo e estabelecer a conexão.
Antes de começar
- Este é o primeiro tópico de uma série. Antes de iniciar este tutorial, você deve ter criado um projeto básico do Visual Studio que pode ser estendido neste tutorial. Leia Introdução aos aplicativos UWP para obter mais informações.
- Os exemplos de código são baseados no exemplo CustomUsbDeviceAccess. Você pode baixar o exemplo completo nesta página da galeria de códigos.
- O dispositivo USB usado no tutorial é o dispositivo SuperMUTT.
- Para usar o namespace Windows.Devices.Usb para gravar um aplicativo do Windows que interage com um dispositivo USB, o dispositivo deve ter o driver Winusb.sys carregado como seu driver de função. Winusb.sys é fornecido pela Microsoft e está incluído no Windows na pasta \Windows\System32\drivers .
Fluxograma: localizando o dispositivo
Para se conectar a um dispositivo USB, primeiro você deve encontrar o dispositivo com base em vários padrões de descoberta e, em seguida, conectar-se a ele:
- Conecte-se a qualquer dispositivo USB com um GUID de interface de dispositivo específico.
- Conecte-se a um dispositivo USB com uma ID de Fornecedor e ID do Produto específicas e que tenha um GUID de interface de dispositivo específico.
- Conecte-se a um dispositivo USB com uma ID de Fornecedor e ID do Produto específicas sem conhecer o GUID da interface do dispositivo.
- Conecte-se a um dispositivo USB que tenha uma classe de dispositivo conhecida.
Principais conceitos
O que é um GUID de interface do dispositivo?
Um driver de modelo de kernel, durante sua inicialização, registra e expõe um GUID chamado GUID da interface do dispositivo. Normalmente, o aplicativo usa o GUID exposto para localizar o driver associado e seu dispositivo e, em seguida, abrir um identificador para o dispositivo. O identificador recuperado é usado para operações de leitura e gravação subsequentes.
No entanto, no caso de Winusb.sys, em vez de o driver expor o GUID da interface do dispositivo, ele pode ser fornecido de uma das duas maneiras:
- Nos descritores do SISTEMA OPERACIONAL MS do dispositivo. O fabricante do dispositivo define DeviceInterfaceGUID como uma propriedade personalizada no descritor de propriedades estendidas no dispositivo. Para obter mais detalhes, consulte o documento "Descritores de propriedades estendidas" em Descritores do sistema operacional da Microsoft.
- Se você instalou Winusb.sys manualmente por meio de um INF personalizado, o INF registrou um GUID no INF. Confira Instalação do WinUSB (Winusb.sys).
Se um GUID de interface do dispositivo for encontrado para o dispositivo, seu aplicativo UWP poderá encontrar todos os dispositivos que correspondam ao GUID da interface do dispositivo.
Como a identificação de dispositivo USB é mostrada no Windows?
Cada dispositivo USB deve ter duas informações: ID do fornecedor e ID do produto.
O USB-IF atribui esses identificadores e o fabricante do dispositivo deve expô-los no dispositivo. Então, como você pode obter essas informações?
Mesmo quando o dispositivo não tem um driver de dispositivo carregado, ou seja, o Windows o detecta como um "Dispositivo Desconhecido", você ainda pode exibir os identificadores no Gerenciador de Dispositivos no valor da propriedade ID de Hardware. Esse valor é uma combinação desses dois identificadores. Por exemplo, para o dispositivo SuperMUTT, a ID de Hardware é "USB\VID_045E&PID_F001"; A ID do fornecedor é "0x045E" e a ID do produto é "0xF001".
Se houver um INF para o dispositivo, obtenha essa cadeia de caracteres na seção Modelos .
Você pode inspecionar várias configurações do Registro. A maneira mais fácil é ver o
<HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\USB\id de hardware>
Para obter mais informações, consulte Entradas do Registro de Dispositivo USB.
A ID de hardware é usada pelo manifesto do aplicativo para identificar o dispositivo.
<Id do dispositivo="vidpid:045e f001">
Seu aplicativo UWP pode encontrar todos os dispositivos que correspondem a um fornecedor específico e ids de produto. Você pode restringir os resultados da pesquisa especificando o GUID da interface do dispositivo.
O que são classes de dispositivo USB?
A maioria dos dispositivos USB está em conformidade com as especificações de classe de dispositivo aprovadas pelo USB-IF. Usando essas especificações, dispositivos de natureza semelhante podem exibir sua funcionalidade de maneira padrão. A maior vantagem dessa abordagem é que o dispositivo pode usar um driver de classe in-box fornecido pela Microsoft ou o driver de Winusb.sys genérico.
Alguns dispositivos podem não seguir uma especificação USB-IF. Em vez disso, eles expõem a funcionalidade definida pelo fornecedor . Para esses dispositivos, o fornecedor deve fornecer o driver do dispositivo ou Winusb.sys pode ser usado.
Se um dispositivo é definido pelo fornecedor ou está em conformidade com uma classe de dispositivo, ele deve descrever essas informações relacionadas à classe de dispositivo:
- Código de classe: indica a classe de dispositivo à qual o dispositivo pertence.
- Código de subclasse: dentro da classe de dispositivo, indica a subclasse do dispositivo.
- Código de protocolo: o protocolo que o dispositivo usa.
Por exemplo, o dispositivo SuperMUTT é um dispositivo definido pelo fornecedor e as informações indicadas pelo código de classe são FF. Se o dispositivo mostrar o código de classe como FEh, o código de subclasse como 02h e o código de protocolo 00h, você poderá concluir que o dispositivo é um dispositivo de ponte IrDA compatível com a classe. Seu aplicativo UWP pode se comunicar com dispositivos que pertencem a essas classes de dispositivo:
- ActiveSync
- CdcControl
- DeviceFirmwareUpdate
- Irda
- Medida
- PalmSync
- PersonalHealthcare
- Físico
- VendorSpecific
Seu aplicativo UWP pode encontrar todos os dispositivos que correspondem a um conjunto específico de códigos de classe, subclasse e protocolo.
Obter a cadeia de caracteres AQS (Sintaxe de Consulta Avançada) para o dispositivo
Gere uma cadeia de caracteres de consulta avançada (AQS) que contém informações de identificação sobre o dispositivo que você deseja detectar. Você pode gerar a cadeia de caracteres especificando as IDs do fornecedor/produto, o GUID da interface do dispositivo ou a classe de dispositivo.
Se você quiser fornecer a ID do fornecedor/a ID do produto ou o GUID da interface do dispositivo, chame qualquer sobrecarga de GetDeviceSelector.
No exemplo do dispositivo SuperMUTT, GetDeviceSelector recupera uma cadeia de caracteres AQS semelhante a esta cadeia de caracteres:
"System.Devices.InterfaceClassGuid:="{DEE824EF-729B-4A0E-9C14-B7117D33A817}" AND System.Devices.InterfaceEnabled:=System.StructuredQueryType.Boolean#True AND System.DeviceInterface.WinUsb.UsbVendorId:=1118 AND System.DeviceInterface.WinUsb.UsbProductId:=61441"
Nota Observe que o GUID da interface do dispositivo que aparece na cadeia de caracteres não é aquele especificado. Esse GUID é o GUID da interface do dispositivo real registrado pelo Winusb.sys para aplicativos UWP.
Se você souber a classe de dispositivo do dispositivo ou seus códigos de classe, subclasse e protocolo, chame GetDeviceClassSelector para gerar a cadeia de caracteres do AQS.
Crie um objeto UsbDeviceClass especificando os valores de propriedade ClassCode, SubclassCode e ProtocolCode . Como alternativa, se você souber a classe de dispositivo do dispositivo, poderá chamar o construtor especificando uma propriedade UsbDeviceClasses específica.
Localizando o dispositivo — A maneira básica
Essa é a maneira mais simples de encontrar um dispositivo USB. Para obter detalhes, consulte Início Rápido: enumerando dispositivos comumente usados.
- Passe a cadeia de caracteres do AQS recuperada para FindAllAsync. A chamada recupera um objeto DeviceInformationCollection .
- Execute um loop pela coleção. Cada iteração obtém um objeto DeviceInformation .
- Obtenha o valor da propriedade DeviceInformation.Id . O valor da cadeia de caracteres é o caminho da instância do dispositivo. Por exemplo, "\\\\?\\USB#VID_045E&PID_078F#6&1b8ff026&0&5#{dee824ef-729b-4a0e-9c14-b7117d33a817}".
- Chame FromIdAsync passando a cadeia de caracteres da instância do dispositivo e obtenha o objeto UsbDevice . Em seguida, você pode usar o objeto UsbDevice para executar outras operações, como enviar uma transferência de controle. Quando o aplicativo terminar de usar o objeto UsbDevice , o aplicativo deverá liberá-lo chamando Close. Nota Quando o aplicativo UWP é suspenso, o dispositivo é fechado automaticamente. Para evitar o uso de um identificador obsoleto para operações futuras, o aplicativo deve liberar a referência usbDevice .
private async void OpenDevice()
{
UInt32 vid = 0x045E;
UInt32 pid = 0x0611;
string aqs = UsbDevice.GetDeviceSelector(vid, pid);
var myDevices = await Windows.Devices.Enumeration.DeviceInformation.FindAllAsync(aqs);
try
{
usbDevice = await UsbDevice.FromIdAsync(myDevices[0].Id);
}
catch (Exception exception)
{
ShowStatus(exception.Message.ToString());
}
finally
{
ShowStatus("Opened device for communication.");
}
}
Localizar o dispositivo usando DeviceWatcher
Como alternativa, você pode enumerar dispositivos dinamicamente. Em seguida, seu aplicativo poderá receber notificação se os dispositivos forem adicionados ou removidos ou se as propriedades do dispositivo forem alteradas. Para obter mais informações, consulte Como obter notificações se os dispositivos forem adicionados, removidos ou alterados.
Um objeto DeviceWatcher permite que um aplicativo detecte dispositivos dinamicamente à medida que eles são adicionados e removidos do sistema.
Crie um objeto DeviceWatcher para detectar quando o dispositivo é adicionado ou removido do sistema. Você deve criar o objeto chamando CreateWatcher e especificando a cadeia de caracteres AQS.
Implemente e registre manipuladores para eventos adicionados e removidos no objeto DeviceWatcher . Esses manipuladores de eventos são invocados quando os dispositivos (com as mesmas informações de identificação) são adicionados ou removidos do sistema.
Inicie e interrompa o objeto DeviceWatcher .
O aplicativo deve iniciar o objeto DeviceWatcher chamando Start para que ele possa começar a detectar dispositivos conforme eles são adicionados ou removidos do sistema. Por outro lado, o aplicativo deve parar o DeviceWatcher chamando Stop, quando não for mais necessário detectar dispositivos. O exemplo tem dois botões que permitem que o usuário inicie e interrompa o DeviceWatcher.
Este exemplo de código mostra como criar e iniciar um observador de dispositivos para procurar instâncias do dispositivo SuperMUTT.
void CreateSuperMuttDeviceWatcher(void)
{
UInt32 vid = 0x045E;
UInt32 pid = 0x0611;
string aqs = UsbDevice.GetDeviceSelector(vid, pid);
var superMuttWatcher = DeviceInformation.CreateWatcher(aqs);
superMuttWatcher.Added += new TypedEventHandler<DeviceWatcher, DeviceInformation>
(this.OnDeviceAdded);
superMuttWatcher.Removed += new TypedEventHandler<DeviceWatcher, DeviceInformationUpdate>
(this.OnDeviceRemoved);
superMuttWatcher.Start();
}
Abrir o dispositivo
Para abrir o dispositivo, o aplicativo deve iniciar uma operação assíncrona chamando o método estático FromIdAsync e passando o caminho da instância do dispositivo (obtido de DeviceInformation.Id). Esse resultado dessa operação é um objeto UsbDevice , que é usado para comunicação futura com o dispositivo, como a execução de transferências de dados.
Depois de terminar de usar o objeto UsbDevice , você deverá liberá-lo. Ao liberar o objeto, todas as transferências de dados pendentes são canceladas. As rotinas de retorno de chamada de conclusão para essas operações ainda são invocadas com erro cancelado ou a operação concluída.
Os aplicativos C++ devem liberar a referência usando a palavra-chave de exclusão. Os aplicativos C#/VB devem chamar o método UsbDevice.Dispose . Os aplicativos JavaScript devem chamar UsbDevice.Close.
O FromIdAsync falhará se o dispositivo estiver em uso ou não puder ser encontrado.