Freigeben über


IO_COMPLETION_ROUTINE Rückruffunktion (wdm.h)

Die IoCompletion-Routine schließt die Verarbeitung von E/A-Vorgängen ab.

Syntax

IO_COMPLETION_ROUTINE IoCompletionRoutine;

NTSTATUS IoCompletionRoutine(
  [in]           PDEVICE_OBJECT DeviceObject,
  [in]           PIRP Irp,
  [in, optional] PVOID Context
)
{...}

Parameter

[in] DeviceObject

Vom Aufrufer bereitgestellter Zeiger auf eine DEVICE_OBJECT-Struktur . Dies ist das Geräteobjekt für das Zielgerät, das zuvor von der AddDevice-Routine des Treibers erstellt wurde.

[in] Irp

Vom Aufrufer bereitgestellter Zeiger auf eine IRP-Struktur , die den E/A-Vorgang beschreibt.

[in, optional] Context

Vom Aufrufer bereitgestellter Zeiger auf treiberspezifische Kontextinformationen, der zuvor beim Aufrufen von IoSetCompletionRoutine oder IoSetCompletionRoutineEx bereitgestellt wurde. Kontextinformationen müssen im nicht ausgelagerten Arbeitsspeicher gespeichert werden, da eine IoCompletion-Routine bei DISPATCH_LEVEL aufgerufen werden kann. Weitere Informationen finden Sie im folgenden Abschnitt "Hinweise".

Rückgabewert

Wenn die IoCompletion-Routine feststellt, dass für das IRP zusätzliche Verarbeitung erforderlich ist, muss STATUS_MORE_PROCESSING_REQUIRED zurückgegeben werden. Weitere Informationen finden Sie im folgenden Abschnitt "Hinweise". Andernfalls sollte STATUS_SUCCESS zurückgegeben werden. (Der E/A-Manager überprüft nur, ob STATUS_MORE_PROCESSING_REQUIRED vorhanden oder nicht vorhanden ist.)

Hinweise

Die IoCompletion-Routine eines Treibers wird in einem beliebigen Thread oder DPC-Kontext und in einem IRQL ausgeführt, der kleiner als oder gleich DISPATCH_LEVEL ist. Da Code, der für die Ausführung mit DISPATCH_LEVEL geschrieben wurde, auch auf niedrigeren Ebenen ausgeführt wird, sollten IoCompletion-Routinen für die Ausführung bei DISPATCH_LEVEL konzipiert werden. Da diese Routinen jedoch nicht garantiert DISPATCH_LEVEL ausgeführt werden, dürfen sie keine Systemroutinen aufrufen, die tatsächlich eine Ausführung bei DISPATCH_LEVEL erfordern. (Weitere Informationen zu IRQLs finden Sie unter Verwalten von Hardwareprioritäten.)

Um eine IoCompletion-Routine für ein bestimmtes IRP zu registrieren, muss ein Treiber IoSetCompletionRoutine oder IoSetCompletionRoutineEx aufrufen, in dem die Adresse der IoCompletion-Routine am E/A-Stapelspeicherort des nächstniedrigen Treibers gespeichert wird. (Daher kann ein Treiber der niedrigsten Ebene keine IoCompletion-Routine registrieren.) Ein Treiber ruft in der Regel IoSetCompletionRoutine oder IoSetCompletionRoutineEx von einer seiner Dispatchroutines auf, jedes Mal, wenn ein IRP empfangen wird. Die meisten Treiber, einschließlich aller PnP-Treiber, können IoSetCompletionRoutine verwenden, um ihre IoCompletion-Routine zu registrieren. Nicht-PnP-Treiber, die möglicherweise entladen werden, bevor ihre IoCompletion-Routine ausgeführt wird, sollten stattdessen IoSetCompletionRoutineEx verwenden.

Wenn ein Treiber einen IRP abschließt, ruft er IoCompleteRequest auf, das wiederum die IoCompletion-Routine jedes Treibers höherer Ebene vom nächsthöheren zum höchsten aufruft, bis alle höheren IoCompletion-Routinen aufgerufen wurden oder bis eine Routine STATUS_MORE_PROCESSING_REQUIRED zurückgibt.

Wenn Sie das IRP erstellen, ordnen Sie einen Stapelspeicherort für den aktuellen Treiber sowie alle niedrigeren Treiber zu. Wenn Sie nicht genügend Stapelspeicherorte zuordnen, wird der DeviceObject-Zeiger möglicherweise auf NULL festgelegt, wenn die Vervollständigungsroutine aufgerufen wird. Sie können das Zuweisen eines zusätzlichen Stapelspeicherorts für den aktuellen Treiber vermeiden, wenn Sie das Feld Kontext verwenden, um Informationen an IoCompletion zu übergeben, anstatt sich auf den DeviceObject-Parameter zu verlassen.

Wenn eine IoCompletion-Routine STATUS_MORE_PROCESSING_REQUIRED zurückgibt, wird der Aufruf des unteren Treibers an IoCompleteRequest sofort zurückgegeben. In diesem Fall muss ein Treiber auf höherer Ebene IoCompleteRequest aufrufen, um das IRP abzuschließen.

Weitere Informationen zum Implementieren von IoCompletion-Routinen finden Sie unter Abschließen von IRPs.

Beispiele

Um eine IoCompletion-Rückrufroutine zu definieren, müssen Sie zunächst eine Funktionsdeklaration bereitstellen, die den Typ der Rückrufroutine identifiziert, die Sie definieren. Windows bietet eine Reihe von Rückruffunktionstypen für Treiber. Das Deklarieren einer Funktion mithilfe der Rückruffunktionstypen hilft der Codeanalyse für Treiber, der statischen Treiberüberprüfung (Static Driver Verifier , SDV) und anderen Überprüfungstools, Fehler zu finden, und es ist eine Voraussetzung für das Schreiben von Treibern für das Windows-Betriebssystem.

Um beispielsweise eine IoCompletion-Rückrufroutine mit dem Namen MyIoCompletionzu definieren, verwenden Sie den typ IO_COMPLETION_ROUTINE, wie in diesem Codebeispiel gezeigt:

IO_COMPLETION_ROUTINE MyIoCompletion;

Implementieren Sie dann Ihre Rückrufroutine wie folgt:

_Use_decl_annotations_
NTSTATUS
  MyIoCompletion(
    PDEVICE_OBJECT  DeviceObject,
    PIRP  Irp,
    PVOID  Context
    )
  {
      // Function body
  }

Der IO_COMPLETION_ROUTINE Funktionstyp ist in der Wdm.h-Headerdatei definiert. Um Fehler beim Ausführen der Codeanalysetools genauer zu identifizieren, fügen Sie die _Use_decl_annotations_ Anmerkung ihrer Funktionsdefinition hinzu. Die _Use_decl_annotations_ Anmerkung stellt sicher, dass die Anmerkungen verwendet werden, die auf den IO_COMPLETION_ROUTINE Funktionstyp in der Headerdatei angewendet werden. Weitere Informationen zu den Anforderungen für Funktionsdeklarationen finden Sie unter Deklarieren von Funktionen mithilfe von Funktionsrollentypen für WDM-Treiber. Informationen zu _Use_decl_annotations_finden Sie unter Verhalten von Funktionen mit Anmerkungen.

Anforderungen

Anforderung Wert
Zielplattform Desktop
Header wdm.h (einschließlich Wdm.h, Ntddk.h, Ntifs.h)
IRQL Wird unter IRQL <= DISPATCH_LEVEL aufgerufen (siehe Abschnitt "Hinweise").