So schreiben Sie Ihren ersten USB-Clienttreiber (UMDF)

In diesem Artikel verwenden Sie die Vorlage Benutzermodustreiber, USB (UMDF V2), die mit Microsoft Visual Studio 2022 bereitgestellt wird, um einen umDF-basierten Clienttreiber zu schreiben. Nach dem Erstellen und Installieren des Clienttreibers zeigen Sie den Clienttreiber in Geräte-Manager an und zeigen die Treiberausgabe in einem Debugger an.

UMDF (in diesem Artikel als Framework bezeichnet) basiert auf dem Komponentenobjektmodell (COM). Jedes Frameworkobjekt muss IUnknown und die zugehörigen Methoden QueryInterface, AddRef und Release standardmäßig implementieren. Die AddRef- und Release-Methoden verwalten die Lebensdauer des Objekts, sodass der Clienttreiber die Verweisanzahl nicht beibehalten muss. Mit der QueryInterface-Methode kann der Clienttreiber Schnittstellenzeiger auf andere Frameworkobjekte im WDF-Objektmodell (Windows Driver Frameworks) abrufen. Framework-Objekte führen komplizierte Treiberaufgaben aus und interagieren mit Windows. Bestimmte Frameworkobjekte machen Schnittstellen verfügbar, die es einem Clienttreiber ermöglichen, mit dem Framework zu interagieren.

Ein UMDF-basierter Clienttreiber wird als prozessinterner COM-Server (DLL) implementiert, und C++ ist die bevorzugte Sprache zum Schreiben eines Clienttreibers für ein USB-Gerät. In der Regel implementiert der Clienttreiber mehrere Schnittstellen, die vom Framework verfügbar gemacht werden. Dieser Artikel bezieht sich auf eine vom Clienttreiber definierte Klasse, die Frameworkschnittstellen als Rückrufklasse implementiert. Nachdem diese Klassen instanziiert wurden, werden die resultierenden Rückrufobjekte mit bestimmten Frameworkobjekten verknüpft. Diese Partnerschaft gibt dem Clienttreiber die Möglichkeit, auf geräte- oder systembezogene Ereignisse zu reagieren, die vom Framework gemeldet werden. Wenn Windows das Framework über bestimmte Ereignisse benachrichtigt, ruft das Framework den Rückruf des Clienttreibers auf, sofern eins verfügbar ist. Andernfalls fährt das Framework mit der Standardverarbeitung des Ereignisses fort. Der Vorlagencode definiert Treiber-, Geräte- und Warteschlangenrückrufklassen.

Eine Erklärung zum von der Vorlage generierten Quellcode finden Sie unter Grundlegendes zum UMDF-Vorlagencode für den USB-Clienttreiber.

Vorbereitung

Zum Entwickeln, Debuggen und Installieren eines Benutzermodustreibers benötigen Sie zwei Computer:

  • Ein Hostcomputer, auf dem Windows 10 oder eine höhere Version des Windows-Betriebssystems ausgeführt wird. Der Hostcomputer ist Ihre Entwicklungsumgebung, in der Sie Ihren Treiber schreiben und debuggen.
  • Ein Zielcomputer, auf dem die Version des Betriebssystems ausgeführt wird, auf dem Sie Ihren Treiber testen möchten, z. B. Windows 11 Version 22H2. Der Zielcomputer verfügt über den Benutzermodustreiber, den Sie debuggen möchten, und über einen der Debugger.

In einigen Fällen, auf denen der Host und der Zielcomputer dieselbe Windows-Version ausführen, kann nur ein Computer Windows 10 oder eine höhere Version von Windows ausgeführt werden. In diesem Artikel wird davon ausgegangen, dass Sie zwei Computer zum Entwickeln, Debuggen und Installieren Ihres Benutzermodustreibers verwenden.

Bevor Sie beginnen, stellen Sie sicher, dass Sie die folgenden Anforderungen erfüllen:

Softwareanforderungen

  • Ihr Hostcomputer verfügt über Visual Studio 2022.

  • Ihr Hostcomputer verfügt über das neueste Windows Driver Kit (WDK) für Windows 11, Version 22H2.

    Das Kit enthält Header, Bibliotheken, Tools, Dokumentation und die Debugtools, die zum Entwickeln, Erstellen und Debuggen eines USB-Clienttreibers erforderlich sind. Sie können die neueste Version des WDK unter Abrufen des WDK abrufen.

  • Ihr Hostcomputer verfügt über die neueste Version von Debugtools für Windows. Sie können die neueste Version vom WDK abrufen oder Debugtools für Windows herunterladen und installieren.

  • Wenn Sie zwei Computer verwenden, müssen Sie die Host- und Zielcomputer für das Debuggen im Benutzermodus konfigurieren. Weitere Informationen finden Sie unter Einrichten User-Mode Debuggen in Visual Studio.

