Schreiben einer Windows-Desktop-App basierend auf der WinUSB-Vorlage

Die einfachste Möglichkeit zum Schreiben einer Windows-Desktop-App, die mit einem USB-Gerät kommuniziert, ist die Verwendung der C/C++-WinUSB-Vorlage. Für diese Vorlage benötigen Sie eine integrierte Umgebung mit dem Windows Driver Kit (WDK) (mit Debugtools für Windows) und Microsoft Visual Studio (Professional oder Ultimate). Sie können die Vorlage als Ausgangspunkt verwenden.

Vorbereitung

  • Installieren Sie zum Einrichten der integrierten Entwicklungsumgebung zuerst Microsoft Visual Studio Ultimate 2019 oder Microsoft Visual Studio Professional 2019, und installieren Sie dann das WDK. Informationen zum Einrichten von Visual Studio und dem WDK finden Sie auf der WDK-Downloadseite.
  • Debugtools für Windows sind enthalten, wenn Sie das WDK installieren. Weitere Informationen finden Sie unter Herunterladen und Installieren von Debugtools für Windows.

Erstellen einer WinUSB-Anwendung

So erstellen Sie eine Anwendung aus der Vorlage:

  1. Geben Sie im Dialogfeld Neues Projekt im Suchfeld oben USB ein.

  2. Wählen Sie im mittleren Bereich WinUSB-Anwendung (Universell) aus.

  3. Wählen Sie Weiter aus.

  4. Geben Sie einen Projektnamen ein, wählen Sie einen Speicherort aus, und wählen Sie Erstellen aus.

    Die folgenden Screenshots zeigen das Dialogfeld Neues Projekt für die Vorlage WinUSB-Anwendung (Universell).

    Winusb-Vorlage neue Projekterstellung erster Bildschirm.

    Winusb-Vorlage neue Projekterstellung zweiter Bildschirm.

    In diesem Thema wird davon ausgegangen, dass der Name des Visual Studio-Projekts USB Application1 lautet.

    Visual Studio erstellt ein Projekt und eine Projektmappe. Sie können die Projektmappe, das Projekt und die Dateien, die zum Projekt gehören, im Projektmappen-Explorer Fenster sehen, wie im folgenden Screenshot gezeigt. (Wenn das fenster Projektmappen-Explorer nicht angezeigt wird, wählen Sie im Menü Ansichtdie Option Projektmappen-Explorer aus.) Die Projektmappe enthält ein C++-Anwendungsprojekt namens USB Application1.

    Projektmappen-Explorer für winusb-Vorlagen 1.

    Das USB Application1-Projekt enthält Quelldateien für die Anwendung. Wenn Sie sich den Quellcode der Anwendung ansehen möchten, können Sie jede der Dateien öffnen, die unter Quelldateien angezeigt werden.

  5. Fügen Sie der Projektmappe ein Treiberpaketprojekt hinzu. Wählen Sie die Projektmappe (oder klicken Sie mit der rechten Maustaste darauf) (Projektmappe "USB-Anwendung1") und wählen Sie dannNeues Projekthinzufügen> aus, wie im folgenden Screenshot gezeigt.

    Winusb-Vorlagenerstellung zweite Projektzugabe.

  6. Geben Sie im Dialogfeld Neues Projekt oben im Suchfeld erneut USB ein.

  7. Wählen Sie im mittleren Bereich WinUSB INF-Treiberpaket aus.

  8. Wählen Sie Weiter aus.

  9. Geben Sie einen Projektnamen ein, und wählen Sie dann Erstellen aus.

    Die folgenden Screenshots zeigen das Dialogfeld Neues Projekt für die Vorlage WinUSB INF-Treiberpaket .

    Winusb-Vorlage zweite Projekterstellung erster Bildschirm.

    zweiter Bildschirm der winusb-Vorlage zum Erstellen eines zweiten Projekts.

    In diesem Thema wird davon ausgegangen, dass der Name des Visual Studio-Projekts USB Application1 Package ist.

    Das USB Application1-Paketprojekt enthält eine INF-Datei, die verwendet wird, um den von Microsoft bereitgestellten Winusb.sys Treiber als Gerätetreiber zu installieren.

    Ihr Projektmappen-Explorer sollte nun beide Projekte enthalten, wie im folgenden Screenshot gezeigt.

    Projektmappen-Explorer für winusb-Vorlagen 2.

  10. Suchen Sie in der INF-Datei USBApplication1.inf nach folgendem Code: %DeviceName% =USB_Install, USB\VID_vvvv&PID_pppp

  11. Ersetzen Sie VID_vvvv&PID_pppp durch die Hardware-ID für Ihr Gerät. Rufen Sie die Hardware-ID von Geräte-Manager ab. Zeigen Sie in Geräte-Manager die Geräteeigenschaften an. Zeigen Sie auf der Registerkarte Details den Eigenschaftswert hardware-IDs an.

  12. Wählen Sie im fenster Projektmappen-Explorer die Option Projektmappe "USB-Anwendung1" (2 von 2 Projekten) aus, halten Sie sie gedrückt (oder klicken Sie mit der rechten Maustaste darauf), und wählen Sie Configuration Manager aus. Wählen Sie eine Konfiguration und Plattform für das Anwendungsprojekt und das Paketprojekt aus. In dieser Übung wählen Sie Debuggen und x64 aus, wie im folgenden Screenshot gezeigt.

