Unterstützung Kernel-Mode Clients in UMDF 1.x-Treibern

Warnung

UMDF 2 ist die neueste Version von UMDF und ersetzt UMDF 1. Alle neuen UMDF-Treiber sollten mit UMDF 2 geschrieben werden. UMDF 1 werden keine neuen Features hinzugefügt, und die Unterstützung für UMDF 1 in neueren Versionen von Windows 10 ist eingeschränkt. Universelle Windows-Treiber müssen UMDF 2 verwenden.

Die archivierten UMDF 1-Beispiele finden Sie im Treiberbeispielupdate Windows 11, Version 22H2 – Mai 2022.

Weitere Informationen finden Sie unter Erste Schritte mit UMDF.

Warnung

Weitere Informationen finden Sie unter Unterstützen Kernel-Mode Clients in UMDF 2.x.

MIT UMDF-Versionen 1.9 und höher können UMDF-Treiber Clients im Kernelmodus unterstützen. Ein Client im Kernelmodus kann einer der folgenden Sein:

  • Ein Kernelmodustreiber, der über einem UMDF-Treiber im Treiberstapel eines Geräts vorhanden ist.

  • Ein Kernelmodustreiber für einen Gerätestapel, der ein Gerät unterstützt, öffnet ein Handle für ein anderes Gerät, und der Treiberstapel des geräts enthält einen UMDF-Treiber.

Anders ausgedrückt: Ein UMDF-Treiber, der Clients im Kernelmodus unterstützt, kann E/A-Anforderungen von einem Kernelmodustreiber empfangen. Der Kernelmodustreiber kann E/A-Anforderungen weiterleiten, die er von einer Benutzermodusanwendung empfangen hat, oder neue E/A-Anforderungen erstellen und an den Benutzermodustreiber senden.

Um zu ermitteln, ob Ihr UMDF-Treiber Clients im Kernelmodus unterstützen muss, müssen Sie den Treiberstapel kennen, dem Ihr Treiber hinzugefügt wird, und wissen, wo sich ihr Treiber in diesem Stapel befindet. Außerdem müssen Sie ermitteln, ob ein Treiber aus einem anderen Stapel E/A-Anforderungen an das Gerät Ihres Treibers sendet.

Ihr Treiber muss Clients im Kernelmodus unterstützen, wenn:

  • Ein Kernelmodustreiber kann sich direkt über Ihrem UMDF-Treiber in einem Treiberstapel befinden. Beispielsweise kann sich ein Kernelmodusfiltertreiber direkt über einem UMDF-basierten Funktionstreiber befinden.

  • Ein Kernelmodustreiber aus einem anderen Stapel kann E/A-Anforderungen an das Gerät Ihres Treibers senden. Ihr Treiber könnte beispielsweise eine symbolische Verknüpfung erstellen, die ein Kernelmodustreiber in einem anderen Stapel verwenden kann, um ein Handle für das Gerät Ihres Treibers zu öffnen. Der Kernelmodustreiber kann dann E/A-Anforderungen an das Gerät senden.

Unterstützen von Kernelmodusclients in einem UMDF-Treiber

Ein UMDF-Treiber kann E/A-Anforderungen von einem Kernelmodustreiber nur empfangen, wenn der UMDF-Treiber die Unterstützung für Kernelmodusclients aktiviert hat. Wenn eine Geräteinstallation versucht, Kernelmodustreiber oberhalb eines UMDF-Treibers im Treiberstapel des Geräts zu laden, ermöglicht das Framework den Treibern das Laden nur, wenn der UMDF-Treiber die Unterstützung für Kernelmodusclients aktiviert hat.

Um die Unterstützung eines UMDF-Treibers für Clients im Kernelmodus zu aktivieren, muss die INF-Datei des UMDF-Treibers eine UmdfKernelModeClientPolicy-Direktive in ihrem INF DDInstall enthalten. WDF-Abschnitt . Wenn die INF-Datei des UMDF-Treibers diese Direktive nicht enthält, lässt UMDF die Ausführung eines Kernelmodustreibers, der oberhalb des UMDF-Treibers installiert ist, nicht zu.

