Freigeben über


Schreiben Ihres ersten USB-Client-Treibers (UMDF)

In diesem Artikel verwenden Sie die User Mode Driver, USB (UMDF V2)-Vorlage, die mit Microsoft Visual Studio 2022 geliefert wird, um einen User Mode Driver Framework (UMDF)-basierten Client-Treiber zu schreiben. Nachdem Sie den Client-Treiber erstellt und installiert haben, werden Sie den Client-Treiber im Geräte-Manager anzeigen und die Treiberausgabe in einem Debugger betrachten.

UMDF (in diesem Artikel als Framework bezeichnet) basiert auf dem Component Object Model (COM). Jedes Framework-Objekt muss standardmäßig IUnknown und seine Methoden, QueryInterface, AddRef und Release, implementieren. Die Methoden AddRef und Release verwalten die Lebensdauer des Objekts, sodass der Client-Treiber die Anzahl der Referenzen nicht verwalten muss. Die Methode QueryInterface ermöglicht es dem Client-Treiber, Schnittstellenzeiger auf andere Framework-Objekte im Objektmodell des Windows Driver Frameworks (WDF) zu erhalten. Framework-Objekte führen komplizierte Treiberaufgaben aus und interagieren mit Windows. Bestimmte Framework-Objekte stellen Schnittstellen zur Verfügung, die es einem Client-Treiber ermöglichen, mit dem Framework zu interagieren.

Ein UMDF-basierter Client-Treiber wird als prozessinterner COM-Server (DLL) implementiert, und C++ ist die bevorzugte Sprache zum Schreiben eines Client-Treibers für ein USB-Gerät. In der Regel implementiert der Client-Treiber mehrere vom Framework bereitgestellte Schnittstellen. In diesem Artikel wird eine vom Client-Treiber definierte Klasse, die die Schnittstellen des Frameworks implementiert, als Callback-Klasse bezeichnet. Nach der Instanziierung dieser Klassen werden die resultierenden Callback-Objekte mit bestimmten Objekten des Frameworks verknüpft. Diese Partnerschaft gibt dem Client-Treiber die Möglichkeit, auf geräte- oder systembezogene Ereignisse zu reagieren, die vom Framework geliefert werden. Wenn Windows das Framework über bestimmte Ereignisse benachrichtigt, ruft das Framework den Callback des Client-Treibers auf, sofern ein solcher vorhanden ist. Andernfalls fährt das Framework mit der Standardverarbeitung des Ereignisses fort. Der Code der Vorlage definiert Treiber-, Geräte- und Warteschlangen-Callback-Klassen.

Eine Erklärung des von der Vorlage generierten Quellcodes finden Sie unter Verständnis des UMDF-Vorlagencodes für den USB Client-Treiber.

Vor der Installation

Für die Entwicklung, das Debugging und die Installation eines Benutzermodustreibers benötigen Sie zwei Computer:

  • Einen Host-Computer, auf dem Windows 10 oder eine neuere Version des Windows-Betriebssystems ausgeführt wird. Der Host-Computer ist Ihre Entwicklungsumgebung, in der Sie Ihren Treiber schreiben und debuggen.
  • Einen Zielcomputer, auf dem die Version des Betriebssystems ausgeführt wird, unter der 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 einen der Debugger.

In einigen Fällen, in denen der Host- und der Zielcomputer dieselbe Version von Windows ausführen, können Sie auch nur einen Computer mit Windows 10 oder einer neueren Version von Windows einsetzen. Dieser Artikel geht davon aus, dass Sie zwei Computer für die Entwicklung, das Debugging und die Installation Ihres Benutzermodustreibers verwenden.

Bevor Sie beginnen, sollten Sie sicherstellen, dass Sie die folgenden Voraussetzungen erfüllen:

Softwareanforderungen

  • Auf Ihrem Host-Computer ist Visual Studio 2022 installiert.

  • Ihr Host-Computer 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 Debugging-Tools, die zum Entwickeln, Erstellen und Debuggen eines USB Client-Treibers erforderlich sind. Die neueste Version des WDK erhalten Sie unter So erhalten Sie das WDK.

  • Ihr Host-Computer verfügt über die neueste Version der Debugging Tools für Windows. Sie können die neueste Version aus dem WDK beziehen oder Sie können Die Debugging Tools für Windows herunterladen und installieren.

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

Hardwareanforderungen

Besorgen Sie sich ein USB-Gerät, für das Sie den Client-Treiber schreiben werden. In den meisten Fällen erhalten Sie ein USB-Gerät und dessen Hardwarespezifikation. Die Spezifikation beschreibt die Fähigkeiten des Geräts und die unterstützten Herstellerbefehle. Verwenden Sie die Spezifikation, um die Funktionalität des USB-Treibers und die damit verbundenen Designentscheidungen zu bestimmen.

