Scrivere un'app desktop di Windows basata sul modello WinUSB
Il modo più semplice per scrivere un'app desktop di Windows che comunica con un dispositivo USB, usa il modello WinUSB C/C++. Per questo modello è necessario un ambiente integrato con Windows Driver Kit (WDK) (con Gli strumenti di debug per Windows) e Microsoft Visual Studio (Professional o Ultimate). È possibile usare il modello come punto di partenza.
Prima di iniziare
- Per configurare l'ambiente di sviluppo integrato, installare prima Microsoft Visual Studio Ultimate 2019 o Microsoft Visual Studio Professional 2019 e quindi installare WDK. È possibile trovare informazioni su come configurare Visual Studio e WDK nella pagina di download WDK.
- Gli strumenti di debug per Windows vengono inclusi quando si installa WDK. Per altre informazioni, vedere Scaricare e installare strumenti di debug per Windows.
Creazione di un'applicazione WinUSB
Per creare un'applicazione dal modello:
Nella finestra di dialogo Nuovo progetto nella casella di ricerca nella parte superiore digitare USB.
Nel riquadro centrale selezionare Applicazione WinUSB (Universale).
Selezionare Avanti.
Immettere un nome del progetto, scegliere una posizione di salvataggio e selezionare Crea.
Gli screenshot seguenti mostrano la finestra di dialogo Nuovo progetto per il modello Applicazione WinUSB (Universal).
In questo argomento si presuppone che il nome del progetto di Visual Studio sia USB Application1.
Visual Studio crea un progetto e una soluzione. È possibile visualizzare la soluzione, il progetto e i file che appartengono al progetto nella finestra Esplora soluzioni, come illustrato nella schermata seguente. Se la finestra Esplora soluzioni non è visibile, scegliere Esplora soluzioni dal menu Visualizza. La soluzione contiene un progetto di applicazione C++ denominato USB Application1.
Il progetto USB Application1 include file di origine per l'applicazione. Se si vuole esaminare il codice sorgente dell'applicazione, è possibile aprire uno dei file visualizzati in File di origine.
Aggiungere un progetto del pacchetto driver alla soluzione. Selezionare e tenere premuto (o fare clic con il pulsante destro del mouse) la soluzione (Soluzione 'USB Application1'), quindi selezionare Aggiungi>nuovo progetto come illustrato nello screenshot seguente.
Nella finestra di dialogo Nuovo progetto nella casella di ricerca nella parte superiore digitare di nuovo USB.
Nel riquadro centrale selezionare Pacchetto driver WINUSB INF.
Selezionare Avanti.
Immettere un nome di progetto, quindi selezionare Crea.
Gli screenshot seguenti mostrano la finestra di dialogo Nuovo progetto per il modello di pacchetto driver WINUSB INF .
In questo argomento si presuppone che il nome del progetto di Visual Studio sia il pacchetto USB Application1.
Il progetto pacchetto USB Application1 contiene un file INF usato per installare il driver di Winusb.sys fornito da Microsoft come driver di dispositivo.
La Esplora soluzioni dovrebbe ora contenere entrambi i progetti, come illustrato nello screenshot seguente.
Nel file INF, USBApplication1.inf individuare questo codice:
%DeviceName% =USB_Install, USB\VID_vvvv&PID_pppp
Sostituire VID_vvvv&PID_pppp con l'ID hardware per il dispositivo. Ottenere l'ID hardware da Gestione dispositivi. In Gestione dispositivi visualizzare le proprietà del dispositivo. Nella scheda Dettagli visualizzare il valore della proprietà Ids hardware .
Nella finestra Esplora soluzioni selezionare e tenere premuto (o fare clic con il pulsante destro del mouse) Soluzione "USB Application1" (2 di 2 progetti) e scegliere Configuration Manager. Scegliere una configurazione e una piattaforma per il progetto dell'applicazione e il progetto del pacchetto. In questo esercizio si sceglie Debug e x64, come illustrato nella schermata seguente.
Compilazione, distribuzione e debug del progetto
Finora in questo esercizio è stato usato Visual Studio per creare i progetti. È quindi necessario configurare il dispositivo a cui è connesso il dispositivo. Il modello richiede che il driver Winusb sia installato come driver per il dispositivo.
L'ambiente di test e debug può avere:
Configurazione di due computer: il computer host e il computer di destinazione. Sviluppare e compilare il progetto in Visual Studio nel computer host. Il debugger viene eseguito nel computer host ed è disponibile nell'interfaccia utente di Visual Studio. Quando si esegue il test e il debug dell'applicazione, il driver viene eseguito nel computer di destinazione.
Configurazione del singolo computer: la destinazione e l'host vengono eseguite in un computer. È possibile sviluppare e compilare il progetto in Visual Studio ed eseguire il debugger e l'applicazione.
È possibile distribuire, installare, caricare e eseguire il debug dell'applicazione e il driver seguendo questa procedura:
Configurazione di due computer
- Effettuare il provisioning del computer di destinazione seguendo le istruzioni riportate in Effettuare il provisioning di un computer per la distribuzione e il test dei driver. Nota: Il provisioning crea un utente nel computer di destinazione denominato WDKRemoteUser. Al termine del provisioning, verrà visualizzato il passaggio dell'utente a WDKRemoteUser.
- Nel computer host aprire la soluzione in Visual Studio.
- In main.cpp aggiungere questa riga prima della chiamata OpenDevice.
system ("pause")
La riga causa la sospensione dell'applicazione al momento dell'avvio. Questo è utile nel debug remoto.
- In pch.h includere questa riga:
#include <cstdlib>
Questa istruzione include è necessaria per la
system()
chiamata nel passaggio precedente.Nella finestra Esplora soluzioni selezionare e tenere premuto (o fare clic con il pulsante destro del mouse) pacchetto USB Application1 e scegliere Proprietà.
Nella finestra Pagine delle proprietà del pacchetto USB Application1, nel riquadro sinistro passare alla distribuzione installazione > driver proprietà > configurazione, come illustrato nella schermata seguente.
Selezionare Rimuovi versioni precedenti del driver prima della distribuzione.
Per Nome computer remoto selezionare il nome del computer configurato per il test e il debug. In questo esercizio viene usato un computer denominato dbg-target.
Selezionare Installa/Reinstalla e Verifica. Selezionare Applica.
Nella pagina delle proprietà passare a Debug proprietà > configurazione e selezionare Strumenti di debug per Windows - Debugger remoto, come illustrato nella schermata seguente.
Selezionare Compila soluzione dal menu Compila . Visual Studio visualizza lo stato di avanzamento della compilazione nella finestra Output . Se la finestra Output non è visibile, scegliere Output dal menu Visualizza. In questo esercizio è stato creato il progetto per un sistema x64 che esegue Windows 10.
Selezionare Distribuisci soluzione dal menu Compila .
Nel computer di destinazione verranno visualizzati gli script di installazione del driver in esecuzione. I file driver vengono copiati nella cartella %Systemdrive%\drivertest\drivers nel computer di destinazione. Verificare che i file con estensione inf, cat, certificato di test e .sys e tutti gli altri file necessari siano presenti %systemdrive%\drivertest\drivers. Il dispositivo deve essere visualizzato in Gestione dispositivi senza errori.
Nel computer host verrà visualizzato questo messaggio nella finestra Output .
Deploying driver files for project
"<path>\visual studio 14\Projects\USB Application1\USB Application1 Package\USB Application1 Package.vcxproj".
Deployment may take a few minutes...
========== Build: 1 succeeded, 0 failed, 1 up-to-date, 0 skipped ==========
Per eseguire il debug dell'applicazione
Nel computer host passare a x64 > Win8.1Debug nella cartella della soluzione.
Copiare l'eseguibile dell'applicazione, UsbApplication1.exe nel computer di destinazione.
Nel computer di destinazione avviare l'applicazione.
Nel computer host selezionare Collega al processo dal menu Debug.
Nella finestra selezionare Debugger modalità utente windows (Strumenti di debug per Windows) come trasporto e il nome del computer di destinazione, in questo caso dbg-target, come qualificatore come illustrato in questa immagine.
Selezionare l'applicazione dall'elenco Processi disponibili e selezionare Collega. È ora possibile eseguire il debug usando La finestra immediata o usando le opzioni nel menu Debug .
Le istruzioni precedenti eseguino il debug dell'applicazione usando Debug Strumenti per Windows - Debugger remoto. Se si vuole usare il debugger Di Windows remoto (il debugger incluso in Visual Studio), seguire queste istruzioni:
- Nel computer di destinazione aggiungere msvsmon.exe all'elenco di app consentite tramite Firewall.
- Avviare Monitoraggio debug remoto di Visual Studio situato in C:\DriverTest\msvsmon\msvsmon.exe.
- Creare una cartella di lavoro, ad esempio C:\remotetemp.
- Copiare l'eseguibile dell'applicazione, UsbApplication1.exe nella cartella di lavoro nel computer di destinazione.
- Nel computer host, in Visual Studio fare clic con il pulsante destro del mouse sul progetto Pacchetto applicazione USB1 e scegliere Scarica progetto.
- Selezionare e tenere premuto (o fare clic con il pulsante destro del mouse) sul progetto USB Application1 , nelle proprietà del progetto espandere il nodo Proprietà di configurazione e selezionare Debug.
- Modificare debugger per avviare il debuggerdi Windows remoto.
- Modificare le impostazioni del progetto per eseguire il file eseguibile in un computer remoto seguendo le istruzioni fornite in Debug remoto di un progetto compilato in locale. Assicurarsi che le proprietà di Working Directory e Remote Command riflettano la cartella nel computer di destinazione.
- Per eseguire il debug dell'applicazione, nel menu Compila selezionare Avvia debug oppure premere F5.
Configurazione del singolo computer:
Per compilare l'applicazione e il pacchetto di installazione del driver, scegliere Compila soluzione dal menu Compilazione . Visual Studio visualizza lo stato di avanzamento della compilazione nella finestra Output . Se la finestra Output non è visibile, scegliere Output dal menu Visualizza. In questo esercizio è stato creato il progetto per un sistema x64 che esegue Windows 10.
Per visualizzare il pacchetto driver compilato, passare a Esplora risorse nella cartella USB Application1 e quindi passare a x64 > Debug > USB Application1 Package. Il pacchetto driver contiene diversi file: MyDriver.inf è un file di informazioni usato da Windows quando si installa il driver, mydriver.cat è un file di catalogo usato dal programma di installazione per verificare la firma di test per il pacchetto driver. Questi file vengono visualizzati nella schermata seguente.
Nel pacchetto non è incluso alcun file di driver. Ciò avviene perché il file INF fa riferimento al driver in box, Winusb.sys, trovato nella cartella Windows\System32.
Installare manualmente il driver. In Gestione dispositivi aggiornare il driver specificando INF nel pacchetto. Puntare al pacchetto driver che si trova nella cartella della soluzione, illustrato nella sezione precedente. Se viene visualizzato l'errore
DriverVer set to a date in the future
, impostare le impostazioni > del progetto del pacchetto INF Inf2Cat > General > Use Local Time > Yes.Selezionare e tenere premuto (o fare clic con il pulsante destro del mouse) sul progetto USB Application1 , nelle proprietà del progetto espandere il nodo Proprietà di configurazione e selezionare Debug.
Modificare debugger per avviare il debuggerdi Windows locale.
Selezionare e tenere premuto (o fare clic con il pulsante destro del mouse) sul progetto pacchetto USB Application1 e selezionare Scarica progetto.
Per eseguire il debug dell'applicazione, nel menu Compila selezionare Avvia debug oppure premere F5.
Discussione del codice modello
Il modello è un punto di partenza per l'applicazione desktop. Il progetto USB Application1 include file di origine device.cpp e main.cpp.
Il file main.cpp contiene il punto di ingresso dell'applicazione, _tmain. Il dispositivo.cpp contiene tutte le funzioni helper che aprono e chiudino l'handle al dispositivo.
Il modello include anche un file di intestazione denominato device.h. Questo file contiene definizioni per il GUID dell'interfaccia del dispositivo (illustrato più avanti) e una struttura DEVICE_DATA che archivia le informazioni ottenute dall'applicazione. Ad esempio, archivia l'handle dell'interfaccia WinUSB ottenuto da OpenDevice e usato nelle operazioni successive.
typedef struct _DEVICE_DATA {
BOOL HandlesOpen;
WINUSB_INTERFACE_HANDLE WinusbHandle;
HANDLE DeviceHandle;
TCHAR DevicePath[MAX_PATH];
} DEVICE_DATA, *PDEVICE_DATA;
Recupero del percorso dell'istanza del dispositivo: vedere RetrieveDevicePath in device.cpp
Per accedere a un dispositivo USB, l'applicazione crea un handle di file valido per il dispositivo chiamando CreateFile. Per tale chiamata, l'applicazione deve ottenere l'istanza del percorso del dispositivo. Per ottenere il percorso del dispositivo, l'app usa routine SetupAPI e specifica il GUID dell'interfaccia del dispositivo nel file INF usato per installare Winusb.sys. Device.h dichiara una costante GUID denominata GUID_DEVINTERFACE_USBApplication1. Usando queste routine, l'applicazione enumera tutti i dispositivi nella classe di interfaccia del dispositivo specificata e recupera il percorso del dispositivo del dispositivo.
HRESULT
RetrieveDevicePath(
_Out_bytecap_(BufLen) LPTSTR DevicePath,
_In_ ULONG BufLen,
_Out_opt_ PBOOL FailureDeviceNotFound
)
/*++
Routine description:
Retrieve the device path that can be used to open the WinUSB-based device.
If multiple devices have the same device interface GUID, there is no
guarantee of which one will be returned.
Arguments:
DevicePath - On successful return, the path of the device (use with CreateFile).
BufLen - The size of DevicePath's buffer, in bytes
FailureDeviceNotFound - TRUE when failure is returned due to no devices
found with the correct device interface (device not connected, driver
not installed, or device is disabled in Device Manager); FALSE
otherwise.
Return value:
HRESULT
--*/
{
BOOL bResult = FALSE;
HDEVINFO deviceInfo;
SP_DEVICE_INTERFACE_DATA interfaceData;
PSP_DEVICE_INTERFACE_DETAIL_DATA detailData = NULL;
ULONG length;
ULONG requiredLength=0;
HRESULT hr;
if (NULL != FailureDeviceNotFound) {
*FailureDeviceNotFound = FALSE;
}
//
// Enumerate all devices exposing the interface
//
deviceInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_USBApplication1,
NULL,
NULL,
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (deviceInfo == INVALID_HANDLE_VALUE) {
hr = HRESULT_FROM_WIN32(GetLastError());
return hr;
}
interfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
//
// Get the first interface (index 0) in the result set
//
bResult = SetupDiEnumDeviceInterfaces(deviceInfo,
NULL,
&GUID_DEVINTERFACE_USBApplication1,
0,
&interfaceData);
if (FALSE == bResult) {
//
// We would see this error if no devices were found
//
if (ERROR_NO_MORE_ITEMS == GetLastError() &&
NULL != FailureDeviceNotFound) {
*FailureDeviceNotFound = TRUE;
}
hr = HRESULT_FROM_WIN32(GetLastError());
SetupDiDestroyDeviceInfoList(deviceInfo);
return hr;
}
//
// Get the size of the path string
// We expect to get a failure with insufficient buffer
//
bResult = SetupDiGetDeviceInterfaceDetail(deviceInfo,
&interfaceData,
NULL,
0,
&requiredLength,
NULL);
if (FALSE == bResult && ERROR_INSUFFICIENT_BUFFER != GetLastError()) {
hr = HRESULT_FROM_WIN32(GetLastError());
SetupDiDestroyDeviceInfoList(deviceInfo);
return hr;
}
//
// Allocate temporary space for SetupDi structure
//
detailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)
LocalAlloc(LMEM_FIXED, requiredLength);
if (NULL == detailData)
{
hr = E_OUTOFMEMORY;
SetupDiDestroyDeviceInfoList(deviceInfo);
return hr;
}
detailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
length = requiredLength;
//
// Get the interface's path string
//
bResult = SetupDiGetDeviceInterfaceDetail(deviceInfo,
&interfaceData,
detailData,
length,
&requiredLength,
NULL);
if(FALSE == bResult)
{
hr = HRESULT_FROM_WIN32(GetLastError());
LocalFree(detailData);
SetupDiDestroyDeviceInfoList(deviceInfo);
return hr;
}
//
// Give path to the caller. SetupDiGetDeviceInterfaceDetail ensured
// DevicePath is NULL-terminated.
//
hr = StringCbCopy(DevicePath,
BufLen,
detailData->DevicePath);
LocalFree(detailData);
SetupDiDestroyDeviceInfoList(deviceInfo);
return hr;
}
Nella funzione precedente l'applicazione ottiene il percorso del dispositivo chiamando queste routine:
SetupDiGetClassDevs per ottenere un handle per il set di informazioni sul dispositivo, una matrice che contiene informazioni su tutti i dispositivi installati che corrispondono alla classe di interfaccia del dispositivo specificata, GUID_DEVINTERFACE_USBApplication1. Ogni elemento nella matrice denominata interfaccia del dispositivo corrisponde a un dispositivo installato e registrato con il sistema. La classe dell'interfaccia del dispositivo viene identificata passando il GUID dell'interfaccia del dispositivo definito nel file INF. La funzione restituisce un handle HDEVINFO al set di informazioni sul dispositivo.
SetupDiEnumDeviceInterfaces per enumerare le interfacce del dispositivo nel set di informazioni sul dispositivo e ottenere informazioni sull'interfaccia del dispositivo.
Questa chiamata richiede gli elementi seguenti:
Struttura del chiamante allocata SP_DEVICE_INTERFACE_DATA inizializzata con il membro cbSize impostato sulla dimensione della struttura.
Handle HDEVINFO dal passaggio 1.
GUID dell'interfaccia del dispositivo definito nel file INF.
SetupDiEnumDeviceInterfaces cerca la matrice del set di informazioni del dispositivo per l'indice specificato dell'interfaccia del dispositivo e riempie la struttura di SP_DEVICE_INTERFACE_DATA inizializzata con dati di base sull'interfaccia.
Per enumerare tutte le interfacce del dispositivo nel set di informazioni del dispositivo, chiamare SetupDiEnumDeviceInterfaces in un ciclo fino a quando la funzione restituisce FALSE e il codice di errore per l'errore è ERROR_NO_MORE_ITEMS. Il codice di errore ERROR_NO_MORE_ITEMS può essere recuperato chiamando GetLastError. Con ogni iterazione, aumentare l'indice membro.
In alternativa, è possibile chiamare SetupDiEnumDeviceInfo che enumera il set di informazioni sul dispositivo e restituisce informazioni sugli elementi dell'interfaccia del dispositivo, specificati dall'indice, in una struttura SP_DEVINFO_DATA allocata dal chiamante. È quindi possibile passare un riferimento a questa struttura nel parametro DeviceInfoData della funzione SetupDiEnumDeviceInterfaces .
SetupDiGetDeviceInterfaceDetail per ottenere dati dettagliati per l'interfaccia del dispositivo. Le informazioni vengono restituite in una struttura SP_DEVICE_INTERFACE_DETAIL_DATA . Poiché le dimensioni della struttura SP_DEVICE_INTERFACE_DETAIL_DATA variano, SetupDiGetDeviceInterfaceDetail viene chiamato due volte. La prima chiamata ottiene le dimensioni del buffer da allocare per la struttura SP_DEVICE_INTERFACE_DETAIL_DATA . La seconda chiamata riempie il buffer allocato con informazioni dettagliate sull'interfaccia.
- Chiama SetupDiGetDeviceInterfaceDetail con il parametro DeviceInterfaceDetailData impostato su NULL. La funzione restituisce le dimensioni corrette del buffer nel parametro obbligatorio . Questa chiamata ha esito negativo con il codice di errore ERROR_INSUFFICIENT_BUFFER. Questo codice di errore è previsto.
- Alloca la memoria per una struttura di SP_DEVICE_INTERFACE_DETAIL_DATA in base alle dimensioni corrette del buffer recuperate nel parametro requiredlength .
- Chiama di nuovo SetupDiGetDeviceInterfaceDetail e lo passa a un riferimento alla struttura inizializzata nel parametro DeviceInterfaceDetailData . Quando la funzione restituisce, la struttura viene riempita con informazioni dettagliate sull'interfaccia. Il percorso del dispositivo si trova nel membro DevicePath della struttura di SP_DEVICE_INTERFACE_DETAIL_DATA.
Creazione di un handle di file per il dispositivo
Vedere OpenDevice in device.cpp.
Per interagire con il dispositivo, è necessario un handle di interfaccia WinUSB per la prima interfaccia (predefinita) nel dispositivo. Il codice modello ottiene l'handle di file e l'handle dell'interfaccia WinUSB e li archivia nella struttura DEVICE_DATA.
HRESULT
OpenDevice(
_Out_ PDEVICE_DATA DeviceData,
_Out_opt_ PBOOL FailureDeviceNotFound
)
/*++
Routine description:
Open all needed handles to interact with the device.
If the device has multiple USB interfaces, this function grants access to
only the first interface.
If multiple devices have the same device interface GUID, there is no
guarantee of which one will be returned.
Arguments:
DeviceData - Struct filled in by this function. The caller should use the
WinusbHandle to interact with the device, and must pass the struct to
CloseDevice when finished.
FailureDeviceNotFound - TRUE when failure is returned due to no devices
found with the correct device interface (device not connected, driver
not installed, or device is disabled in Device Manager); FALSE
otherwise.
Return value:
HRESULT
--*/
{
HRESULT hr = S_OK;
BOOL bResult;
DeviceData->HandlesOpen = FALSE;
hr = RetrieveDevicePath(DeviceData->DevicePath,
sizeof(DeviceData->DevicePath),
FailureDeviceNotFound);
if (FAILED(hr)) {
return hr;
}
DeviceData->DeviceHandle = CreateFile(DeviceData->DevicePath,
GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_WRITE | FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL);
if (INVALID_HANDLE_VALUE == DeviceData->DeviceHandle) {
hr = HRESULT_FROM_WIN32(GetLastError());
return hr;
}
bResult = WinUsb_Initialize(DeviceData->DeviceHandle,
&DeviceData->WinusbHandle);
if (FALSE == bResult) {
hr = HRESULT_FROM_WIN32(GetLastError());
CloseHandle(DeviceData->DeviceHandle);
return hr;
}
DeviceData->HandlesOpen = TRUE;
return hr;
}
- L'app chiama CreateFile per creare un handle di file per il dispositivo specificando il percorso del dispositivo recuperato in precedenza. Usa il flag FILE_FLAG_OVERLAPPED perché WinUSB dipende da questa impostazione.
- Usando l'handle di file per il dispositivo, l'app crea un handle di interfaccia WinUSB. Le funzioni WinUSB usano questo handle per identificare il dispositivo di destinazione anziché l'handle di file. Per ottenere un handle di interfaccia WinUSB, l'app chiama WinUsb_Initialize passando l'handle di file. Usare l'handle ricevuto nelle chiamate successive per ottenere informazioni dal dispositivo e inviare richieste di I/O al dispositivo.
Rilasciare gli handle del dispositivo : vedere CloseDevice in device.cpp
Il codice modello implementa il codice per rilasciare l'handle di file e l'handle dell'interfaccia WinUSB per il dispositivo.
- CloseHandle per rilasciare l'handle creato da CreateFile, come descritto nella sezione Crea un handle file per il dispositivo di questa procedura dettagliata.
- WinUsb_Free per rilasciare l'handle dell'interfaccia WinUSB per il dispositivo, restituito da WinUsb_Initialize .
VOID
CloseDevice(
_Inout_ PDEVICE_DATA DeviceData
)
/*++
Routine description:
Perform required cleanup when the device is no longer needed.
If OpenDevice failed, do nothing.
Arguments:
DeviceData - Struct filled in by OpenDevice
Return value:
None
--*/
{
if (FALSE == DeviceData->HandlesOpen) {
//
// Called on an uninitialized DeviceData
//
return;
}
WinUsb_Free(DeviceData->WinusbHandle);
CloseHandle(DeviceData->DeviceHandle);
DeviceData->HandlesOpen = FALSE;
return;
}
Passaggi successivi
Leggere quindi questi argomenti per inviare informazioni sul dispositivo e inviare trasferimenti di dati al dispositivo:
Accedere a un dispositivo USB usando funzioni WinUSB
Informazioni sull'esecuzione di query sul dispositivo per informazioni specifiche di USB, ad esempio velocità del dispositivo, descrittori di interfaccia, endpoint correlati e pipe.
Inviare trasferimenti USB isochronous da un'app desktop WinUSB
Trasferire i dati da e verso endpoint isochronous di un dispositivo USB.