Screenshot: Fenster

Erstellen, Bereitstellen und Debuggen des Projekts

Bisher haben Sie in dieser Übung Visual Studio verwendet, um Ihre Projekte zu erstellen. Als Nächstes müssen Sie das Gerät konfigurieren, mit dem das Gerät verbunden ist. Die Vorlage erfordert, dass der Winusb-Treiber als Treiber für Ihr Gerät installiert ist.

Ihre Test- und Debugumgebung kann Folgendes aufweisen:

  • Zwei Computereinrichtung: der Hostcomputer und der Zielcomputer. Sie entwickeln und erstellen Ihr Projekt in Visual Studio auf dem Hostcomputer. Der Debugger wird auf dem Hostcomputer ausgeführt und ist auf der Visual Studio-Benutzeroberfläche verfügbar. Wenn Sie die Anwendung testen und debuggen, wird der Treiber auf dem Zielcomputer ausgeführt.

  • Einrichtung eines einzelnen Computers: Ziel und Host werden auf einem Computer ausgeführt. Sie entwickeln und erstellen Ihr Projekt in Visual Studio und führen den Debugger und die Anwendung aus.

Sie können Ihre Anwendung und den Treiber bereitstellen, installieren, laden und debuggen, indem Sie die folgenden Schritte ausführen:

  • Einrichtung von zwei Computern

    1. Stellen Sie Ihren Zielcomputer bereit, indem Sie die Anweisungen unter Bereitstellen eines Computers für die Treiberbereitstellung und -tests befolgen. Hinweis: Die Bereitstellung erstellt einen Benutzer auf dem Zielcomputer mit dem Namen WDKRemoteUser. Nach Abschluss der Bereitstellung wird angezeigt, dass der Benutzer zu WDKRemoteUser wechselt.
    2. Öffnen Sie auf dem Hostcomputer Ihre Projektmappe in Visual Studio.
    3. Fügen Sie in Standard.cpp diese Zeile vor dem OpenDevice-Aufruf hinzu.
    system ("pause")
    

    Die Zeile bewirkt, dass die Anwendung beim Starten angehalten wird. Dies ist beim Remotedebuggen nützlich.

    1. Fügen Sie in pch.h die folgende Zeile ein:
    #include <cstdlib>
    

    Diese include-Anweisung ist für den system() Aufruf im vorherigen Schritt erforderlich.

    1. Wählen Sie im Projektmappen-Explorer Fenster USB Application1 Package aus, halten Sie es gedrückt (oder klicken Sie mit der rechten Maustaste darauf), und wählen Sie Eigenschaften aus.

    2. Navigieren Sie im fenster USB Application1 Package Property Pages im linken Bereich zu Konfigurationseigenschaften > Treiberinstallation>, wie im folgenden Screenshot gezeigt.

    3. Aktivieren Sie Vorherige Treiberversionen vor der Bereitstellung entfernen.

    4. Wählen Sie unter Remotecomputername den Namen des Computers aus, den Sie zum Testen und Debuggen konfiguriert haben. In dieser Übung verwenden wir einen Computer namens dbg-target.

    5. Wählen Sie Installieren/Neu installieren und überprüfen aus. Wählen Sie Übernehmen.

      Winusb-Vorlagenbereitstellung.

    6. Navigieren Sie auf der Eigenschaftenseite zu Debuggen von Konfigurationseigenschaften>, und wählen Sie Debugtools für Windows – Remotedebugger aus, wie im folgenden Screenshot gezeigt.

      Winusb-Vorlagen-Remotedebugger.

    7. Wählen Sie im Menü Erstellen die Option Projektmappe erstellen aus. Visual Studio zeigt den Buildfortschritt im Ausgabefenster an. (Wenn das Ausgabefenster nicht angezeigt wird, wählen Sie im Menü Ansicht die Option Ausgabe aus.) In dieser Übung haben wir das Projekt für ein x64-System erstellt, auf dem Windows 10 ausgeführt wird.

    8. Wählen Sie im Menü Erstellen die Option Lösung bereitstellen aus.

