Ausführen im Treiberspeicher

Ein INF, der "Aus dem Treiberspeicher ausführen" verwendet, bedeutet, dass der INF DIRID 13 verwendet, um den Speicherort für Treiberpaketdateien bei der Installation anzugeben.

Bei einer Datei mit dem Namen "Run from Driver Store", die von einem INF verwendet wird, muss der im Eintrag SourceDisksFiles für die Datei im INF aufgeführte Unterdir mit dem im Eintrag DestinationDirs aufgeführten Unterdir für die Datei im INF übereinstimmen.

Darüber hinaus kann eine CopyFiles-Direktive nicht verwendet werden, um eine Datei umzubenennen, die aus dem Treiberspeicher ausgeführt wird. Diese Einschränkungen sind erforderlich, damit die Installation eines INF auf einem Gerät nicht zur Erstellung neuer Dateien im Verzeichnis Driver Store 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 vom Treiberspeicher ausgeführte Datei, auf die ein INF verweist, einen eindeutigen Dateinamen aufweisen.

Treiberpakete verfügen ab Windows 10 1709 über allgemeine Unterstützung für die Ausführung aus dem Treiberspeicher. Bestimmte Gerätestapel können jedoch zusätzliche Einschränkungen für Dateien festlegen, die Sie für die Bereitstellung dieses Plug-Ins in diesen Stapels benötigen. Einige Beispiele sind diese Gerätestapel, die die Ausführung aus dem Treiberspeicher bis Windows 10 1803 nicht unterstützt haben:

Wenn Sie eine Binärdatei bereitstellen, die an einen bestimmten Gerätestapel angebunden wird, lesen Sie die Dokumentation für den spezifischen Gerätestapel, an den Sie sich anschließen möchten, um zu überprüfen, ob die Bereitstellung eines vollständigen Dateipfads für die Binärdatei unterstützt wird und ob es Einschränkungen für diesen vollständigen Dateipfad gibt. Wenn die Bereitstellung eines vollständigen Dateipfads für die Binärdatei ohne Einschränkungen für diesen Pfad unterstützt wird, sollte die Datei unterstützt werden, die aus dem Treiberspeicher ausgeführt wird.

Dynamisches Suchen und Laden von Dateien aus dem Treiberspeicher

Manchmal muss eine Komponente eine Datei laden, die Teil eines Treiberpakets ist, das "aus dem Treiberspeicher ausführen" verwendet. Pfade zu diesen Treiberpaketdateien sollten nicht hartcodiert werden, da sie sich zwischen verschiedenen Versionen des Treiberpakets, verschiedenen Betriebssystemversionen, verschiedenen Betriebssystemeditionen usw. unterscheiden können. Wenn eine solche Notwendigkeit zum Laden von Treiberpaketdateien besteht, sollten diese Treiberpaketdateien mithilfe einiger der unten beschriebenen Paradigmen dynamisch ermittelt und 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 bestimmen, in dem diese Datei ausgeführt wird, und die andere Datei relativ zu diesem Verzeichnis zu laden.

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

Binärdateien im Benutzermodus können GetModuleHandleExW und GetModuleFileNameW verwenden, um zu bestimmen, woher der Treiber geladen wurde. Eine Binärdatei des UMDF-Treibers kann z. B. folgende Aktionen ausführen:

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 finden Sie einige Beispiele für Szenarien, die das Laden von Dateien aus einem Treiberpaket umfassen können:

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

  • Ein Erweiterungstreiberpaket enthält eine Konfigurationsdatei, die vom Treiber in das 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 werden soll.

Ein Treiberpaket verwendet in der Regel einen HKR AddReg , um diesen Zustand festzulegen. In diesem Beispiel sollte davon ausgegangen werden, dass das Treiberpaket über ExampleFile.dlleinen SourceDisksFiles-Eintrag ohne Subdir verfügt. Dies führt dazu, dass sich die Datei im Stammverzeichnis des Treiberpaketverzeichnisses befindet. Es sollte auch davon ausgegangen werden, dass die DestinationDirs-Anweisung für eine CopyFiles-Direktivedirid 13 angibt.

Hier sehen Sie ein INF-Beispiel zum Festlegen des Gerätezustands:

[ExampleDDInstall.HW]
AddReg = Example_DDInstall.AddReg

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

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

