Ausführen über den Treiberspeicher

Wenn eine INF „Ausführen über den Treiberspeicher“ verwendet, bedeutet dies, dass die INF DIRID 13 verwendet, um den Speicherort für die Treiberpaketdateien bei der Installation anzugeben.

Für eine von einer INF geladene „Ausführen über den Treiberspeicher“-Nutzlastdatei muss der Wert subdir, der im Eintrag SourceDisksFiles für die Datei in der INF aufgelistet ist, dem subdir entsprechen, der in DestinationDirs für die Datei in der INF aufgelistet ist.

Darüber hinaus kann eine CopyFiles-Anweisung nicht verwendet werden, um eine Datei umzubenennen, die über den Treiberspeicher ausgeführt wird. Diese Einschränkungen sind erforderlich, damit die Installation einer INF auf einem Gerät nicht zur Erstellung neuer Dateien im Treiberspeicherverzeichnis führt.

Da SourceDisksFiles-Einträge nicht über mehrere Einträge mit demselben Dateinamen verfügen können und CopyFiles nicht zum Umbenennen einer Datei verwendet werden kann, muss jede Datei mit „Ausführen über den Treiberspeicher“, auf die eine INF verweist, über einen eindeutigen Dateinamen verfügen.

Treiberpakete bieten eine allgemeine Unterstützung für „Ausführen über den Treiberspeicher“ ab Windows 10 1709. Bestimmte Gerätestapel setzen jedoch möglicherweise zusätzliche Einschränkungen für Dateien ein, die Sie benötigen, um dieses Plug-In in diesem Stapel bereitzustellen. Beispielhaft sind diese Gerätestapel, die die Ausführung über den Treiberspeicher erst ab Windows 10 1803 unterstützt haben:

Wenn Sie eine Binärdatei bereitstellen, die in einen bestimmten Gerätestapel eingebunden wird, überprüfen Sie in der Dokumentation für diesen Gerätestapel, ob die Bereitstellung eines vollständigen Dateipfads für die Binärdatei unterstützt wird und ob Einschränkungen für diesen vollständigen Dateipfad bestehen. Wenn der Gerätestapel die Bereitstellung eines vollständigen Dateipfads zur Binärdatei ohne Einschränkungen für diesen Pfad unterstützt, sollte er auch die Datei unterstützen, die über den Treiberspeicher ausgeführt wird.

Dynamisches Suchen und Laden von Dateien über den Treiberspeicher

Manchmal ist es erforderlich, dass eine Komponente eine Datei lädt, die Teil eines Treiberpakets ist, das die Ausführung über den Treiberspeicher verwendet. Pfade zu diesen Treiberpaketdateien sollten nicht hartcodiert werden, da sie sich für verschiedene Versionen des Treiberpakets, Betriebssystemversionen, Betriebssystemeditionen usw. unterscheiden können. Wenn das Laden der Treiberpaketdateien erforderlich ist, sollten diese Dateien mithilfe einiger der unten beschriebenen Paradigmen ermittelt und dynamisch geladen werden.

Suchen und Laden von Dateien im selben Treiberpaket

Wenn eine Datei in einem Treiberpaket eine andere Datei aus demselben Treiberpaket laden muss, besteht eine mögliche Option zum dynamischen Ermitteln dieser Datei darin, das Verzeichnis zu ermitteln, aus dem diese Datei ausgeführt wird, und die andere Datei relativ zu diesem Verzeichnis zu laden.

Ein über den Treiberspeicher unter Windows 10, Version 1803 und höher ausgeführter WDM- oder KMDF-Treiber, der auf andere Dateien aus seinem Treiberpaket zugreifen muss, sollte IoGetDriverDirectory mit DriverDirectoryImage als den Verzeichnistyp aufrufen, um den Verzeichnispfad zu erhalten, aus dem der Treiber geladen wurde. Alternativ zu Treibern, die Betriebssystemversionen vor Windows 10, Version 1803 unterstützen müssen, verwenden Sie IoQueryFullDriverPath, um den Treiberpfad zu ermitteln, den Verzeichnispfad abzurufen, aus dem der Treiber geladen wurde, und Dateien relativ zu diesem Pfad zu finden. Wenn der Kernelmodustreiber ein KMDF-Treiber ist, kann er WdfDriverWdmGetDriverObject verwenden, um das WDM-Treiberobjekt abzurufen, das an IoQueryFullDriverPath übergeben werden soll.