Das Framework stellt zwei Methoden bereit, die für Treiber nützlich sind, die Clients im Kernelmodus unterstützen. Ein Treiber kann die IWDFIoRequest2::GetRequestorMode-Methode aufrufen, um zu bestimmen, ob eine E/A-Anforderung aus dem Kernel- oder Benutzermodus stammt. Wenn die E/A-Anforderung aus dem Benutzermodus stammt, kann der Treiber IWDFIoRequest2::IsFromUserModeDriver aufrufen, um zu ermitteln, ob die Anforderung von einer Anwendung oder einem anderen Benutzermodustreiber stammt.

Einschränkungen für Kernelmodustreiber

Ein UMDF-Treiber kann E/A-Anforderungen von einem Kernelmodustreiber nur verarbeiten, wenn der Kernelmodustreiber die folgenden Anforderungen erfüllt:

  • Der Kernelmodustreiber muss unter IRQL = PASSIVE_LEVEL ausgeführt werden, wenn er die E/A-Anforderung sendet.

  • Sofern der Treiber die UmdfFileObjectPolicy INF-Direktive nicht auf AllowNullAndUnknownFileObjects festgelegt hat, muss jede E/A-Anforderung, die ein Kernelmodustreiber an einen Benutzermodustreiber sendet, über ein zugeordnetes Dateiobjekt verfügen. Das Framework muss zuvor benachrichtigt worden sein, dass der E/A-Manager das Dateiobjekt erstellt hat. (Eine solche Benachrichtigung bewirkt, dass das Framework die Rückruffunktion IQueueCallbackCreate::OnCreateFile des Benutzermodustreibers aufruft, diese Rückruffunktion ist jedoch optional.)

  • Die E/A-Anforderung kann keinen IRP_MJ_INTERNAL_DEVICE_CONTROL Funktionscode enthalten.

  • Die Puffer der E/A-Anforderung dürfen keine Zeiger auf zusätzliche Informationen enthalten, da der Benutzermodustreiber die Zeiger nicht dereferenzieren kann.

  • Wenn die E/A-Anforderung einen E/A-Steuerungscode enthält, der die Pufferzugriffsmethode "weder" angibt, muss der Kernelmodustreiber die E/A-Anforderung im Prozesskontext der Anwendung senden, die die E/A-Anforderung erstellt hat. Weitere Informationen zur Unterstützung der "neither"-Methode in einem UMDF-Basistreiber finden Sie unter Verwenden von weder gepufferten E/A- noch direkten E/A-Vorgängen in UMDF-Treibern.

  • Der UMDF-Treiber kann die Ausgabedaten einer E/A-Anforderung im Benutzermodus ändern. Daher muss der Kernelmodustreiber alle Ausgabedaten überprüfen, die er vom Benutzermodustreiber empfängt.

  • Der Kernelmodusclient sollte in der Regel den Informationswert überprüfen, den ein UMDF-Treiber an IWDFIoRequest::CompleteWithInformation übergibt. Wenn der Client ein KMDF-Treiber ist, kann er WdfRequestGetCompletionParams aufrufen, um diese Informationen in einer IO_STATUS_BLOCK-Struktur abzurufen.

    In der Regel überprüft das Framework nicht den Informationswert, den ein UMDF-Treiber an IWDFIoRequest::CompleteWithInformation übergibt. (Dieser Parameter gibt in der Regel die Anzahl der übertragenen Bytes an.) Das Framework überprüft den Informationswert nur für Ausgabepuffer und nur für die gepufferte E/ A-Datenzugriffsmethode. (Das Framework überprüft beispielsweise, ob die Anzahl der übertragenen Bytes die Ausgabepuffergröße eines Lesevorgangs nicht überschreitet, wenn die Zugriffsmethode gepuffert ist.)

Die Behandlung gibt status Werte in einem UMDF 1.x-Treiber zurück.