Hardwareanforderungen

Rufen Sie ein USB-Gerät ab, für das Sie den Clienttreiber schreiben. In den meisten Fällen erhalten Sie ein USB-Gerät und dessen Hardwarespezifikation. In der Spezifikation werden die Gerätefunktionen und die unterstützten Anbieterbefehle beschrieben. Verwenden Sie die Spezifikation, um die Funktionalität des USB-Treibers und die zugehörigen Entwurfsentscheidungen zu bestimmen.

Wenn Sie noch nicht mit der Entwicklung von USB-Treibern vertraut sind, verwenden Sie das OSR USB FX2-Lernkit , um USB-Beispiele zu untersuchen, die im WDK enthalten sind. Es enthält das USB FX2-Gerät und alle erforderlichen Hardwarespezifikationen, um einen Clienttreiber zu implementieren.

Schritt 1: Generieren des Treibercodes

Ausführliche Informationen zum Schreiben von UMDF-Treibercode finden Sie unter Schreiben eines UMDF-Treibers basierend auf einer Vorlage.

Wählen Sie für USB-spezifischen Code die folgenden Optionen in Visual Studio 2022 aus.

  1. Geben Sie im Dialogfeld Neues Projekt im Suchfeld oben USB ein.
  2. Wählen Sie im mittleren Bereich Benutzermodustreiber, USB (UMDF V2) 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 Usb-User-Mode-Treibervorlage .

Screenshot der Visual Studio-Projekterstellungsoptionen.

Screenshot des Visual Studio-Bildschirms

In diesem Artikel wird davon ausgegangen, dass der Name des Projekts MyUSBDriver_UMDF_ ist. Er enthält die folgenden Dateien:

Dateien BESCHREIBUNG
Driver.h; Driver.c Enthält die Implementierung des Einstiegspunkts des Treibermoduls. DriverEntry - und WDFDRIVER-bezogene Funktionen und Rückrufe.
Device.h; Device.c Funktionen und Rückrufe im Zusammenhang mit WDFDEVICE und WDFUSBDEVICE.
Queue.h; Queue.c WDFQUEUE-bezogene Funktionen und Rückrufe.
Trace.h Definiert die Geräteschnittstellen-GUID. Außerdem werden Ablaufverfolgungsfunktionen und Makros deklariert.
<Projektname.inf> INF-Datei, die zum Installieren des Clienttreibers auf dem Zielcomputer erforderlich ist.

Schritt 2: Hinzufügen von Informationen zu Ihrem Gerät

Bevor Sie den Treiber erstellen, müssen Sie Informationen zu Ihrem Gerät hinzufügen, insbesondere die Hardware-ID. So geben Sie die Hardware-ID an:

  1. Klicken Sie im Projektmappen-Explorer Fenster mit der rechten Maustaste auf MyUSBDriver_UMDF_, und wählen Sie Eigenschaften aus.
  2. Navigieren Sie im Fenster MyUSBDriver_UMDF_ Eigenschaftenseiten zu Konfigurationseigenschaften > Treiberinstallation>, wie hier gezeigt. Screenshot des Visual Studio 2022-Eigenschaftenseitenfensters.
  3. Aktivieren Sie Vorherige Treiberversionen vor der Bereitstellung entfernen.
  4. Wählen Sie unter Zielgerätname den Namen des Computers aus, den Sie zum Testen und Debuggen konfiguriert haben.
  5. Wählen Sie Hardware-ID-Treiberupdate aus, und geben Sie die Hardware-ID für Ihren Treiber ein. In dieser Übung lautet die Hardware-ID Root\MyUSBDriver_UMDF_. Klicken Sie auf OK.

Hinweis

