Behandeln einer IRP_MN_QUERY_STOP_DEVICE-Anforderung (Windows 2000 und höher)
Eine IRP_MN_QUERY_STOP_DEVICE Anforderung wird zuerst vom obersten Treiber im Gerätestapel und dann von jedem nächstniedrigten Treiber verarbeitet. Ein Treiber verarbeitet Stopp-IRPs in seiner DispatchPnP-Routine .
Als Reaktion auf eine IRP_MN_QUERY_STOP_DEVICE muss ein Treiber folgendes tun:
Bestimmen Sie, ob das Gerät beendet und die Hardwareressourcen freigegeben werden können, ohne nachteilige Auswirkungen zu haben.
Bei einem Treiber muss ein Abfragestopp-IRP fehlschlagen, wenn einer der folgenden Punkte zutrifft:
Ein Treiber wurde (über IRP_MN_DEVICE_USAGE_NOTIFICATION) benachrichtigt, dass sich das Gerät im Pfad einer Auslagerungs-, Ruhezustands- oder Absturzabbilddatei befindet.
Die Hardwareressourcen des Geräts können nicht freigegeben werden.
Ein Treiber schlägt möglicherweise einen Abfragestopp-IRP fehl, wenn Folgendes zutrifft:
Der Treiber darf keine E/A-Anforderungen löschen und verfügt nicht über einen Mechanismus zum Anstehen von IRPs.
Während sich das Gerät im Zustand beendet befindet, muss ein Treiber IRPs enthalten, die Zugriff auf das Gerät erfordern. Wenn ein Treiber keine IRPs in die Warteschlange stellt, darf er nicht zulassen, dass das Gerät beendet wird, und daher muss ein Abfragestopp-IRP fehlschlagen.
Die Ausnahme von dieser Regel ist ein Gerät, das E/A löschen darf. Die Treiber für ein solches Gerät können Abfragen beenden und Beenden von Anforderungen erfolgreich ausführen, ohne IRPs an der Warteschlange zu halten.
Wenn das Gerät nicht beendet werden kann, schlägt die Abfragestopp-IRP fehl.
Legen Sie Irp-IoStatus.Status> auf einen entsprechenden Fehler status fest, rufen Sie IoCompleteRequest mit IO_NO_INCREMENT auf, und kehren Sie von der DispatchPnP-Routine des Treibers zurück. Übergeben Sie den IRP nicht an den nächst niedrigeren Treiber.
Wenn das Gerät beendet werden kann und der Treiber IRPs in die Warteschlange stellt, legen Sie das HOLD_NEW_REQUESTS-Flag in der Geräteerweiterung fest, damit nachfolgende IRPs in die Warteschlange gestellt werden (siehe Halten eingehender IRPs, wenn ein Gerät angehalten wird).
Alternativ können die Treiber für ein Gerät das Gerät vollständig anhalten, bis die Treiber die nachfolgende IRP_MN_STOP_DEVICE-Anforderung erhalten. Solche Treiber müssen jedoch alle Anforderungen in die Warteschlange stellen, die sie daran hindern würden, beim Eintreffen der Stopp-IRP sofort zu folgen. Bis zum Neustart des Geräts müssen solche Treiber Anforderungen wie die folgenden in die Warteschlange stellen:
IRP_MN_DEVICE_USAGE_NOTIFICATION Anforderungen (z. B. zum Ablegen einer Auslagerungsdatei auf dem Gerät).
Anforderungen für isochrone Übertragungen.
Erstellen Sie Anforderungen, die verhindern würden, dass die Treiber eine Beenden-IRP ausführen.
Wenn auf dem Gerät kein IRP-Fehler auftritt, stellen Sie sicher, dass alle ausstehenden Anforderungen, die an andere Treiberroutinen und niedrigere Treiber übergeben wurden, abgeschlossen sind.
Eine Möglichkeit, dies zu erreichen, besteht darin, eine Verweisanzahl und ein Ereignis zu verwenden, um sicherzustellen, dass alle Anforderungen abgeschlossen wurden:
In seiner AddDevice-Routine definiert der Treiber eine E/A-Referenzanzahl in der Geräteerweiterung und initialisiert die Anzahl auf eins.
Außerdem erstellt der Treiber in seiner AddDevice-Routine ein Ereignis mit KeInitializeEvent und initialisiert das Ereignis im Not-Signaled Zustand mit KeClearEvent.
Jedes Mal, wenn ein IRP verarbeitet wird, erhöht der Treiber die Verweisanzahl mit InterlockedIncrement.
Jedes Mal, wenn eine Anforderung abgeschlossen wird, erhöht der Treiber die Verweisanzahl mit InterlockedDecrement.
Der Treiber erhöht die Referenzanzahl in der IoCompletion-Routine , wenn die Anforderung eine hat, oder direkt nach dem Aufruf von IoCallDriver , wenn der Treiber keine IoCompletion-Routine für die Anforderung verwendet.
Wenn der Treiber eine IRP_MN_QUERY_STOP_DEVICE empfängt, wird die Verweisanzahl mit InterlockedDecrement dekrementiert. Wenn keine ausstehenden Anforderungen vorhanden sind, wird die Verweisanzahl auf 0 reduziert.
Wenn die Referenzanzahl 0 erreicht, legt der Treiber das Ereignis mit KeSetEvent fest, das signalisiert, dass der Abfragestoppcode fortgesetzt werden kann.
Alternativ zum obigen Verfahren kann ein Treiber die IRP_MN_QUERY_STOP_DEVICE IRP hinter allen derzeit ausgeführten IRPs serialisieren.
Führen Sie alle anderen erforderlichen Schritte aus, um das Gerät in den Status "Ausstehender Beenden" zu versetzen.
Nachdem ein Treiber eine Abfragestopp-IRP erfolgreich abgeschlossen hat, muss er bereit sein, eine IRP_MN_STOP_DEVICE erfolgreich auszuführen.
Beenden Sie die IRP.
In einer Funktion oder einem Filtertreiber:
Legen Sie Irp-IoStatus.Status> auf STATUS_SUCCESS fest.
Richten Sie den nächsten Stapelspeicherort mit IoSkipCurrentIrpStackLocation ein, und übergeben Sie den IRP mit IoCallDriver an den nächstniedrigen Treiber.
Verteilen Sie die status von IoCallDriver als Rückgabe status aus der DispatchPnP-Routine.
Schließen Sie die IRP nicht ab.
In einem Bustreiber:
Legen Sie Irp-IoStatus.Status> auf STATUS_SUCCESS fest.
Wenn die Geräte auf dem Bus jedoch Hardwareressourcen verwenden, bewerten Sie die Ressourcenanforderungen des Busses und der untergeordneten Geräte neu. Wenn sich eine der Anforderungen geändert hat, geben Sie STATUS_RESOURCE_REQUIREMENTS_CHANGED anstelle von STATUS_SUCCESS zurück. Diese status zeigt den Erfolg an, fordert jedoch, dass der PnP-Manager Ihre Ressourcen vor dem Senden des Stopp-IRP erneut anforderte.
Schließen Sie die IRP (IoCompleteRequest) mit IO_NO_INCREMENT ab.
Kehren Sie von der DispatchPnP-Routine zurück.
Wenn bei einem Treiber im Gerätestapel der IRP_MN_QUERY_STOP_DEVICE fehlschlägt, sendet der PnP-Manager eine IRP_MN_CANCEL_STOP_DEVICE an den Gerätestapel. Dadurch wird verhindert, dass Treiber eine IoCompletion-Routine für ein Abfragestopp-IRP benötigen, um zu erkennen, ob ein niedrigerer Treiber die IRP ausgeschlagen hat.