Die Übergabe status Rückgabewerte aus dem Benutzermodus an den Kernelmodus erfordert besondere Aufmerksamkeit, wie folgt:

  • UMDF-Treiber der Version 1 erhalten in der Regel HRESULT-typisierte Rückgabewerte, während KMDF- und WDM-basierte Kernelmodustreiber in der Regel NTSTATUS-typisierte Werte empfangen. Wenn ein UMDF 1. Der x-Treiber führt eine E/A-Anforderung aus, und wenn der Treiber über einen Client im Kernelmodus verfügt, sollte der Aufruf des Treibers an IWDFIoRequest::Complete oder IWDFIoRequest::CompleteWithInformation einen HRESULT-Wert angeben, den der Treiber aus einem NTSTATUS-Wert generiert. Im Allgemeinen gilt UMDF 1. x-Treiber sollten das makro HRESULT_FROM_NT (definiert in Winerror.h) verwenden, um status an einen Kernelmodusclient zurückzugeben. Im folgenden Beispiel wird gezeigt, wie Sie dieses Makro beim Abschließen einer Anforderung verwenden.

    hr = HRESULT_FROM_NT(STATUS_BUFFER_OVERFLOW)
    request->Complete(HRESULT_FROM_NT(STATUS_BUFFER_OVERFLOW);
    return hr;
    

    Um einen bestimmten HRESULT-Wert an einen Kernelmodusclient zurückzugeben, müssen die folgenden Rückrufe das makro HRESULT_FROM_NT verwenden:

    Zum Verwenden der NTSTATUS-Werte, die in ntstatus.h, einem UMDF 1, definiert sind. Der x-Treiber muss diese beiden Zeilen enthalten, bevor zusätzliche Header eingeschlossen werden.

    #define UMDF_USING_NTSTATUS
    #include <ntstatus.h>
    

    Verwenden Sie das Makro HRESULT_FROM_NT nicht, um STATUS_SUCCESS von einem NTSTATUS-Wert in einen HRESULT-Wert zu konvertieren. Geben Sie einfach S_OK zurück, wie im folgenden Beispiel gezeigt.

    request->Complete(S_OK);
    
  • Das Framework schließt einige E/A-Anforderungen im Namen von UMDF-Treibern ab. Manchmal konvertiert das Framework HRESULT-typisierte Rückgabewerte nicht in gleichwertige NTSTATUS-Werte, sodass das Framework möglicherweise einen HRESULT-typisierten Abschluss status an einen Client im Kernelmodus übergibt.

    Aus diesem Grund sollten Clients im Kernelmodus beim Testen des Abschlusses einer E/A-Anforderung status nicht das Makro NT_ERROR verwenden, da das NT_ERROR Makro für HRESULT-Fehlerwerte nicht TRUE zurückgibt. Kernelmodustreiber sollten das makro NT_SUCCESS verwenden, wenn sie die Abschluss einer E/A-Anforderung status testen.

Unterstützung des Kernelmodusclients in früheren UMDF-Versionen

Bei UMDF-Versionen vor Version 1.9 kann die INF-Datei eines Treibers eine INF AddReg-Direktive enthalten, um einen REG_DWORD UpperDriverOk-Registrierungswert unter dem WUDF-Unterschlüssel des Hardwareschlüssels des Geräts zu erstellen.

Wenn der Registrierungswert UpperDriverOk auf eine Nicht-Null-Zahl festgelegt ist, ermöglicht das Framework das Laden von Kernelmodustreibern über dem Benutzermodustreiber. Die Kernelmodustreiber können E/A-Anforderungen von Anwendungen im Benutzermodus an den UMDF-Treiber weiterleiten, aber Kernelmodustreiber können keine E/A-Anforderungen senden, die im Kernelmodus erstellt werden, an den UMDF-Treiber.

Für UMDF-Versionen 1.9 und höher ist der Registrierungswert UpperDriverOk veraltet und wird nur für vorhandene Treiber unterstützt. Neue Treiber sollten die UmdfKernelModeClientPolicy-Direktive verwenden.