In dieser Übung identifiziert die Hardware-ID kein echtes Hardwarestück. Es identifiziert ein imaginäres Gerät, das einen Platz in der Gerätestruktur als untergeordnetes Element des Stammknotens erhält. Wählen Sie für echte Hardware nicht Hardware-ID-Treiberupdate aus. Wählen Sie stattdessen Installieren und Überprüfen aus. Die Hardware-ID wird in der INF-Datei (Driver's Information) angezeigt. Navigieren Sie im Projektmappen-Explorer Fenster zu MyUSBDriver_UMDF_ > Treiberdateien, und doppelklicken Sie auf MyUSBDriver_UMDF_.inf. Die Hardware-ID befindet sich unter [Standard.NT$ARCH$].

Alle UMDF-basierten USB-Clienttreiber erfordern zwei von Microsoft bereitgestellte Treiber, den Reflektor und WinUSB.

  • Reflektor: Wenn Ihr Treiber erfolgreich geladen wird, wird der Reflektor als oberster Treiber im Kernelmodusstapel geladen. Der Reflektor muss der oberste Treiber im Kernelmodusstapel sein. Um diese Anforderung zu erfüllen, gibt die INF-Datei der Vorlage den Reflektor als Dienst und WinUSB als Treiber mit niedrigerem Filter im INF an:

    [MyDevice_Install.NT.Services]
    AddService=WUDFRd,0x000001fa,WUDFRD_ServiceInstall  ; flag 0x2 sets this as the service for the device
    AddService=WinUsb,0x000001f8,WinUsb_ServiceInstall  ; this service is installed because its a filter.
    
  • WinUSB: Das Installationspaket muss Coinstaller für Winusb.sys enthalten, da WinUSB für den Clienttreiber das Gateway zum Kernelmodus-USB-Treiberstapel ist. Eine weitere Komponente, die geladen wird, ist eine Benutzermodus-DLL mit dem Namen WinUsb.dll im Hostprozess des Clienttreibers (Wudfhost.exe). Winusb.dll macht WinUSB-Funktionen verfügbar, die den Kommunikationsprozess zwischen dem Clienttreiber und WinUSB vereinfachen.

Schritt 3: Erstellen des USB-Clienttreibercodes

So erstellen Sie Ihren Treiber:

  1. Öffnen Sie das Treiberprojekt oder die Projektmappe in Visual Studio 2022.
  2. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf die Projektmappe, und wählen Sie Configuration Manager aus.
  3. Wählen Sie auf der Configuration Manager Ihre aktive Projektmappenkonfiguration (z. B. Debuggen oder Release) und Ihre Active Solution Platform (z. B. x64) aus, die dem Typ des builds entsprechen, an dem Sie interessiert sind.
  4. Vergewissern Sie sich, dass die GUID Ihrer Geräteschnittstelle während des gesamten Projekts korrekt ist.
    • Die Geräteschnittstellen-GUID ist in Trace.h definiert und wird in Device.c referenziert MyUSBDriverUMDFCreateDevice . Wenn Sie Ihr Projekt mit dem Namen MyUSBDriver_UMDF_ erstellen, definiert Visual Studio 2022 die Geräteschnittstellen-GUID mit dem NamenGUID_DEVINTERFACE_MyUSBDriver_UMDF_, ruft jedoch mit dem falschen Parameter &GUID_DEVINTERFACE_MyUSBDriverUMDFaufWdfDeviceCreateDeviceInterface. Ersetzen Sie den falschen Parameter durch den in Trace.h definierten Namen, um sicherzustellen, dass der Treiber ordnungsgemäß erstellt wird.
  5. Klicken Sie im Menü Build (Erstellen) auf Build Solution (Projektmappe erstellen).

Weitere Informationen finden Sie unter Erstellen eines Treibers.

Schritt 4: Konfigurieren eines Computers zum Testen und Debuggen

Zum Testen und Debuggen eines Treibers führen Sie den Debugger auf dem Hostcomputer und den Treiber auf dem Zielcomputer aus. Bisher haben Sie Visual Studio auf dem Hostcomputer verwendet, um einen Treiber zu erstellen. Als Nächstes müssen Sie einen Zielcomputer konfigurieren. Befolgen Sie zum Konfigurieren eines Zielcomputers die Anweisungen unter Bereitstellen eines Computers für die Treiberbereitstellung und -tests.

Schritt 5: Aktivieren der Ablaufverfolgung für kerneldebuggen

Der Vorlagencode enthält mehrere Ablaufverfolgungsmeldungen (TraceEvents), mit denen Sie Funktionsaufrufe nachverfolgen können. Alle Funktionen im Quellcode enthalten Ablaufverfolgungsmeldungen, die den Eintrag und das Beenden einer Routine markieren. Bei Fehlern enthält die Ablaufverfolgungsmeldung den Fehlercode und eine aussagekräftige Zeichenfolge. Da die WPP-Ablaufverfolgung für Ihr Treiberprojekt aktiviert ist, enthält die während des Buildvorgangs erstellte PDB-Symboldatei Anweisungen zur Formatierung von Ablaufverfolgungsmeldungen. Wenn Sie den Host und die Zielcomputer für die WPP-Ablaufverfolgung konfigurieren, kann Ihr Treiber Ablaufverfolgungsmeldungen an eine Datei oder den Debugger senden.

So konfigurieren Sie Ihren Hostcomputer für die WPP-Ablaufverfolgung

  1. Erstellen Sie TMF-Dateien (Trace Message Format), indem Sie Anweisungen zur Formatierung von Ablaufverfolgungsnachrichten aus der PDB-Symboldatei extrahieren.

    Sie können Tracepdb.exe verwenden, um TMF-Dateien zu erstellen. Das Tool befindet sich im <Installationsordner>Windows Kits\10\bin\<architecture> des WDK. Mit dem folgenden Befehl werden TMF-Dateien für das Treiberprojekt erstellt.

    tracepdb -f <PDBFiles> -p <TMFDirectory>
    

    Die Option -f gibt den Speicherort und den Namen der PDB-Symboldatei an. Die Option -p gibt den Speicherort für die TMF-Dateien an, die von Tracepdb erstellt werden. Weitere Informationen finden Sie unter Tracepdb-Befehle.

    Es gibt drei Dateien am angegebenen Speicherort, eine pro C-Codedatei im Projekt. Sie erhalten GUID-Dateinamen.

  2. Geben Sie im Debugger die folgenden Befehle ein:

    .load Wmitrace
    .chain
    !wmitrace.searchpath + <TMF file location>
    

Folgende Befehle:

  • Laden Sie die Wmitrace.dll-Erweiterung.
  • Überprüft, ob die Debuggererweiterung geladen ist.
  • Fügt dem Suchpfad der Debuggererweiterung den Speicherort der TMF-Dateien hinzu.

Die Ausgabe sieht ungefähr wie folgt aus:

Trace Format search path is: 'C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE;c:\drivers\tmf

So konfigurieren Sie Ihren Zielcomputer für die WPP-Ablaufverfolgung

  1. Stellen Sie sicher, dass Sie das Tracelog-Tool auf Ihrem Zielcomputer haben. Das Tool befindet sich im <Ordner install_folder>Windows Kits\10\Tools\<arch> des WDK. Weitere Informationen finden Sie unter Ablaufverfolgungsbefehlsyntax.

  2. Öffnen Sie ein Befehlsfenster , und führen Sie als Administrator aus.

  3. Geben Sie folgenden Befehl ein:

    tracelog -start MyTrace -guid \#c918ee71-68c7-4140-8f7d-c907abbcb05d -flag 0xFFFF -level 7-rt -kd
    

Der Befehl startet eine Ablaufverfolgungssitzung mit dem Namen MyTrace.

Das guid-Argument gibt die GUID des Ablaufverfolgungsanbieters an, bei dem es sich um den Clienttreiber handelt. Sie können die GUID aus Trace.h im Visual Studio 2022-Projekt abrufen. Als weitere Option können Sie den folgenden Befehl eingeben und die GUID in einer GUID-Datei angeben. Die Datei enthält die GUID im Bindestrichformat:

tracelog -start MyTrace -guid c:\\drivers\\Provider.guid -flag 0xFFFF -level 7-rt -kd

Sie können die Ablaufverfolgungssitzung beenden, indem Sie den folgenden Befehl eingeben:

tracelog -stop MyTrace

Schritt 6: Bereitstellen des Treibers auf dem Zielcomputer

  1. Klicken Sie im fenster Projektmappen-Explorer mit der rechten Maustaste auf den Projektnamen (MyUSBDriver_UMDF_), und wählen Sie Eigenschaften aus.
  2. Navigieren Sie im linken Bereich zu Konfigurationseigenschaften > Treiberinstallationsbereitstellung>.
  3. Geben Sie unter Zielgerätname den Namen des Zielcomputers an.
  4. Wählen Sie Installieren/Neu installieren und überprüfen aus.
  5. Klicken Sie auf OK.
  6. Wählen Sie im Menü Debuggen die Option Debuggen starten aus, oder drücken Sie F5 auf der Tastatur.

Hinweis

Geben Sie die Hardware-ID Ihres Geräts nicht unter Hardware-ID-Treiberupdate an. Die Hardware-ID darf nur in der INF-Datei (Information) Ihres Treibers angegeben werden.

Schritt 7: Anzeigen des Treibers in Geräte-Manager

  1. Geben Sie den folgenden Befehl ein, um Geräte-Manager zu öffnen.

    devmgmt
    
  2. Vergewissern Sie sich, dass Geräte-Manager den folgenden Knoten anzeigt.

    USB-Gerät

    MyUSBDriver_UMDF_Device

Schritt 8: Anzeigen der Ausgabe im Debugger

Vergewissern Sie sich, dass Ablaufverfolgungsmeldungen im Debugger-Direktfenster auf dem Hostcomputer angezeigt werden.

Die Ausgabe sollte ähnlich der Folgenden aussehen:

[0]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyDevice::OnPrepareHardware Entry
[0]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyDevice::OnPrepareHardware Exit
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyDevice::CreateInstanceAndInitialize Entry
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyDevice::Initialize Entry
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyDevice::Initialize Exit
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyDevice::CreateInstanceAndInitialize Exit
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyDevice::Configure Entry
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyIoQueue::CreateInstanceAndInitialize Entry
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyIoQueue::Initialize Entry
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyIoQueue::Initialize Exit
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyIoQueue::CreateInstanceAndInitialize Exit
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyDevice::Configure Exit

Hinweise

Sehen wir uns an, wie das Framework und der Clienttreiber zusammenarbeiten, um mit Windows zu interagieren und Anforderungen zu behandeln, die an das USB-Gerät gesendet werden. Diese Abbildung zeigt die Module, die für einen UMDF-basierten USB-Clienttreiber in das System geladen werden.

Diagramm der Clienttreiberarchitektur im Benutzermodus.

Der Zweck der einzelnen Module wird hier beschrieben:

  • Anwendung : Ein Benutzermodusprozess, der E/A-Anforderungen für die Kommunikation mit dem USB-Gerät ausgibt.
  • E/A-Manager: Eine Windows-Komponente, die E/A-Anforderungspakete (IRPs) erstellt, um die empfangenen Anwendungsanforderungen darzustellen, und diese an den oberen Rand des Kernelmodusgerätestapels für das Zielgerät weiterleitet.
  • Reflektor – ein von Microsoft bereitgestellter Kernelmodustreiber, der oben auf dem Kernelmodusgerätestapel (WUDFRd.sys) installiert ist. Der Reflektor leitet IRPs, die vom E/A-Manager empfangen werden, an den Hostprozess des Clienttreibers um. Beim Empfang der Anforderung behandeln das Framework und der Clienttreiber die Anforderung.
  • Hostprozess – der Prozess, in dem der Benutzermodustreiber ausgeführt wird (Wudfhost.exe). Außerdem werden das Framework und der E/A-Verteiler gehostet.
  • Clienttreiber – der Funktionstreiber für den Benutzermodus für das USB-Gerät.
  • UMDF – das Frameworkmodul, das die meisten Interaktionen mit Windows im Auftrag des Clienttreibers verarbeitet. Es macht die Gerätetreiberschnittstellen (Device Driver Interfaces, DDIs) im Benutzermodus verfügbar, die der Clienttreiber zum Ausführen allgemeiner Treiberaufgaben verwenden kann.
  • Dispatcher– Mechanismus, der im Hostprozess ausgeführt wird; bestimmt, wie eine Anforderung an den Kernelmodus weitergeleitet wird, nachdem sie von Benutzermodustreibern verarbeitet wurde und den unteren Rand des Benutzermodusstapels erreicht hat. In der Abbildung leitet der Dispatcher die Anforderung an die Benutzermodus-DLL weiter, Winusb.dll.
  • Winusb.dll – eine von Microsoft bereitgestellte Benutzermodus-DLL, die WinUSB-Funktionen verfügbar macht, die den Kommunikationsprozess zwischen dem Clienttreiber und WinUSB (Winusb.sys, geladen im Kernelmodus) vereinfachen.
  • Winusb.sys – ein von Microsoft bereitgestellter Treiber, der von allen UMDF-Clienttreibern für USB-Geräte benötigt wird. Der Treiber muss unterhalb des Reflektors installiert sein und fungiert als Gateway zum USB-Treiberstapel im Kernelmodus. Weitere Informationen finden Sie unter WinUSB.
  • USB-Treiberstapel – eine Reihe von Treibern, die von Microsoft bereitgestellt werden und die Kommunikation auf Protokollebene mit dem USB-Gerät verarbeiten. Weitere Informationen finden Sie unter USB-hostseitige Treiber in Windows.

Wenn eine Anwendung eine Anforderung für den USB-Treiberstapel stellt, sendet der Windows E/A-Manager die Anforderung an den Reflektor, der sie im Benutzermodus an den Clienttreiber weitergibt. Der Clienttreiber verarbeitet die Anforderung durch Aufrufen bestimmter UMDF-Methoden, die intern WinUSB-Funktionen aufrufen, um die Anforderung an WinUSB zu senden. Beim Empfang der Anforderung verarbeitet WinUSB entweder die Anforderung oder leitet sie an den USB-Treiberstapel weiter.