Auf dem Zielcomputer werden Treiberinstallationsskripts ausgeführt. Die Treiberdateien werden auf dem Zielcomputer in den Ordner %Systemdrive%\drivertest\drivers kopiert. Vergewissern Sie sich, dass der Ordner ".inf", ".cat", "test cert" und ".sys" sowie alle anderen erforderlichen Dateien vorhanden sind. Das Gerät muss in Geräte-Manager ohne Fehler angezeigt werden.

Auf dem Hostcomputer wird diese Meldung im Ausgabefenster angezeigt.

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 ==========

So debuggen Sie die Anwendung

  1. Navigieren Sie auf dem Hostcomputer im Projektmappenordner zu x64 > Win8.1Debug .

  2. Kopieren Sie die ausführbare Anwendung, UsbApplication1.exe auf den Zielcomputer.

  3. Starten Sie die Anwendung auf dem Zielcomputer.

  4. Wählen Sie auf dem Hostcomputer im Menü Debuggen die Option An Prozess anfügen aus.

  5. Wählen Sie im Fenster den Windows-Benutzermodusdebugger (Debugtools für Windows) als Transport und den Namen des Zielcomputers, in diesem Fall dbg-target, als Qualifizierer aus, wie in dieser Abbildung gezeigt.

    Winusb-Vorlagendebugeinstellung.

  6. Wählen Sie die Anwendung aus der Liste Der verfügbaren Prozesse aus, und wählen Sie Anfügen aus. Sie können jetzt mithilfe des Unmittelbaren Fensters oder mithilfe der Optionen im Menü Debuggen debuggen debuggen.