Wenn Sie neu in der Entwicklung von USB-Treibern sind, verwenden Sie das OSR USB FX2 Learning Kit, um die im WDK enthaltenen USB-Beispiele zu studieren. Es enthält das USB FX2-Gerät und alle erforderlichen Hardwarespezifikationen, um einen Client-Treiber zu implementieren.

Schritt 1: Generieren des Treiber-Codes

Einzelheiten zum Schreiben von UMDF-Treibercode finden Sie unter Schreiben eines UMDF-Treibers auf der Grundlage einer Vorlage.

Für USB-spezifischen Code wählen Sie in Visual Studio 2022 die folgenden Optionen

  1. Geben Sie im Dialogfeld Neues Projekt im oberen Suchfeld USB. ein.
  2. Wählen Sie im mittleren Bereich Benutzermodus-Treiber, USB (UMDF V2).
  3. Wählen Sie Weiter aus.
  4. Geben Sie einen Projektnamen ein, wählen Sie einen Speicherort, und wählen Sie Erstellen.

Die folgenden Screenshots zeigen das Dialogfeld Neues Projekt für die Vorlage Benutzermodus-Treiber.

Screenshot der Visual Studio-Optionen zum Erstellen eines Projekts.

Screenshot der Visual Studio-Seite zum Erstellen von Projekten.

Dieser Artikel geht davon aus, dass der Name des Projekts MyUSBDriver_UMDF_ lautet. Er enthält die folgenden Dateien:

Dateien Beschreibung
Driver.h; Driver.c Enthält die Implementierung des Einstiegspunkts des Treibermoduls. DriverEntry und WDFDRIVER bezogene Funktionalität und Callbacks.
Device.h; Device.c WDFDEVICE und WDFUSBDEVICE bezogene Funktionen und Callbacks.
Queue.h; Queue.c WDFQUEUE-bezogene Funktionen und Callbacks.
Trace.h Definiert die GUID der Geräteschnittstelle. Außerdem werden Tracing-Funktionen und Makros deklariert.
<Projektname>.inf INF-Datei, die für die Installation des Client-Treibers auf dem Zielcomputer erforderlich ist.

Schritt 2: Hinzufügen von Informationen über Ihr Gerät

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

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

Hinweis

In dieser Übung identifiziert die Hardware-ID kein reales Gerät. Sie identifiziert ein imaginäres Gerät, das als untergeordneter Knoten des Root-Knotens einen Platz im Gerätebaum erhalten wird. Bei echter Hardware wählen Sie nicht Hardware ID Treiber Update. Wählen Sie stattdessen Installieren und Überprüfen. Sie können die Hardware-ID in der Informationsdatei (INF) Ihres Treibers sehen. Gehen Sie im Fenster Lösungs-Explorer zu MyUSBDriver_UMDF_ > Treiberdateien, und doppelklicken Sie auf MyUSBDriver_UMDF_.inf. Die Hardware-ID steht unter [Standard.NT$ARCH$].

