Übergeben von IRPs im Treiberstapel

Wenn die Dispatchroutine eines Treibers einen IRP empfängt, muss er IoGetCurrentIrpStackLocation aufrufen, damit er seinen eigenen E/A-Stapelspeicherort überprüfen und ermitteln kann, ob alle Parameter gültig sind. Wenn der Treiber die Anforderung selbst nicht erfüllen und abschließen kann, kann er eine der folgenden Aktionen ausführen:

  • Übergeben Sie das IRP zur weiteren Verarbeitung durch Treiber niedrigerer Ebene.

  • Erstellen Sie eine oder mehrere neue IRPs, und übergeben Sie sie an Treiber auf niedrigerer Ebene.

Ein Treiber auf höherer Ebene sollte eine E/A-Anforderung wie folgt an einen nächstniedrigen Treiber übergeben:

  1. Wenn der Treiber die Eingabe-IRP an den nächsten Treiber auf niedrigerer Ebene weiterleitet, sollte die Dispatchroutine IoSkipCurrentIrpStackLocation oder IoCopyCurrentIrpStackLocationToNext aufrufen, um den E/A-Stapelspeicherort des nächstniedrigen Treibers einzurichten.

    Wenn der Treiber IoAllocateIrp aufruft , um eine oder mehrere zusätzliche IRPs für niedrigere Treiber zuzuweisen, muss die Dispatchroutine den E/A-Stapelspeicherort des nächstniedrigen Treibers initialisieren, indem die unter Verarbeiten von IRPs in einem Intermediate-Level Driver beschriebenen Schritte ausgeführt werden.

    Die Dispatchroutine kann einige der Parameter am E/A-Stapelspeicherort des nächstniedrigen Treibers für bestimmte Anforderungen ändern. Beispielsweise kann ein Treiber auf höherer Ebene die Parameter für eine große Übertragungsanforderung ändern, wenn das zugrunde liegende Gerät über ein bekanntes Limit für die Übertragungskapazität verfügt, und das IRP wiederverwenden, um Teilübertragungsanforderungen an den zugrunde liegenden Gerätetreiber zu senden.

  2. Rufen Sie IoSetCompletionRoutine auf.

    Wenn die Dispatchroutine einen empfangenen IRP an den nächstniedrigen Treiber übergibt, ist das Festlegen einer IoCompletion-Routine optional, aber nützlich, da die Routine Aufgaben ausführen kann, z. B. das Bestimmen, wie niedrigere Treiber die Anforderung abgeschlossen haben, die Wiederverwendung des IRP für Teilübertragungen, das Aktualisieren des Zustands, den der Treiber bei der Nachverfolgung von IRPs hat, und das Wiederholen einer Anforderung, die mit einem Fehler zurückgegeben wurde.

    Wenn die Dispatchroutine neue IRPs zugeordnet hat, ist das Festlegen einer IoCompletion-Routine erforderlich, da die Routine jedes IRP freigeben muss, nachdem niedrigere Treiber sie abgeschlossen haben.

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

  3. Rufen Sie IoCallDriver mit jedem IRP auf, der von niedrigeren Treibern verarbeitet werden soll.

  4. Gibt einen geeigneten NTSTATUS-Wert zurück, z. B.:

    • STATUS_PENDING

      Der Treiber gibt in der Regel STATUS_PENDING zurück, wenn es sich bei der Eingabe-IRP um eine asynchrone Anforderung handelt, z. B. IRP_MJ_READ oder IRP_MJ_WRITE.

    • Das Ergebnis des Aufrufs von IoCallDriver

      Der Treiber gibt häufig das Ergebnis des Aufrufs von IoCallDriver zurück, wenn die Eingabe-IRP eine synchrone Anforderung ist, z. B. IRP_MJ_CREATE.

Ein Gerätetreiber der niedrigsten Ebene übergibt alle IRP, die er in seiner Dispatchroutine nicht abschließen kann, wie folgt an andere Treiberroutinen:

  1. Rufen Sie IoMarkIrpPending mit dem Eingabe-IRP auf.

  2. Rufen Sie IoStartPacket auf, um das IRP an die StartIo-Routine des Treibers zu übergeben oder in eine Warteschlange zu stellen, es sei denn, der Treiber verwaltet seine eigene interne IRP-Warteschlange, wie unter Treiberverwaltete IRP-Warteschlangen beschrieben.

    Wenn der Treiber über keine StartIo-Routine verfügt, aber abbruchfähige IRPs verarbeitet, muss er entweder eine Cancel-Routine registrieren oder eine abbruchsichere IRP-Warteschlange implementieren. Weitere Informationen zu Cancel-Routinen finden Sie unter Abbrechen von IRPs.

  3. Gibt STATUS_PENDING zurück.