Die obigen Anweisungen zum Debuggen der Anwendung mithilfe von Debugtools für Windows – Remotedebugger. Wenn Sie den Windows-Remotedebugger (den Debugger, der in Visual Studio enthalten ist) verwenden möchten, führen Sie die folgenden Anweisungen aus:

  1. Fügen Sie auf dem Zielcomputer msvsmon.exe zur Liste der Apps hinzu, die über die Firewall zulässig sind.
  2. Starten Sie den Visual Studio-Remotedebugmonitor in C:\DriverTest\msvsmon\msvsmon.exe.
  3. Erstellen Sie einen Arbeitsordner, z. B. C:\remotetemp.
  4. Kopieren Sie die ausführbare Anwendungsdatei, UsbApplication1.exe in den Arbeitsordner auf dem Zielcomputer.
  5. Klicken Sie auf dem Hostcomputer in Visual Studio mit der rechten Maustaste auf das Projekt USB Application1 Package , und wählen Sie Projekt entladen aus.
  6. Wählen Sie das USB Application1-Projekt aus, und halten Sie es gedrückt (oder klicken Sie mit der rechten Maustaste darauf), erweitern Sie in Projekteigenschaften den Knoten Konfigurationseigenschaften , und wählen Sie Debuggen aus.
  7. Ändern Sie Debugger zum Starten in Windows-Remotedebugger.
  8. Ändern Sie die Projekteinstellungen, um die ausführbare Datei auf einem Remotecomputer auszuführen, indem Sie die Anweisungen unter Remotedebuggen eines lokal erstellten Projekts befolgen. Stellen Sie sicher, dass die Eigenschaften Arbeitsverzeichnis und Remotebefehl den Ordner auf dem Zielcomputer widerspiegeln.
  9. Wählen Sie zum Debuggen der Anwendung im Menü Erstellen die Option Debuggen starten aus, oder drücken Sie F5.
  • Einrichtung eines einzelnen Computers:

    1. Um Ihre Anwendung und das Treiberinstallationspaket zu erstellen, wählen Sie im Menü Erstellen die Option Projektmappeerstellen aus. Visual Studio zeigt den Buildfortschritt im Ausgabefenster an. (Wenn das Ausgabefenster nicht angezeigt wird, wählen Sie im Menü Ansicht die Option Ausgabe aus.) In dieser Übung haben wir das Projekt für ein x64-System erstellt, auf dem Windows 10 ausgeführt wird.

    2. Um das integrierte Treiberpaket anzuzeigen, navigieren Sie in Windows Explorer zu Ihrem USB Application1-Ordner, und navigieren Sie dann zu x64 > Debug > USB Application1 Package. Das Treiberpaket enthält mehrere Dateien: MyDriver.inf ist eine Informationsdatei, die Windows bei der Installation des Treibers verwendet, mydriver.cat eine Katalogdatei ist, die das Installationsprogramm verwendet, um die Testsignatur für das Treiberpaket zu überprüfen. Diese Dateien werden im folgenden Screenshot angezeigt.

      winusb-Anwendungsvorlage.

      Im Paket ist keine Treiberdatei enthalten. Dies liegt daran, dass die INF-Datei auf den im Lieferumfang enthaltenen Treiber Winusb.sys verweist, der sich im Ordner Windows\System32 befindet.

    3. Installieren Sie den Treiber manuell. Aktualisieren Sie in Geräte-Manager den Treiber, indem Sie den INF im Paket angeben. Zeigen Sie auf das Treiberpaket im Projektmappenordner, der im vorherigen Abschnitt gezeigt wird. Wenn der Fehler DriverVer set to a date in the futureangezeigt wird, legen Sie INF2Cat-Projekteinstellungen > für inf2Cat > Allgemein > Lokalzeit > ja fest.

    4. Wählen Sie das USB Application1-Projekt aus, und halten Sie es gedrückt (oder klicken Sie mit der rechten Maustaste darauf), erweitern Sie in Projekteigenschaften den Knoten Konfigurationseigenschaften , und wählen Sie Debuggen aus.

    5. Ändern Sie debugger to launch to Local Windows Debugger.

    6. Wählen Sie das USB Application1-Paketprojekt aus, und halten Sie es gedrückt (oder klicken Sie mit der rechten Maustaste darauf), und wählen Sie Projekt entladen aus.

    7. Wählen Sie zum Debuggen der Anwendung im Menü Erstellen die Option Debuggen starten aus, oder drücken Sie F5.

Vorlagencode-Diskussion

Die Vorlage ist ein Ausgangspunkt für Ihre Desktopanwendung. Das USB Application1-Projekt enthält die Quelldateien device.cpp und Standard.cpp.