Binärdateien für den Benutzermodus können GetModuleHandleExW und GetModuleFileNameW verwenden, um den Speicherort zu bestimmen, aus dem die Binärdatei geladen wurde. Beispielsweise kann eine UMDF-Treiber-Binärdatei wie folgt vorgehen:

bRet = GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
                         (PCWSTR)&DriverEntry,
                         &handleModule);
if (bRet) {
    charsWritten = GetModuleFileNameW(handleModule,
                                      path,
                                      pathLength);
    …

Suchen und Laden von Dateien in einem beliebigen Treiberpaket

In einigen Szenarien kann ein Treiberpaket eine Datei enthalten, die von einer Binärdatei in einem anderen Treiberpaket oder von einer Benutzermoduskomponente geladen werden soll. Diese Methode kann auch für Dateien aus demselben Treiberpaket verwendet werden, wenn dies gegenüber der oben beschriebenen Methode zum Laden von Dateien aus demselben Treiberpaket bevorzugt wird.

Im Folgenden sind einige Beispiele für Szenarien aufgeführt, die das Laden von Dateien aus einem Treiberpaket umfassen können:

  • Eine Benutzermodus-DLL in einem Treiberpaket bietet eine Schnittstelle für die Kommunikation mit einem Treiber im Treiberpaket.

  • Ein Erweiterungstreiberpaket enthält eine Konfigurationsdatei, die vom Treiber im Basistreiberpaket geladen wird.

In diesen Situationen sollte das Treiberpaket einen Zustand auf einem Gerät oder einer Geräteschnittstelle festlegen, der den Pfad der Datei angibt, die voraussichtlich geladen wird.

Ein Treiberpaket würde in der Regel ein HKR AddReg verwenden, um diesen Status festzulegen. In diesem Beispiel wird davon ausgegangen, dass das Treiberpaket für ExampleFile.dll einen SourceDisksFiles-Eintrag ohne subdir enthält. Dies führt dazu, dass sich die Datei im Stammverzeichnis des Treiberpakets befindet. Es sollte auch davon ausgegangen werden, dass DestinationDirs für eine CopyFiles-Anweisung dirid 13 angibt.

Im Folgenden finden Sie ein INF-Beispiel, um dies als Gerätestatus festzulegen:

[ExampleDDInstall.HW]
AddReg = Example_DDInstall.AddReg

[Example_DDInstall.AddReg]
HKR,,ExampleValue,,%13%\ExampleFile.dll

Ein INF-Beispiel für die Einstellung als Geräteschnittstellenstatus:

[ExampleDDInstall.Interfaces]
AddInterface = {<fill in an interface class GUID for an interface exposed by the device>},,Example_Add_Interface_Section

[Example_Add_Interface_Section]
AddReg = Example_Add_Interface_Section.AddReg

[Example_Add_Interface_Section.AddReg]
HKR,,ExampleValue,,%13%\ExampleFile.dll

In den vorherigen Beispielen wird ein leerer Flags-Wert verwendet, der zu einem REG_SZ-Registrierungswert führt. Dies führt dazu, dass %13% in einen vollqualifizierten Benutzermodusdateipfad umgewandelt wird. In vielen Fällen ist es besser, den Pfad relativ zu einer Umgebungsvariablen zu haben. Wenn ein Flagwert von 0x20000 verwendet wird, ist der Registrierungswert vom Typ REG_EXPAND_SZ und %13% wird in einen Pfad mit entsprechenden Umgebungsvariablen konvertiert, um den Speicherort des Pfads zu abstrahieren. Rufen Sie beim Abrufen dieses Registrierungswerts ExpandEnvironmentStrings auf, um die Umgebungsvariablen im Pfad aufzulösen.

Wenn der Wert von einer Kernelmoduskomponente gelesen werden muss, sollte der Wert ein REG_SZ-Wert sein. Wenn die Kernelmoduskomponente diesen Wert liest, sollte sie \??\ vor dem Übergeben an APIs ZwOpenFile voranstellen.

Um auf diese Einstellung zuzugreifen, wenn sie Teil des Gerätestatus ist, muss die Anwendung zuerst die Identität des Geräts ermitteln. Der Benutzermoduscode kann CM_Get_Device_ID_List_Size und CM_Get_Device_ID_List verwenden, um eine Liste der Geräte abzurufen, die ggf. gefiltert ist. Diese Liste kann mehrere Geräte enthalten. Suchen Sie daher vor dem Lesen des Gerätestatus nach dem entsprechenden Gerät. Rufen Sie beispielsweise CM_Get_DevNode_Property auf, um Eigenschaften auf dem Gerät abzurufen, wenn Sie nach einem Gerät suchen, das bestimmte Kriterien erfüllt.

Nachdem das richtige Gerät gefunden wurde, rufen Sie CM_Open_DevNode_Key auf, um ein Handle an den Registrierungsspeicherort zu erhalten, an dem der Gerätestatus gespeichert wurde.

Der Kernelmoduscode sollte ein PDO (physisches Geräteobjekt) mit dem Gerätestatus abrufen und IoOpenDeviceRegistryKey aufrufen. Ein möglicher Weg für den Kernelmoduscode das PDO des Geräts abzurufen, wäre das Ermitteln einer aktivierten Schnittstelle, die vom Gerät verfügbar gemacht wird, und IoGetDeviceObjectPointer zu verwenden, um das Geräteobjekt abzurufen.

Um auf diese Einstellung zuzugreifen, wenn es sich um den Status der Geräteschnittstelle handelt, kann der Benutzermoduscode CM_Get_Device_Interface_List_Size und CM_Get_Device_Interface_List aufrufen.

Darüber hinaus kann CM_Register_Notification verwendet werden, um Eingehen und Entfernen von Geräteschnittstellen zu melden, sodass der Code über die Aktivierung der Schnittstelle benachrichtigt wird, und dann den Status abrufen kann. Es kann mehrere Geräteschnittstellen in der Geräteschnittstellenklasse geben, die in den oben genannten APIs verwendet wird. Überprüfen Sie diese Schnittstellen, um zu bestimmen, welche Schnittstelle für die zu lesende Einstellung geeignet ist.

Sobald die richtige Geräteschnittstelle gefunden wurde, rufen Sie CM_Open_Device_Interface_Key auf.

Kernelmoduscode kann einen symbolischen Linknamen für die Geräteschnittstelle abrufen, aus der der Status erhalten werden soll. Rufen Sie dazu IoRegisterPlugPlayNotification auf, um sich für Geräteschnittstellenbenachrichtigungen in der entsprechenden Geräteschnittstellenklasse zu registrieren. Alternativ können Sie IoGetDeviceInterfaces aufrufen, um eine Liste der aktuellen Geräteschnittstellen im System abzurufen. Es kann mehrere Geräteschnittstellen in der Geräteschnittstellenklasse geben, die in den oben genannten APIs verwendet wird. Überprüfen Sie diese Schnittstellen, um zu bestimmen, welche Schnittstelle diejenige ist, für die die Einstellung gelesen werden soll.

Nachdem der entsprechende symbolische Linkname gefunden wurde, rufen Sie IoOpenDeviceInterfaceRegistryKey auf, um ein Handle an den Registrierungsspeicherort abzurufen, an dem der Geräteschnittstellenstatus gespeichert wurde.

Hinweis

Verwenden Sie das Flag CM_GETIDLIST_FILTER_PRESENT mit CM_Get_Device_ID_List_Size und das Flag CM_Get_Device_ID_List oder CM_GET_DEVICE_INTERFACE_LIST_PRESENT mit CM_Get_Device_Interface_List_Size und CM_Get_Device_Interface_List. So stellen Sie sicher, dass die Hardware im Zusammenhang mit dem Status, der den Dateipfad enthält, vorhanden und für die Kommunikation bereit ist.

Entfernen des Treiberpakets

Standardmäßig kann ein Treiberpaket nicht aus dem System entfernt werden, wenn es weiterhin auf Geräten installiert ist. Einige Optionen zum Entfernen eines Treiberpakets aus dem System ermöglichen jedoch, dass versucht wird, seine Entfernung zu erzwingen. Dadurch wird versucht, das Treiberpaket zu entfernen, auch wenn es auf einigen Geräten auf dem System noch installiert ist. Erzwungene Entfernungen sind für Treiberpakete mit Dateien, die über den Treiberspeicher ausgeführt werden, nicht zulässig. Wenn ein Treiberpaket aus dem System entfernt wird, werden auch dessen Treiberspeicherinhalte entfernt. Falls Geräte vorhanden sind, die noch mit diesem Treiberpaket installiert sind, werden alle Dateien aus dem Treiberspeicher in diesem Treiberpaket ausgeführt, und diese fehlenden Dateien können dazu führen, dass das Gerät nicht funktioniert. Um den Wechsel des Geräts in einen ungültigen Status zu verhindern, können Treiberpakete, die alle „Ausführen über den Treiberspeicher“-Dateien enthalten, nicht entfernt werden. Sie können nur entfernt werden, wenn sie nicht mehr auf Geräten installiert sind. Um das Entfernen solcher Treiberpakete zu unterstützen, können Sie DiUninstallDriver oder pnputil /delete-driver <oem#.inf> /uninstall verwenden. Bei diesen Entfernungsmethoden werden zunächst alle Geräte aktualisiert, auf denen das Treiberpaket entfernt wird, sodass sie nicht mehr mit diesem Treiberpaket installiert sind, bevor Sie versuchen, das Treiberpaket zu entfernen.

Treiberpaketentwicklung

Testen privater Binärdateien

Wenn es bei der Entwicklung eines Treiberpakets erforderlich ist, eine bestimmte ausführbare Datei des Treiberpakets durch eine private Version zu ersetzen, anstatt das gesamte Treiberpaket neu zu erstellen und auf dem System zu ersetzen, wird empfohlen, einen Kernel-Debugger mit dem Befehl .kdfiles zu verwenden. Da der vollständige Pfad zur Datei im Treiberspeicher nicht hartcodiert werden sollte, wird empfohlen, dass in der .kdfiles-Zuordnung der Name der OldDriver-Datei nur der direkte Name der Datei ohne vorherige Pfadinformationen ist. Um dies (und andere Szenarien) zu erleichtern, sollten die Dateinamen in Treiberpaketen so eindeutig wie möglich sein, sodass sie nicht mit dem Namen einer Datei aus einem nicht verknüpften Treiberpaket im System übereinstimmen.

Portieren einer INF, um die Ausführung über den Treiberspeicher zu verwenden

Wenn Sie über ein vorhandenes Treiberpaket mit einer INF verfügen, die nicht über den Treiberspeicher ausgeführt wird und zum Ausführen aus dem Treiberspeicher portiert wird, zeigen die folgenden Beispiele einige allgemeine Dateiverwendung in INFs und Mustern zum Aktualisieren dieser über den Treiberspeicher auszuführenden Dateien.

Kurzübersicht für Zielverzeichnisupdates

Die folgende Tabelle enthält eine Kurzübersicht für die Suche nach den entsprechenden Anleitungen basierend auf der aktuellen Zielverzeichnis-DIRID, die eine Treiberpaket-INF für eine Datei angibt.

DIRID Unterverzeichnis Details
13 Die Datei verwendet bereits „Ausführen über den Treiberspeicher“. Weitere Schritte sind nicht erforderlich.
1 DIRID 1 sollte nicht verwendet werden. Es gibt keine Garantie dafür, dass das Quellverzeichnis verfügbar ist, wenn ein Verweis auf die Datei aufgelöst werden muss. Wenn Komponenten im Treiberpaket stattdessen von bestimmten Dateien abhängen, schließen Sie diese Dateien in das Treiberpaket ein, und führen Sie sie aus dem Treiberspeicher aus.
10 Firmware Informationen zur Verwendung von DIRID 13 mit einem Firmwareupdatetreiberpaket zur Verwendung von „Ausführen über den Treiberspeicher“ finden Sie unter Erstellen eines Updatetreiberpakets .
10 Siehe Sonstige Dateien.
11 Siehe Sonstige Dateien.
12 UMDF Siehe UMDF-Treiber-Binärdatei.
12 Die meisten Dateien mit einem Ziel von DIRID 12 stellen Binärdateien des Treiberdiensts dar. Siehe Dienst-Binärdatei.
16422, 16426, 16427, 16428 Die meisten Dateien mit einem Ziel dieser DIRIDs stellen die Installation einer Anwendung dar. Stellen Sie stattdessen eine Universelle Windows-Plattform-Anwendung (UWP) bereit, und installieren Sie sie mithilfe einer AddSoftware-Anweisung aus einem DDInstall.Software-Abschnitt der Treiberpaket-INF. Ausführliche Informationen finden Sie unter Koppeln eines Treibers mit einer Universal Windows Platform-App (UWP).

Dienst-Binärdatei

Wenn Ihre INF einen Dienst hinzufügt und die Binärdatei nicht über den Treiberspeicher ausgeführt wird, sieht Ihre INF möglicherweise wie folgt aus:

[DestinationDirs]
 ; Copy the file to %windir%\system32\drivers
 Example_CopyFiles = 12

[ExampleDDInstall]
CopyFiles = Example_CopyFiles

[Example_CopyFiles]
ExampleBinary.sys

[ExampleDDInstall.Services]
AddService = ExampleService,0x2,Example_Service_Inst

[Example_Service_Inst]
DisplayName   = %SvcDesc%
ServiceType   = %SERVICE_KERNEL_DRIVER%
StartType     = %SERVICE_DEMAND_START%
ErrorControl  = %SERVICE_ERROR_NORMAL%
; Point at the file in %windir%\system32\drivers
ServiceBinary = %12%\ExampleBinary.sys

Um diese Datei über den Treiberspeicher auszuführen, müssen Sie den DestinationDirs-Eintrag aktualisieren, in den die Datei kopiert wird. Aktualisieren Sie die ServiceBinary-Anweisung, die auf den Speicherort dieser Datei verweist.

[DestinationDirs]
; Update the destination to DIRID 13
Example_CopyFiles = 13

[ExampleDDInstall]
CopyFiles = Example_CopyFiles

[Example_CopyFiles]
ExampleBinary.sys

[ExampleDDInstall.Services]
AddService = ExampleService,0x2,Example_Service_Inst

[Example_Service_Inst]
DisplayName   = %SvcDesc%
ServiceType   = %SERVICE_KERNEL_DRIVER%
StartType     = %SERVICE_DEMAND_START%
ErrorControl  = %SERVICE_ERROR_NORMAL%
; Point at the run from Driver Store file using DIRID 13
ServiceBinary = %13%\ExampleBinary.sys

UMDF-Treiberbinärdatei

Wenn Ihre INF einen UMDF-Treiber hinzufügt und die Binärdatei nicht über den Treiberspeicher ausgeführt wird, sieht Ihre INF möglicherweise wie folgt aus:

[DestinationDirs]
; Copy the file to %windir%\system32\drivers\UMDF
Example_CopyFiles = 12, UMDF

[ExampleDDInstall]
CopyFiles = Example_CopyFiles

[Example_CopyFiles]
ExampleUmdfDriver.dll

[ExampleDDInstall.Wdf]
UmdfService = ExampleUmdfDriver,Example_UMDF_Inst
...

[Example_UMDF_Inst]
; Point at the file in %windir%\system32\drivers\UMDF
ServiceBinary = %12%\UMDF\ExampleUmdfDriver.dll
...

Um diese Datei über den Treiberspeicher auszuführen, müssen Sie den DestinationDirs-Eintrag aktualisieren, in den die Datei kopiert wird. Aktualisieren Sie die ServiceBinary-Anweisung, die auf den Speicherort dieser Datei verweist.

[DestinationDirs]
; Update the destination to DIRID 13
Example_CopyFiles = 13

[ExampleDDInstall]
CopyFiles = Example_CopyFiles

[Example_CopyFiles]
ExampleUmdfDriver.dll

[ExampleDDInstall.Wdf]
UmdfService = ExampleUmdfDriver,Example_UMDF_Inst
...

[Example_UMDF_Inst]
; Point at the run from Driver Store file using DIRID 13
ServiceBinary = %13%\ExampleUmdfDriver.dll
...

Andere Dateien

Wenn Ihre INF eine Datei hinzufügt, die möglicherweise von anderen Komponenten geladen wird und nicht über den Treiberspeicher ausgeführt wird, sieht Ihre INF möglicherweise wie folgt aus. In diesem Beispiel wird nur der Name der Datei in den Registrierungsstatus des Geräts geschrieben. Komponenten, die diesen Registrierungswert lesen, um zu bestimmen, welche Datei geladen werden soll, hängen von der Datei %windir%\system32 oder von der Suchreihenfolge von LoadLibrary ab, in der die Datei gefunden werden kann.

[DestinationDirs]
; Copy the file to %windir%\system32
Example_CopyFiles = 11

[ExampleDDInstall]
CopyFiles=Example_CopyFiles
AddReg=Example_AddReg

[Example_CopyFiles]
ExampleFile.dll

[Example_AddReg]
HKR,,FileLocation,,"ExampleFile.dll"

Um diese Datei über den Treiberspeicher auszuführen, müssen Sie den DestinationDirs-Eintrag aktualisieren, in den die Datei kopiert wird. Aktualisieren Sie den im Gerätestatus gespeicherten Speicherort. Dies erfordert Komponenten, die diesen Registrierungswert lesen, um ihn als vollständigen Pfad zu einer Datei anstelle einer Datei relativ zu %windir%\system32 zu behandeln.

[DestinationDirs]
Example_CopyFiles = 13 ; update the destination to DIRID 13

[ExampleDDInstall]
CopyFiles=Example_CopyFiles
AddReg=Example_AddReg

[Example_CopyFiles]
ExampleFile.dll

[Example_AddReg]
; Point at the run from Driver Store file using DIRID 13
HKR,,FileLocation,,"%13%\ExampleFile.dll"