Alle UMDF-basierten USB Client-Treiber benötigen zwei von Microsoft zur Verfügung gestellte Treiber, den Reflektor und WinUSB.

  • Reflektor: Wenn Ihr Treiber erfolgreich geladen wird, wird der Reflektor als oberster Treiber im Stack des Kernel-Modus geladen. Der Reflektor muss der oberste Treiber im Kernel-Mode Stack sein. Um diese Anforderung zu erfüllen, wird in der INF-Datei der Vorlage der Reflektor als Dienst und WinUSB als Treiber mit niedrigerem Filter in der INF angegeben:

    [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, denn für den Client-Treiber ist WinUSB das Gateway zum Kernel-Modus USB-Treiber Stack. Eine weitere Komponente, die geladen wird, ist eine Benutzermodus-DLL namens WinUsb.dll im Host-Prozess des Client-Treibers (Wudfhost.exe). Winusb.dll stellt WinUSB-Funktionen bereit, die den Kommunikationsprozess zwischen dem Client-Treiber und WinUSB vereinfachen.

Schritt 3: Erstellen des Codes für den USB Client-Treiber

So erstellen Sie Ihren Treiber:

  1. Öffnen Sie das Treiberprojekt oder die Lösung in Visual Studio 2022.
  2. Klicken Sie im Lösungs-Explorer mit der rechten Maustaste auf die Lösung und wählen Sie Configuration Manager.
  3. Wählen Sie im Configuration Manager Ihre Aktive Projektmappenkonfiguration (z. B. Debug oder Release) und Ihre Aktive Projektmappenplattform (z. B. x64), die der Art des Builds entspricht, an dem Sie interessiert sind.
  4. Vergewissern Sie sich, dass die GUID Ihrer Geräteschnittstelle im gesamten Projekt korrekt ist.
    • Die GUID der Geräteschnittstelle ist in Trace.h definiert und wird von MyUSBDriverUMDFCreateDevice in Device.c referenziert. Wenn Sie Ihr Projekt mit dem Namen MyUSBDriver_UMDF_ erstellen, definiert Visual Studio 2022 die Geräte-Interface-GUID mit dem Namen GUID_DEVINTERFACE_MyUSBDriver_UMDF_, ruft aber WdfDeviceCreateDeviceInterface mit dem falschen Parameter &GUID_DEVINTERFACE_MyUSBDriverUMDF auf. Ersetzen Sie den falschen Parameter durch den in Trace.h definierten Namen, um sicherzustellen, dass der Treiber korrekt 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

Um einen Treiber zu testen und zu debuggen, führen Sie den Debugger auf dem Host-Computer und den Treiber auf dem Ziel-Computer aus. Bislang haben Sie Visual Studio auf dem Host-Computer verwendet, um einen Treiber zu erstellen. Als nächstes müssen Sie einen Zielcomputer konfigurieren. Um einen Zielcomputer zu konfigurieren, folgen Sie den Direktiveen in Bereitstellen eines Computers für die Bereitstellung und das Testen von Treibern.

Schritt 5: Aktivieren des Tracings zum Debuggen des Kernels

Der Code der Vorlage enthält mehrere Trace-Nachrichten (TraceEvents), mit deren Hilfe Sie Funktionsaufrufe verfolgen können. Alle Funktionen im Quellcode enthalten Trace-Nachrichten, die den Eintritt und den Austritt aus einer Funktion markieren. Bei Fehlern enthält die Trace-Nachricht den Code des Fehlers und eine aussagekräftige Zeichenfolge. Da das WPP Tracing für Ihr Treiberprojekt aktiviert ist, enthält die PDB-Symboldatei, die während des Build-Prozesses erstellt wird, Direktiveen zur Formatierung von Trace-Nachrichten. Wenn Sie den Host- und den Zielcomputer für das WPP Tracing konfigurieren, kann Ihr Treiber Trace-Nachrichten an eine Datei oder den Debugger senden.

So konfigurieren Sie Ihren Host-Computer für das WPP-Tracing:

  1. Erstellen Sie Dateien im Trace Message Format (TMF), indem Sie die Formatierungsanweisungen für Trace-Nachrichten aus der PDB-Symboldatei extrahieren.

    Sie können Tracepdb.exe verwenden, um TMF-Dateien zu erstellen. Das Tool befindet sich im Ordner <Installationsordner>Windows Kits<Architecture> des WDKs. Der folgende Befehl erstellt TMF-Dateien für das Treiberprojekt.

    tracepdb -f <PDBFiles> -p <TMFDirectory>
    

    Mit der Option -f geben Sie 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 Ort, eine pro C-Code-Datei im Projekt. Sie sind mit GUID-Dateinamen versehen.

  2. Geben Sie im Debugger die folgenden Befehle ein:

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

Folgende Befehle:

  • Laden der Erweiterung Wmitrace.dll.
  • Überprüft, ob die Debugger-Erweiterung geladen ist.
  • Fügt den Speicherort der TMF-Dateien zum Suchpfad der Debugger-Erweiterung 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 das WPP Tracing

  1. Vergewissern Sie sich, dass Sie das Tool Tracelog auf Ihrem Zielcomputer installiert haben. Das Tool befindet sich im Ordner <Installationsordner>Windows Kits\10\Tools\<arch> des WDKs. Weitere Informationen finden Sie unter Tracelog-Befehlssyntax.

  2. Öffnen Sie ein Befehlsfenster und führen Sie es als Administrator*in 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 Tracing-Sitzung namens MyTrace.

Das Argument guid gibt die GUID des Trace-Anbieters an, bei dem es sich um den Client-Treiber handelt. Die GUID können Sie der Datei Trace.h im Visual Studio 2022-Projekt entnehmen. 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 Bindestrich-Format:

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

Sie können die Tracing-Sitzung beenden, indem Sie den folgenden Befehl eingeben:

tracelog -stop MyTrace

Schritt 6: Bereitstellen des Treibers auf dem Zielcomputer

  1. Klicken Sie im Fenster Lösungs-Explorer mit der rechten Maustaste auf den Projektnamen (MyUSBDriver_UMDF_) und wählen Sie Eigenschaften.
  2. Navigieren Sie im linken Bereich zu Konfigurationseigenschaften > Treiberinstallation > Bereitstellung.
  3. Geben Sie unter Name des Zielgeräts den Namen des Zielcomputers an.
  4. Wählen Sie Installieren/Neuinstallieren und Überprüfen.
  5. Klicken Sie auf OK.
  6. Wählen Sie im Menü Debuggen die Option Debuggen starten oder drücken Sie F5 auf der Tastatur.

Hinweis

Geben Sie nicht die Hardware-ID Ihres Geräts unter Hardware ID Treiber Update an. Die Hardware-ID muss nur in der Informationsdatei (INF) Ihres Treibers angegeben werden.

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

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

    devmgmt
    
  2. Überprüfen Sie, ob Geräte-Manager den folgenden Knoten anzeigt.

    USB-Gerät

    MyUSBDriver_UMDF_Device

Schritt 8: Anzeigen der Ausgabe im Debugger

Überprüfen Sie, ob Tracing-Nachrichten im Debugger Immediate Window auf dem Host-Computer erscheinen.

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

Schauen wir uns an, wie das Framework und der Client-Treiber zusammenarbeiten, um mit Windows zu interagieren und Anfragen an das USB-Gerät zu bearbeiten. Diese Abbildung zeigt die im System geladenen Module für einen UMDF-basierten USB Client-Treiber.

Diagramm der Architektur des Client-Treibers im Benutzermodus.

Der Zweck der einzelnen Module wird hier beschrieben:

  • Anwendung – ein Prozess im Benutzermodus, der E/A-Anfragen zur Kommunikation mit dem USB-Gerät stellt.
  • E/A-Manager – eine Windows-Komponente, die E/A-Anfrage-Pakete (IRPs) erstellt, um die empfangenen Anwendungsanfragen darzustellen, und sie an den obersten Punkt des Kernel-Modus-Gerätestacks für das Zielgerät weiterleitet.
  • Reflektor – ein von Microsoft bereitgestellter Kernel-Mode-Treiber, der am oberen Ende des Kernel-Mode-Gerätestacks (WUDFRd.sys) installiert ist. Der Reflektor leitet die vom E/A Manager empfangenen IRPs an den Host-Prozess des Client-Treibers um. Nach dem Empfang der Anfrage bearbeiten das Framework und der Client-Treiber die Anfrage.
  • Host-Prozess – der Prozess, in dem der Benutzermodus-Treiber ausgeführt wird (Wudfhost.exe). Er hostet auch das Framework und den I/O-Dispatcher.
  • Client-Treiber – der Benutzermodus-Funktionstreiber für das USB-Gerät.
  • UMDF – das Framework-Modul, das die meisten Interaktionen mit Windows im Namen des Client-Treibers abwickelt. Es stellt die Benutzermodus-Gerätetreiberschnittstellen (Device Driver Interface, DDI) zur Verfügung, die der Client-Treiber verwenden kann, um allgemeine Treiberaufgaben auszuführen.
  • Dispatcher-Mechanismus, der im Host-Prozess ausgeführt wird; bestimmt, wie eine Anfrage an den Kernel-Modus weitergeleitet werden soll, nachdem sie von den Benutzermodus-Treibern verarbeitet wurde und das untere Ende des Benutzermodus-Stacks erreicht hat. In der Abbildung leitet der Dispatcher die Anfrage an die Benutzermodus-DLL, Winusb.dll, weiter.
  • Winusb.dll – eine von Microsoft bereitgestellte Benutzermodus-DLL, die WinUSB-Funktionen bereitstellt, die den Kommunikationsprozess zwischen dem Client-Treiber und WinUSB (Winusb.sys, im Kernel-Modus geladen) vereinfachen.
  • Winusb.sys – ein von Microsoft bereitgestellter Treiber, der von allen UMDF Client-Treibern für USB-Geräte benötigt wird. Der Treiber muss unterhalb des Reflektors installiert werden und fungiert als Gateway zum USB-Treiber Stack im Kernel-Modus. Weitere Informationen finden Sie in der Einführung in WinUSB für Entwickler.
  • USB-Treiber-Stack – ein von Microsoft festgelegter Stack von Treibern, die die Kommunikation auf Protokollebene mit dem USB-Gerät abwickeln. Weitere Informationen finden Sie unter USB Host-seitige Treiber in Windows.

Wann immer eine Anwendung eine Anfrage an den USB-Treiber-Stack stellt, sendet der Windows E/A Manager die Anfrage an den Reflektor, der sie an den Client-Treiber im Benutzermodus weiterleitet. Der Client-Treiber bearbeitet die Anfrage durch den Aufruf bestimmter UMDF-Methoden, die intern WinUSB-Funktionen aufrufen, um die Anfrage an WinUSB zu senden. Nach Erhalt der Anfrage verarbeitet WinUSB diese entweder oder leitet sie an den USB-Treiber Stack weiter.