Vom Beispielcode zum Produktionstreiber – Was Sie an den Beispielen ändern müssen
In diesem Thema werden wichtige Änderungen beschrieben, die an den WDK-Beispieltreibern vorgenommen werden müssen, bevor Gerätetreiber, die auf dem Beispielcode basieren, veröffentlicht werden.
Zusätzlich zu den hier beschriebenen Änderungen sollten alle Treiber die bewährten Verfahren anwenden, die in Erstellen von zuverlässigen Kernel-Mode-Treibern und in Best Practices für die Entwicklung von Treibern durch Oberflächenteams beschrieben sind. Alle Treiber sollten sich auch an die Richtlinien halten, die in Anleitung zur Treibersicherheit beschrieben sind.
WDK-Treiberbeispiele – Eindeutige Bezeichner
Das Windows Driver Kit (WDK) enthält eine Vielzahl von Beispieltreibern, die nützliche Techniken für die Treiberentwicklung demonstrieren. Sie können diese Beispiele als Grundlage für Ihre eigenen Treiber verwenden, aber bevor Sie den Treiber freigeben, müssen Sie bestimmte gerätespezifische Aspekte des Beispiels – über den offensichtlichen operativen Code hinaus – so ändern, dass sie eindeutig auf Ihr eigenes Gerät und Ihren eigenen Treiber zutreffen. Autoren von Treibern übersehen diese Details manchmal.
Die genauen Punkte, die Sie ändern müssen, variieren von einem Beispiel zum nächsten, aber im Allgemeinen identifizieren sie ein bestimmtes Gerät, eine Schnittstelle oder einen Treiber. Wenn der Beispieltreiber zum Beispiel eines der folgenden Elemente enthält, müssen Sie es so ändern, dass es auf Ihren Treiber und Ihr Gerät zutrifft:
Globale eindeutige Bezeichner (Globally Unique Identifier, GUID)
Namen für symbolische Links
Geräteobjektname
Pool-Tags
Definitionen des E/A-Control-Codes (I/O Control Code, IOCTL)
Namen von Dateien, die in den Systemordner kopiert werden
Plug-and-Play-Geräte-ID, Hardware-ID und kompatible IDs
Dienstname des Treiberdienstes
Gerätebeschreibung
Ressourcendatei
Wenn Sie diese Änderungen nicht vornehmen, kann die Installation fehlschlagen, es kann zu Konflikten mit anderen Geräten und Treibern auf dem System kommen, und es kann zu Schwierigkeiten bei der Fehlersuche und anderen Fehlern kommen.
Wenn Sie beispielsweise eine Fehlermeldung wie ...\toastDrv\kmdf\toastmon\wdftoastmon.inx(18-18): error 1284: Class "Sample" is reserved for use by Microsoft.
erhalten, bedeutet dies, dass der Name „Sample“ in einen eindeutigen Namen für Ihren Beispieltreiber geändert werden muss.
GUIDs
Treiber verwenden GUIDs, um Geräteeinrichtungsklassen, Geräteschnittstellenklassen, angepasste PnP-Ereignisse, angepasste Windows Management Instrumentation (WMI) Ereignisse und Windows PreProcessor (WPP) Trace-Provider zu identifizieren. Einige GUIDs werden von Microsoft definiert, andere werden von Geräte- und Treiberherstellern festgelegt.
Die GUIDs der Einrichtungsklassen, die GUIDs der Geräteschnittstellenklassen und die WMI-GUIDs für allgemeine Geräte und WMI-Daten sind im WDK oder in öffentlichen Header-Dateien zur Verwendung durch jeden Treiber definiert. Sie sollten diese GUIDs nicht ändern.
Wenn Sie beispielsweise eine Maus implementieren, würden Sie weiterhin die GUID_DEVINTERFACE_MOUSE, die in der WDK-Header-Datei Ntddmou.h definiert ist, als Geräteschnittstellenklasse verwenden. Wenn Sie jedoch eine neue Einrichtungsklasse für ein Gerät definieren, müssen Sie eine neue GUID für die Einrichtungsklasse und den Namen der Einrichtungsklasse generieren und möglicherweise auch eine neue GUID für die Geräteschnittstellenklasse. Die GUID der Einrichtungsklasse und die GUID der Geräteschnittstellenklasse müssen eindeutige Werte sein; sie können keine einheitliche GUID haben.
Bei den meisten beispielbasierten Treibern sollten Sie nur die GUIDs ändern, die in der lokalen Header- oder Quelldatei eines Beispiels definiert sind und somit spezifisch für das Beispiel sind. Zu diesen GUIDs können die folgenden gehören:
Angepasste PnP-Ereignisse
Angepasste WMI-Ereignisse
Geräteschnittstellenklassen für neue oder angepasste Geräte
WPP-Tracing-Anbieter
Die Verwendung einer GUID, die für einen anderen Treiber definiert wurde, kann zu Konflikten führen, wenn beide Treiber auf demselben System geladen sind. Wenn beispielsweise zwei verschiedene Treiber dieselbe GUID zur Registrierung einer Geräteschnittstelle verwenden, könnten Clients, die versuchen, die Geräteschnittstelle zu öffnen, versehentlich das falsche Gerät öffnen.
Der folgende Auszug stammt aus der Datei Driver.h, die in allen Toaster-Treiberbeispielen enthalten ist. Sie definiert die GUID der Geräteschnittstelle für Toaster-Geräte:
DEFINE_GUID(GUID_TOASTER_INTERFACE_STANDARD, \ 0xe0b27630, 0x5434, 0x11d3, 0xb8, 0x90, 0x0, 0xc0, \ 0x4f, 0xad, 0x51, 0x71); // {E0B27630-5434-11d3-B890-00C04FAD5171}
Wenn Sie diese Datei in Ihrem eigenen Treiber verwenden, stellen Sie sicher, dass Sie die Beispiel-GUID (oben als fetter Text dargestellt) durch die Schnittstellen-GUID für Ihr eigenes Gerät ersetzen. Um eine GUID zu erstellen, verwenden Sie das Tool "GUID erstellen" in Microsoft Visual Studio oder Guidgen.exe, die beide im Microsoft Windows Software Development Kit (SDK) enthalten sind. Sie können dann die GUID mit einer symbolischen Konstante in der Treiber-Header-Datei verknüpfen, wie das Beispiel zeigt.
Möglicherweise müssen Sie auch neue GUIDs für die WMI-Ereignisse des Treibers erstellen. In den Beispielen für den Toaster-Treiber ist die folgende GUID für die Benachrichtigung über die Ankunft eines Toaster-Geräts definiert:
DEFINE_GUID (TOASTER_NOTIFY_DEVICE_ARRIVAL_EVENT, \ 0x1cdaff1, 0xc901, 0x45b4, 0xb3, 0x59, 0xb5, 0x54, \ 0x27, 0x25, 0xe2, 0x9c); // {01CDAFF1-C901-45b4-B359-B5542725E29C}
Sie sollten für jedes WMI-Ereignis in Ihrem Treiber eine neue GUID erstellen.
Wenn der Beispieltreiber das WPP-Software-Tracing verwendet, generieren Sie eine neue GUID für alle Treiber, die Sie auf dem Beispiel aufbauen. Zum Beispiel definiert die Header-Datei Trace.h des Beispiels Osrusbfx2 in %WinDDK%\Src\Kmdf\Osrusbfx2\Final eine Control-GUID wie folgt:
#define WPP_CONTROL_GUIDS \ WPP_DEFINE_CONTROL_GUID( \ OsrUsbFxTraceGuid,(d23a0c5a,d307,4f0e,ae8e,E2A355AD5DAB), \ WPP_DEFINE_BIT(DBG_INIT) /* bit 0 = 0x00000001 */ \ WPP_DEFINE_BIT(DBG_PNP) /* bit 1 = 0x00000002 */ \ WPP_DEFINE_BIT(DBG_POWER) /* bit 2 = 0x00000004 */ \ WPP_DEFINE_BIT(DBG_WMI) /* bit 3 = 0x00000008 */ \ WPP_DEFINE_BIT(DBG_CREATE_CLOSE) /* bit 4 = 0x00000010 */ \ WPP_DEFINE_BIT(DBG_IOCTL) /* bit 5 = 0x00000020 */ \ WPP_DEFINE_BIT(DBG_WRITE) /* bit 6 = 0x00000040 */ \ WPP_DEFINE_BIT(DBG_READ) /* bit 7 = 0x00000080 */ \ )
In Ihrem eigenen Treiber würden Sie den fettgedruckten Text durch einen treiberspezifischen Namen und die von Ihnen erstellte GUID ersetzen.
Namen für symbolische Links
Wenn das Beispiel einen Namen für einen symbolischen Link definiert, ersetzen Sie den Namen im Beispiel durch einen Namen, der für Ihren eigenen Treiber gilt. Ändern Sie jedoch keine bekannten Link-Namen wie z. B. \DosDevices\COM1. Allgemein gilt: Wenn der Link-Name dem Namen des Beispiels sehr ähnlich ist (wie z. B. \DosDevices\CancelSamp), sollten Sie ihn ändern.
Die Verwendung desselben symbolischen Links wie bei einem anderen Treiber hat denselben Effekt wie die Verwendung der falschen Geräte-Interface-GUID, da Geräte-Interfaces im Wesentlichen symbolische Links sind.
Der KMDF Toaster Filter-Treiber in %WinDDK\Src\Kmdf\Toaster\Filter erstellt einen symbolischen Link-Namen, der eine Zeichenfolge verwendet, die wie folgt in der Header-Datei Filter.h definiert ist:
#define SYMBOLIC_NAME_STRING L"\\DosDevices\\ToasterFilter"
Ändern Sie die fettgedruckte Zeichenfolge, um Ihren eigenen Treiber korrekter zu beschreiben.
Geräteobjektname
Wenn das Beispiel einen Namen für das Geräteobjekt erstellt, müssen Sie den Namen ändern, wenn Sie den Beispielcode anpassen.
Der KMDF Toaster Filter-Treiber benennt sein Geräteobjekt in der Header-Datei Filter.h wie folgt:
#define NTDEVICE_NAME_STRING L\\Device\\ToasterFilter
Wie beim Namen des symbolischen Links sollten Sie die Zeichenfolge ändern, um Ihren Treiber zu beschreiben.
Denken Sie daran, dass benannte Geräteobjekte ein Sicherheitsrisiko darstellen können. Physikalische Geräteobjekte (Physical Device Objects, PDOs) müssen Namen haben, und die meisten dieser Namen werden vom System generiert und nicht explizit von einem Treiber zugewiesen. Andere Geräteobjekte sollten nur dann benannt werden, wenn es sich um Control-Device-Objekte handelt, die für die Seitenbandkommunikation zwischen einer Anwendung und einem Treiber verwendet werden. Sowohl das Kernel-Mode Driver Framework (KMDF) als auch das Windows Driver Model (WDM) ermöglichen es Ihnen, den Namen von Windows generieren zu lassen. Dieser Ansatz stellt sicher, dass der Name des Geräteobjekts eindeutig ist und dass nicht privilegierte Benutzer keinen Zugriff darauf haben. Einzelheiten finden Sie unter Steuerung des Zugriffs auf den Namespace von Geräten und Steuerung des Zugriffs auf Geräte in KMDF-Treibern.
Pool-Tags
Ein Pool-Tag ist ein ein- bis vierstelliges Literal, das eine bestimmte Speicherzuweisung identifiziert und bei der Fehlersuche helfen kann.
Viele der Beispieltreiber definieren ein Pool-Tag in der Treiber-Header-Datei, wie in der folgenden Zeile aus Toaster.h:
#define TOASTER_POOL_TAG (ULONG) 'saoT'
Der Treiber definiert den Tag rückwärts, weil der Debugger ihn in umgekehrter Reihenfolge anzeigt. Daher erscheint dieser Tag als Toas in der Debugger-Ausgabe. Anstatt den im Beispiel definierten Tag zu verwenden, ändern Sie die Zeichenfolge, um Ihren eigenen Code eindeutig zu identifizieren.
Die Datei Pooltag.txt listet die Pool-Tags auf, die von Komponenten und Treibern im Kernel-Modus verwendet werden, die mit Windows geliefert werden. Pooltag.txt wird mit dem WDK in %winddk%\Tools\Other<i>platform\Poolmon installiert, wobei platform amd64, i386 oder ia64 ist. Verwenden Sie keine der Tags, die in dieser Liste erscheinen.
IOCTL-Definitionen
Ändern Sie alle durch Beispiele definierten Codes für die E/A-Steuerung, um einen Namen, einen Gerätetyp, einen Funktionscode, einen Übertragungstyp und einen Zugriffstyp zu verwenden, die für Ihr Gerät und Ihren Treiber geeignet sind.
Das Beispiel Osrusbfx2 enthält zum Beispiel die folgende Definition für IOCTL_OSRUSBFX2_READ_SWITCHES:
#define IOCTL_OSRUSBFX2_READ_SWITCHES CTL_CODE(FILE_DEVICE_OSRUSBFX2, \ IOCTL_INDEX + 6, \ METHOD_BUFFERED, \ FILE_READ_ACCESS)
Ein auf einem Beispiel basierender Treiber für ein anderes Gerät würde Änderungen an dieser Definition erfordern.
Dateinamen
Ändern Sie in der INF- oder INX-Datei die Namen des Treibers, des vom Hersteller bereitgestellten Co-Installers und aller anderen Dateien, die der Installationsvorgang in den Systemordner kopiert. Diese Dateinamen erscheinen normalerweise in den Abschnitten [SourceDisksFiles] und [ClassInstall32] der INF und in den Einträgen CopyFiles.
Das folgende Beispiel stammt aus der INX-Datei für das KMDF Featured Toaster-Beispiel, das in %WinDDK%\src\kmdf\Toaster\Featured verfügbar ist. Die Dateinamen, die geändert werden müssen, sind fett dargestellt:
[ClassInstall32] Addreg=ToasterClassReg CopyFiles=ToasterClassInstallerCopyFileshighlight [ToasterClassReg] ... HKR,,Installer32,,"tostrcls.dll,ToasterClassInstaller" ... [ToasterClassInstallerCopyFiles] tostrcls.dll ...
Um dieses Element der Datei für einen anderen Treiber anzupassen, würden Sie „tostrcls.dll“ in den Dateinamen Ihres Klasseninstallers ändern und die Zeichenfolge „ToasterClassInstaller“ so ändern, dass sie Ihren eigenen Installer beschreibt. Diese Änderungen stellen sicher, dass bei der Installation die richtige Datei für den Installer kopiert wird und dass der Registrierungsschlüssel den richtigen Datensatz enthält.
Ändern Sie nicht den Namen von Co-Installern, die im WDK oder mit Windows geliefert werden, wie z. B. die Co-Installer KMDF, UMDF und WinUSB.
Weitere Änderungen sind später im Abschnitt Geräte installieren der Datei erforderlich, wie in diesem Beispiel gezeigt:
[Toaster_Device.NT] CopyFiles=Toaster_Device.NT.Copy [Toaster_Device.NT.Copy] wdffeatured.sys
In diesem Beispiel würden Sie den fett dargestellten Dateinamen in den Namen der von Ihnen generierten Treiberdatei ändern.
Wenn die Einrichtung die INF- und Treiberkatalogdateien kopiert, benennt sie diese um, sodass Sie die Namen in Ihrem Treiberpaket nicht unbedingt ändern müssen. Allgemein sollten Sie jedoch darauf achten, dass die Namen der INF- und Katalogdateien den Namen der Treiberdateien ähneln.
PnP-Geräte-ID, Hardware-ID und kompatible IDs
Bei der Einrichtung wird die Geräte-ID zusammen mit den Hardware-IDs und den kompatiblen IDs verwendet, um die INF auszuwählen, die für die Installation des Geräts verwendet werden soll.
Die Geräte-ID ist eine vom Hersteller definierte Zeichenfolge, die ein bestimmtes Gerät eindeutig identifiziert. Jedes Gerät hat genau eine Geräte-ID. Der Bustreiber liefert die Geräte-ID während der Auflistung, und das Setup verwendet sie, um das Gerät mit der richtigen INF-Datei abzugleichen. Die Geräte-ID wird im Abschnitt [Manufacturer] der INF-Datei definiert.
Das folgende Beispiel zeigt die Geräte-ID für das OSR USB Fx2 Gerät, wie sie in der Datei Osrusbfx2.inx angegeben ist:
[Manufacturer] %MfgName%=Microsoft,NT$ARCH$ ; For Win2K [Microsoft] %USB\VID_045E&PID_930A.DeviceDesc%=osrusbfx2.Dev, USB\VID_0547&PID_1002 ... ; For XP and later [Microsoft.NT$ARCH$] %USB\VID_045E&PID_930A.DeviceDesc%=osrusbfx2.Dev, USB\VID_0547&PID_1002
Um diese INF-Direktive für Ihren eigenen Treiber anzupassen, ersetzen Sie die fettgedruckte Geräte-ID durch die Geräte-ID Ihres eigenen Geräts. Außerdem sollten Sie den Herstellernamen durch den Namen Ihres Unternehmens ersetzen.
Die Hardware-ID und die kompatible ID sind weniger spezifische IDs, die das Setup verwendet, wenn es die Geräte-ID nicht mit einer INF abgleichen kann. Wenn Ihre INF andere Geräte unterstützen kann, sollten Sie diese Werte zusätzlich zur Geräte-ID ändern. Das folgende Beispiel aus dem KMDF Featured Toaster-Treiber zeigt eine Hardware-ID:
[Manufacturer] %StdMfg%=Standard,NT$ARCH$ ; For Win2K [Standard] ; DisplayName Section DeviceId ; ----------- ------- -------- %ToasterDevice.DeviceDesc%=Toaster_Device, {b85b7c50-6a01-11d2-b841-00c04fad5171}\MsToaster ; For XP and later [Standard.NT$ARCH$] %ToasterDevice.DeviceDesc%=Toaster_Device, {b85b7c50-6a01-11d2-b841-00c04fad5171}\MsToaster
Um diese INF-Direktive für Ihren eigenen Treiber anzupassen, ersetzen Sie die Hardware-ID durch die Geräte-ID Ihres Treibers und ändern Sie „MsToaster“ in eine beschreibendere Zeichenfolge.
Dienstname des Treiberdienstes
Aktualisieren Sie den Dienstnamen in der Direktive AddService in der INF auf einen Wert, der für Ihren Treiber geeignet ist. Wenn der Dienstname des Treibers mit dem eines anderen Treibers auf dem System kollidiert, kann der Treiber nicht installiert oder geladen werden.
Der KMDF Featured Toaster-Treiber benennt seinen Dienst wie folgt:
[Toaster_Device.NT.Services] AddService = wdffeatured, %SPSVCINST_ASSOCSERVICE%, wdffeatured_Service_Inst
Der Dienstname ist der erste Eintrag in der Direktive AddService. Um die INF des Featured Toaster anzupassen, ändern Sie die fettgedruckte Zeichenfolge in eine Zeichenfolge, die besser zu Ihrem Treiber passt. In diesem Beispiel verweist der Eintrag wdffeatured_Service_Inst lediglich auf einen INF-definierten Abschnitt, sodass eine Änderung nicht kritisch ist.
Gerätebeschreibung
Die Gerätebeschreibung besteht aus mehreren Zeichenfolgen, die normalerweise im Abschnitt [Strings] der INF definiert sind und an verschiedenen Stellen in der INF verwendet werden. Das KMDF Featured Toaster-Beispiel definiert zum Beispiel die folgenden Zeichenfolgen in der Datei WdfFeatured.inx:
[Strings] SPSVCINST_ASSOCSERVICE = 0x00000002 MSFT = "Microsoft" StdMfg = "(Standard system devices)" ClassName = "Toaster" DiskId1 = "Toaster Device Installation Disk #1" ToasterDevice.DeviceDesc = "Microsoft WDF Featured Toaster" Toaster.SVCDESC = "Microsoft WDF Toaster Featured Device Driver"
Wenn Sie diese Datei ändern, um Ihren eigenen Treiber zu installieren, sollten Sie die fettgedruckten Zeichenfolgen so ändern, dass sie Informationen über Ihr Unternehmen, Ihr Gerät und Ihren Treiber enthalten.
Wenn der Firmenname auch in einem [Manufacturer]-Abschnitt in der INF erscheint, müssen Sie den Namen auch dort ändern.
Ressourcendatei
Für Treiber und andere Komponenten wie z. B. beispielspezifische Installer gibt es auch Ressourcendateien (.rc), in denen treiberspezifische Zeichenfolgen definiert sind, darunter der Produktname, die Dateiversion und der Firmenname. Ändern Sie diese Zeichenfolgen in die entsprechenden Werte für Ihr Treiber-Paket.
Zusammenfassung – Was sollten Sie tun?
Bevor Sie einen Treiber veröffentlichen, der auf einem WDK-Beispiel basiert, ersetzen Sie alle beispielspezifischen Informationen in den Quelldateien, der INF und allen anderen Ressourcen, die Sie zum Erstellen Ihres eigenen Treibers verwendet haben. Die erforderlichen Änderungen sind von Beispiel zu Beispiel unterschiedlich, umfassen aber im Allgemeinen alle Informationen, die den Beispieltreiber oder sein Gerät eindeutig identifizieren. Die folgenden Änderungen sind typisch für die, die Sie vornehmen müssen:
Generieren und verwenden Sie gegebenenfalls GUIDs, die für Ihren Treiber spezifisch sind.
Aktualisieren Sie den Namen des symbolischen Links.
Aktualisieren Sie den Namen des Geräteobjekts oder verwenden Sie einen automatisch generierten Namen.
Verwenden Sie Pool-Tags, die Ihren Treiber identifizieren und nicht mit bekannten Tags kollidieren.
Definieren Sie IOCTL-Codes, die für Ihren Treiber und Ihr Gerät geeignet sind.
Aktualisieren Sie die Namen der Dateien, die in den Systemordner kopiert werden.
Fügen Sie die richtige Plug-and-Play-Geräte-ID, Hardware-IDs und kompatible IDs in die INF ein.
Aktualisieren Sie den Dienstnamen des Treibers in der INF.
Ändern Sie die Gerätebeschreibung.
Ändern Sie alle treiberspezifischen Zeichenfolgen in der Ressourcendatei.
Halten Sie sich an bewährte Verfahren für Sicherheit und Zuverlässigkeit
Weitere Informationen
Bücher
Entwicklung von Treibern mit Windows Driver Foundation, von Penny Orwick und Guy Smith
WDK-Themen
Definieren und Exportieren neuer GUIDs
Steuern des Gerätezugriffs in KMDF-Treibern
Entwickeln, Testen und Bereitstellen von Treibern
Erstellen von zuverlässigen Kernelmodustreibern
Bewährte Methoden für die Entwicklung von Surface Team-Treibern