Abschließen von E/A-Anforderungen in UMDF
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.
Jede E/A-Anforderung muss schließlich von einem UMDF-Treiber abgeschlossen werden. Um eine Anforderung abzuschließen, muss der Treiber entweder die IWDFIoRequest::Complete - oder IWDFIoRequest::CompleteWithInformation-Methode aufrufen. Wenn der Treiber die Anforderung abschließt, gibt dies eines der folgenden Szenarien an:
Der angeforderte E/A-Vorgang wurde erfolgreich abgeschlossen.
Der angeforderte E/A-Vorgang wurde gestartet, ist aber nicht erfolgreich, bevor er abgeschlossen wurde.
Der angeforderte E/A-Vorgang wird nicht unterstützt oder ist zum Zeitpunkt des Empfangens ungültig und kann daher nicht mit dem Gerät kommunizieren.
Der angeforderte E/A-Vorgang wurde abgebrochen.
Der Treiber ruft die IWDFIoRequest::CompleteWithInformation-Methode auf, um zusätzliche Informationen zum Anforderungsvorgang zu übergeben. Beispielsweise sollte der Treiber für einen Lesevorgang die Anzahl der gelesenen Bytes angeben.
Um eine E/A-Anforderung abzuschließen, muss der Treiber die entsprechende Vervollständigung status an den CompletionStatus-Parameter im Aufruf von IWDFIoRequest::Complete oder IWDFIoRequest::CompleteWithInformation übergeben. Der Treiber verwendet einen HRESULT-Code, um die status der abgeschlossenen Anforderung zu kommunizieren.
Der UMDF-Treiberhostprozess konvertiert den HRESULT-Code in einen NTSTATUS-Code, bevor er die abgeschlossene Anforderung an den Reflektor (Wudfrd.sys) übergibt. Der Reflektor übergibt den NTSTATUS-Code an das Betriebssystem. Das Betriebssystem konvertiert den NTSTATUS-Code in einen Microsoft Win32-Fehlercode, bevor das Ergebnis der aufrufenden Anwendung angezeigt wird.
Um sicherzustellen, dass die Fehlercodes Ihres Treibers ordnungsgemäß konvertiert werden können, sollten Sie Fehlercodes mit einer der folgenden Techniken erstellen:
Verwenden Sie einen Fehlercode von Winerror.h, und wenden Sie das makro HRESULT_FROM_WIN32 an.
Verwenden Sie einen Fehlercode von Ntstatus.h, und wenden Sie das makro HRESULT_FROM_NT an.
Weitere Informationen zu diesen Makros finden Sie in der Dokumentation zu Microsoft Windows SDK.
Der folgende Beispielcode zeigt, wie Sie eine Anforderung mit einem geeigneten Fehlercode abschließen:
VOID
STDMETHODCALLTYPE
CMyQueue::OnWrite(
__in IWDFIoQueue *pWdfQueue,
__in IWDFIoRequest *pWdfRequest,
__in SIZE_T BytesToWrite
)
{
--------------------
if( BytesToWrite > MAX_WRITE_LENGTH ) {
pWdfRequest->CompleteWithInformation(HRESULT_FROM_WIN32(ERROR_MORE_DATA), 0);
return;
}
---------------------
}
Wenn ein Treiber eine Anforderung erfolgreich abschließt, gibt er S_OK zurück, bei dem es sich um einen HRESULT-Wert handelt. Da S_OK NO_ERROR in Winerror.h und STATUS_SUCCESS in Ntstatus.h entspricht, sind die Konvertierungsmakros nicht erforderlich.
Wenn die Treiberüberprüfung für den Reflektor aktiviert ist, wird ein ungültiger status Code identifiziert und eine Systemfehlerprüfung verursacht.
Hinweis Die Treiberüberprüfung für Windows XP verursacht fälschlicherweise eine Systemfehlerüberprüfung für Win32-Fehlercodes, deren Werte dezimal 1024 (1024L) überschreiten. Wenn Ihr Treiber unter Windows XP ausgeführt wird, beachten Sie dieses Problem, wenn Sie die Treiberüberprüfung für den Reflektor aktivieren.
Wenn der Treiber zuvor eine Anforderung an einen Treiber auf niedrigerer Ebene gesendet hat, benötigt der Treiber eine Benachrichtigung, wenn der Treiber auf niedrigerer Ebene die Anforderung abgeschlossen hat. Um sich für die Benachrichtigung zu registrieren, ruft der Treiber die IWDFIoRequest::SetCompletionCallback-Methode auf, um die Schnittstelle für die Methode zu registrieren, die das Framework aufruft, wenn der Treiber der niedrigeren Ebene die Anforderung abschließt. Der Treiber implementiert die Rückruffunktion IRequestCallbackRequestCompletion::OnCompletion , um die vorgänge auszuführen, die zum Abschließen der Anforderung erforderlich sind.
Ein Treiber führt keine E/A-Anforderung durch, die er durch Aufrufen von IWDFDevice::CreateRequest erstellt hat. Stattdessen muss der Treiber IWDFObject::D eleteWdfObject aufrufen, um das Anforderungsobjekt zu löschen, in der Regel, nachdem ein E/A-Ziel die Anforderung abgeschlossen hat.
Beispielsweise kann ein Treiber eine Lese- oder Schreibanforderung für eine Datenmenge erhalten, die größer ist als die E/A-Ziele des Treibers gleichzeitig verarbeiten können. Der Treiber muss die Daten in mehrere kleinere Anforderungen unterteilen und diese kleineren Anforderungen an ein oder mehrere E/A-Ziele senden. Zu den Verfahren zur Behandlung dieser Situation gehören:
Aufrufen von IWDFDevice::CreateRequest , um ein einzelnes zusätzliches Anforderungsobjekt zu erstellen, das eine kleinere Anforderung darstellt.
Der Treiber kann diese Anforderung synchron an ein E/A-Ziel senden. Die Rückruffunktion IRequestCallbackRequestCompletion::OnCompletion der kleineren Anforderung kann IWDFIoRequest2::Reuse aufrufen, damit der Treiber die Anforderung wiederverwenden und erneut an das E/A-Ziel senden kann. Nachdem das E/A-Ziel die letzte der kleineren Anforderungen abgeschlossen hat, kann die OnCompletion-RückruffunktionIWDFObject::D eleteWdfObject aufrufen, um das vom Treiber erstellte Anforderungsobjekt zu löschen, und der Treiber kann IWDFIoRequest::Complete aufrufen, um die ursprüngliche Anforderung abzuschließen.
Aufrufen von IWDFDevice::CreateRequest , um mehrere zusätzliche Anforderungsobjekte zu erstellen, die die kleineren Anforderungen darstellen.
Die E/A-Ziele des Treibers können diese mehrere kleinere Anforderungen asynchron verarbeiten. Der Treiber kann eine OnCompletion-Rückruffunktion für jede der kleineren Anforderungen registrieren. Jedes Mal, wenn die OnCompletion-Rückruffunktion aufgerufen wird, kann sie IWDFObject::D eleteWdfObject aufrufen, um ein vom Treiber erstelltes Anforderungsobjekt zu löschen. Nachdem das E/A-Ziel alle kleineren Anforderungen abgeschlossen hat, kann der Treiber IWDFIoRequest::Complete aufrufen, um die ursprüngliche Anforderung abzuschließen.
Abrufen von Abschlussinformationen
Um Informationen zu einer E/A-Anforderung zu erhalten, die ein anderer Treiber abgeschlossen hat, kann ein UMDF-basierter Treiber:
Verwenden Sie die IWDFRequestCompletionParams-Schnittstelle, um den Abschluss einer E/A-Anforderung status und andere Informationen zu erhalten.
Verwenden Sie die IWDFIoRequestCompletionParams-Schnittstelle , um die Speicherpuffer einer E/A-Anforderung abzurufen.
Verwenden Sie die IWDFUsbRequestCompletionParams-Schnittstelle , um Speicherpuffer und andere Informationen im Zusammenhang mit einer Anforderung abzurufen, die an ein USB-Zielpipeobjekt gesendet wurde.
Darüber hinaus kann ein UMDF-basierter Treiber die IWDFIoRequest2::GetStatus-Methode verwenden, um die aktuelle status einer E/A-Anforderung zu erhalten, entweder vor oder nach Abschluss der Anforderung.