Die Datei Standard.cpp enthält den Einstiegspunkt der Anwendung _tmain. Device.cpp enthält alle Hilfsfunktionen, die den Handle für das Gerät öffnen und schließen.

Die Vorlage enthält auch eine Headerdatei mit dem Namen device.h. Diese Datei enthält Definitionen für die Geräteschnittstellen-GUID (weiter unten erläutert) und eine DEVICE_DATA-Struktur, in der von der Anwendung abgerufene Informationen gespeichert werden. Beispielsweise wird das WinUSB-Schnittstellenhandle gespeichert, das von OpenDevice abgerufen und in nachfolgenden Vorgängen verwendet wird.

typedef struct _DEVICE_DATA {

    BOOL                    HandlesOpen;
    WINUSB_INTERFACE_HANDLE WinusbHandle;
    HANDLE                  DeviceHandle;
    TCHAR                   DevicePath[MAX_PATH];

} DEVICE_DATA, *PDEVICE_DATA;

Abrufen des instance Pfads für das Gerät – siehe RetrieveDevicePath in device.cpp

Um auf ein USB-Gerät zuzugreifen, erstellt die Anwendung ein gültiges Dateihandle für das Gerät, indem CreateFile aufgerufen wird. Für diesen Aufruf muss die Anwendung den Gerätepfad instance abrufen. Zum Abrufen des Gerätepfads verwendet die App SetupAPI-Routinen und gibt die Geräteschnittstellen-GUID in der INF-Datei an, die zum Installieren Winusb.sys verwendet wurde. Device.h deklariert eine GUID-Konstante namens GUID_DEVINTERFACE_USBApplication1. Mithilfe dieser Routinen listet die Anwendung alle Geräte in der angegebenen Geräteschnittstellenklasse auf und ruft den Gerätepfad des Geräts ab.

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