[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 empfiehlt es sich, den Pfad relativ zu einer Umgebungsvariablen zu verwenden. Wenn ein Flags-Wert von 0x20000 verwendet wird, ist der Registrierungswert vom Typ REG_EXPAND_SZ, und der %13% wird in einen Pfad mit entsprechenden Umgebungsvariablen konvertiert, um den Speicherort des Pfads abzustrahieren. 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 der \??\ Übergabe an APIs wie ZwOpenFile vorangestellt werden.

Um auf diese Einstellung zuzugreifen, wenn sie Teil des Gerätezustands ist, muss die Anwendung zuerst die Identität des Geräts finden. Benutzermoduscode kann CM_Get_Device_ID_List_Size und CM_Get_Device_ID_List verwenden, um eine Liste der Geräte abzurufen, die nach Bedarf gefiltert werden. Diese Geräteliste kann mehrere Geräte enthalten. Suchen Sie daher vor dem Lesen des Gerätezustands 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 bestimmten Kriterien entspricht.

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

Kernelmoduscode sollte ein PDO (physisches Geräteobjekt) auf das Gerät mit dem Status abrufen und IoOpenDeviceRegistryKey aufrufen. Eine mögliche Möglichkeit für den Kernelmoduscode zum Abrufen des PDO des Geräts besteht in der Ermittlung einer aktivierten Schnittstelle, die vom Gerät verfügbar gemacht wird, und die Verwendung von IoGetDeviceObjectPointer zum Abrufen des Geräteobjekts.

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

Darüber hinaus können CM_Register_Notification verwendet werden, um über Ein- und Auslagerungen von Geräteschnittstellen benachrichtigt zu werden, sodass der Code benachrichtigt wird, wenn die Schnittstelle aktiviert ist, und dann den Zustand abrufen kann. In der Geräteschnittstellenklasse, die in den oben genannten APIs verwendet wird, können mehrere Geräteschnittstellen vorhanden sein. Untersuchen Sie diese Schnittstellen, um zu ermitteln, welche Schnittstelle für die Einstellung gelesen werden soll.

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, von der der Zustand abgerufen werden soll. Rufen Sie dazu IoRegisterPlugPlayNotification auf, um sich für Geräteschnittstellenbenachrichtigungen für die entsprechende Geräteschnittstellenklasse zu registrieren. Rufen Sie alternativ IoGetDeviceInterfaces auf, um eine Liste der aktuellen Geräteschnittstellen auf dem System abzurufen. In der Geräteschnittstellenklasse, die in den oben genannten APIs verwendet wird, können mehrere Geräteschnittstellen vorhanden sein. Untersuchen Sie diese Schnittstellen, um zu ermitteln, welche Schnittstelle die richtige Schnittstelle 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 Zustand der Geräteschnittstelle gespeichert wurde.

Hinweis

Verwenden Sie das CM_GETIDLIST_FILTER_PRESENT-Flag mit CM_Get_Device_ID_List_Size und CM_Get_Device_ID_List oder das CM_GET_DEVICE_INTERFACE_LIST_PRESENT-Flag mit CM_Get_Device_Interface_List_Size und CM_Get_Device_Interface_List. Dadurch wird sichergestellt, dass die Hardware, die sich auf den Zustand bezieht, 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 noch auf einem beliebigen Gerät installiert ist. Einige Optionen zum Entfernen eines Treiberpakets aus dem System lassen jedoch den Versuch zu, es zu "erzwingen". Dadurch wird versucht, das Treiberpaket zu entfernen, auch wenn dieses Treiberpaket noch auf einigen Geräten im System installiert ist. Erzwingen von Entfernungen sind für Treiberpakete mit Dateien, die aus dem Treiberspeicher ausgeführt werden, nicht zulässig. Wenn ein Treiberpaket aus dem System entfernt wird, werden dessen Treiberspeicherinhalte entfernt. Wenn geräte vorhanden sind, die noch mit diesem Treiberpaket installiert sind, sind alle "aus dem Treiberspeicher ausgeführten" Dateien in diesem Treiberpaket jetzt verschwunden, und diese fehlenden Dateien können zu Einer Fehlfunktion des Geräts führen. Um zu verhindern, dass das Gerät in einen fehlerhaften Zustand versetzt wird, können Treiberpakete, die alle "Aus dem Treiberspeicher ausgeführten" Dateien enthalten, nicht erzwungen werden, dass entfernt wird. Sie können nur entfernt werden, wenn sie auf keinem Gerät mehr installiert sind. Zum Entfernen solcher Treiberpakete kann DiUninstallDriver oder pnputil /delete-driver <oem#.inf> /uninstall verwendet werden. Diese Entfernungsmethoden aktualisieren zunächst alle Geräte, die das zu entfernende Treiberpaket verwenden, um nicht mehr mit diesem Treiberpaket installiert zu werden, bevor versucht wird, das Treiberpaket zu entfernen.

Treiberpaketentwicklung

Testen privater Binärdateien

Wenn beim Entwickeln eines Treiberpakets eine bestimmte ausführbare Datei aus dem Treiberpaket durch eine private Version ersetzt werden muss, anstatt das Treiberpaket vollständig neu zu erstellen und auf dem System zu ersetzen, empfiehlt es sich, einen Kerneldebugger zusammen mit dem Befehl .kdfiles zu verwenden. Da der vollständige Pfad zur Datei im Treiberspeicher nicht hartcodiert werden sollte, wird empfohlen, in der KDfiles-Zuordnung der OldDriver-Dateiname nur der direkte Name der Datei ohne vorangehende Pfadinformationen zu sein. Um dies (und andere Szenarien) zu erleichtern, sollten die Namen von Dateien in Treiberpaketen so eindeutig wie möglich sein, damit sie nicht mit dem Namen einer Datei aus einem nicht verwandten Treiberpaket auf dem System übereinstimmen.

Portieren eines INF zur Verwendung der Ausführung aus dem Treiberspeicher

Wenn Sie über ein vorhandenes Treiberpaket mit einem INF verfügen, das die Ausführung aus dem Treiberspeicher nicht verwendet und es portiert, um die Ausführung aus dem Treiberspeicher zu verwenden, zeigen die folgenden Beispiele eine allgemeine Dateiverwendung in INFs und Muster beim Aktualisieren dieser Dateien, die aus DriverStore ausgeführt werden sollen.

Kurzübersicht zu Zielverzeichnisupdates

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

DIRID Unterverzeichnis Details
13 Die Datei verwendet bereits "aus dem Treiberspeicher ausführen". Es sind keine weiteren Arbeiten erforderlich.
1 DIRID 1 sollte nicht verwendet werden. Es gibt keine Garantie, dass das Quellverzeichnis verfügbar ist, wenn ein Verweis auf die Datei aufgelöst werden muss. Wenn Komponenten im Treiberpaket von bestimmten Dateien abhängen, schließen Sie stattdessen 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 aus dem Treiberspeicher" finden Sie unter Erstellen eines Updatetreiberpakets für.
10 Weitere Dateien finden Sie unter Andere Dateien.
11 Weitere Dateien finden Sie unter Andere Dateien.
12 UMDF Weitere Informationen finden Sie unter Binärdatei des UMDF-Treibers.
12 Die meisten Dateien mit einem Ziel von DIRID 12 stellen Treiberdienst-Binärdateien dar. Weitere Informationen finden Sie unter Dienstbinär.
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-Direktive aus einem DDInstall.Software-Abschnitt des Treiberpakets INF. Ausführliche Informationen finden Sie unter Koppeln eines Treibers mit einer Universelle Windows-Plattform-App (UWP).

Dienstbinär

Wenn Ihr INF einen Dienst hinzufügt und die Binärdatei nicht aus dem Treiberspeicher ausgeführt wird, kann Ihr INF wie folgt aussehen:

[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 zur Ausführung aus dem Treiberspeicher zu verschieben, müssen Sie den Eintrag DestinationDirs für den Speicherort aktualisieren, in den die Datei kopiert wird, und die ServiceBinary-Direktive aktualisieren, 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

Binärdatei des UMDF-Treibers

Wenn Ihr INF einen UMDF-Treiber hinzufügt und die Binärdatei nicht aus dem Treiberspeicher ausgeführt wird, sieht Ihr 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 zur Ausführung aus dem Treiberspeicher zu verschieben, müssen Sie den Eintrag DestinationDirs für den Speicherort aktualisieren, in den die Datei kopiert wird, und die ServiceBinary-Direktive aktualisieren, 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 Ihr INF eine Datei hinzufügt, die möglicherweise von anderen Komponenten geladen und nicht aus dem Treiberspeicher ausgeführt wird, sieht Ihr 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ängt davon ab, in welcher Datei sich die Datei befindet %windir%\system32 oder von der Suchreihenfolge von LoadLibrary abhängig ist, die die Datei finden 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 zur Ausführung aus dem Treiberspeicher zu verschieben, müssen Sie den Eintrag DestinationDirs für den Speicherort aktualisieren, in den die Datei kopiert wird, und den Speicherort im Zustand des Geräts aktualisieren. Dies erfordert Komponenten, die diesen Registrierungswert lesen, damit dieser Registrierungswert den vollständigen Pfad zu einer Datei anstelle einer Datei relativ zu %windir%\system32behandeln kann.

[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"