In der vorherigen Funktion ruft die Anwendung den Gerätepfad durch Aufrufen der folgenden Routinen ab:

  1. SetupDiGetClassDevs zum Abrufen eines Handles für den Geräteinformationssatz, ein Array, das Informationen zu allen installierten Geräten enthält, die der angegebenen Geräteschnittstellenklasse entsprechen, GUID_DEVINTERFACE_USBApplication1. Jedes Element im Array, das als Geräteschnittstelle bezeichnet wird, entspricht einem Gerät, das beim System installiert und registriert ist. Die Geräteschnittstellenklasse wird durch Übergeben der Geräteschnittstellen-GUID identifiziert, die Sie in der INF-Datei definiert haben. Die Funktion gibt ein HDEVINFO-Handle an den Geräteinformationssatz zurück.

  2. SetupDiEnumDeviceInterfaces , um die Geräteschnittstellen im Geräteinformationssatz aufzulisten und Informationen zu Ihrer Geräteschnittstelle abzurufen.

    Für diesen Aufruf sind die folgenden Elemente erforderlich:

    • Eine initialisierte aufruferseitig zugeordnete SP_DEVICE_INTERFACE_DATA-Struktur , deren cbSize-Member auf die Größe der Struktur festgelegt ist.

    • Das HDEVINFO-Handle aus Schritt 1.

    • Die GUID der Geräteschnittstelle, die Sie in der INF-Datei definiert haben.

      SetupDiEnumDeviceInterfaces sucht das Array des Geräteinformationssatzes für den angegebenen Index der Geräteschnittstelle und füllt die initialisierte SP_DEVICE_INTERFACE_DATA Struktur mit grundlegenden Daten zur Schnittstelle.

    Um alle Geräteschnittstellen im Geräteinformationssatz aufzulisten, rufen Sie SetupDiEnumDeviceInterfaces in einer Schleife auf, bis die Funktion FALSE zurückgibt und der Fehlercode für den Fehler ERROR_NO_MORE_ITEMS ist. Der ERROR_NO_MORE_ITEMS Fehlercode kann durch Aufrufen von GetLastError abgerufen werden. Erhöhen Sie mit jeder Iteration den Memberindex.

    Alternativ können Sie SetupDiEnumDeviceInfo aufrufen, das den Geräteinformationssatz auflistet und Informationen zu Geräteschnittstellenelementen zurückgibt, die durch den Index angegeben werden, in einer vom Aufrufer zugewiesenen SP_DEVINFO_DATA-Struktur . Anschließend können Sie einen Verweis auf diese Struktur im DeviceInfoData-Parameter der SetupDiEnumDeviceInterfaces-Funktion übergeben.

  3. SetupDiGetDeviceInterfaceDetail , um detaillierte Daten für die Geräteschnittstelle abzurufen. Die Informationen werden in einer SP_DEVICE_INTERFACE_DETAIL_DATA-Struktur zurückgegeben. Da die Größe der SP_DEVICE_INTERFACE_DETAIL_DATA-Struktur variiert, wird SetupDiGetDeviceInterfaceDetail zweimal aufgerufen. Der erste Aufruf ruft die Puffergröße ab, die für die SP_DEVICE_INTERFACE_DETAIL_DATA-Struktur zugewiesen werden soll. Der zweite Aufruf füllt den zugeordneten Puffer mit detaillierten Informationen zur Schnittstelle aus.

    1. Ruft SetupDiGetDeviceInterfaceDetail auf, wobei der DeviceInterfaceDetailData-Parameter auf NULL festgelegt ist. Die Funktion gibt die richtige Puffergröße im parameter requiredlength zurück. Dieser Aufruf schlägt mit dem ERROR_INSUFFICIENT_BUFFER Fehlercode fehl. Dieser Fehlercode wird erwartet.
    2. Ordnet Arbeitsspeicher für eine SP_DEVICE_INTERFACE_DETAIL_DATA-Struktur basierend auf der richtigen Puffergröße zu, die im requiredlength-Parameter abgerufen wird.
    3. Ruft SetupDiGetDeviceInterfaceDetail erneut auf und übergibt einen Verweis auf die initialisierte Struktur im DeviceInterfaceDetailData-Parameter . Wenn die Funktion zurückgibt, wird die Struktur mit detaillierten Informationen zur Schnittstelle gefüllt. Der Gerätepfad befindet sich im DevicePath-Element der SP_DEVICE_INTERFACE_DETAIL_DATA-Struktur.

Erstellen eines Dateihandles für das Gerät

Weitere Informationen finden Sie unter OpenDevice in device.cpp.

Für die Interaktion mit dem Gerät ist ein WinUSB-Schnittstellenhandle für die erste (Standard)-Schnittstelle des Geräts erforderlich. Der Vorlagencode ruft das Dateihandle und das WinUSB-Schnittstellenhandle ab und speichert sie in der DEVICE_DATA-Struktur.

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;
}
  1. Die App ruft CreateFile auf, um ein Dateihandle für das Gerät zu erstellen, indem sie den zuvor abgerufenen Gerätepfad angibt. Es wird das FILE_FLAG_OVERLAPPED-Flag verwendet, da WinUSB von dieser Einstellung abhängig ist.
  2. Mithilfe des Dateihandles für das Gerät erstellt die App ein WinUSB-Schnittstellenhandle. WinUSB-Funktionen verwenden dieses Handle, um das Zielgerät anstelle des Dateihandles zu identifizieren. Um ein WinUSB-Schnittstellenhandle abzurufen, ruft die App WinUsb_Initialize auf, indem das Dateihandle übergeben wird. Verwenden Sie das empfangene Handle in den nachfolgenden Aufrufen, um Informationen vom Gerät abzurufen und E/A-Anforderungen an das Gerät zu senden.

Freigeben der Gerätehandles– siehe CloseDevice in device.cpp

Der Vorlagencode implementiert Code, um das Dateihandle und das WinUSB-Schnittstellenhandle für das Gerät freizugeben.

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

Nächste Schritte

Lesen Sie als Nächstes die folgenden Themen, um Geräteinformationen abzurufen und Datenübertragungen an das Gerät zu senden: