DispatchDeviceControl in Higher-Level Treibern
Normalerweise richtet die DispatchDeviceControl-Routine eines Treibers auf höherer Ebene einfach den E/A-Stapelspeicherort für den nächstniedrigen Treiber ein und übergibt die IRP mit IoCallDriver. Die DispatchDeviceControl-Routine überprüft selten die Gültigkeit von Parametern in der Eingabe-IRP, da angenommen wird, dass der zugrunde liegende Gerätetreiber über bessere Informationen zur Behandlung jeder gerätetypspezifischen E/A-Steuerungsanforderung verfügt.
Eine mögliche Ausnahme von dieser allgemeinen Regel ist die DispatchDeviceControl-Routine im Klassentreiber eines Klassen-/Port-Treiberpaars. Weitere Informationen zum Behandeln von Gerätesteuerungsanforderungen in gekoppelten Klassen-/Porttreibern finden Sie unter Dispatch(Internal)DeviceControl in Class/Port Drivers.
Jeder neue Treiber auf höherer Ebene, der nicht eng mit einem bestimmten Gerätetreiber verbunden ist, sollte einfach den E/A-Stapelspeicherort für den nächstniedrigen Treiber einrichten und die IRP_MJ_DEVICE_CONTROL Anforderung zur weiteren Verarbeitung übergeben.
Eine Gerätesteuerungsanforderung wird in der Regel synchron behandelt. Das heißt, die DispatchDeviceControl-Routine eines übergeordneten Treibers kann die Steuerung häufig wie folgt an das System zurückgeben:
: :
return IoCallDriver(DeviceObject->NextDeviceObject, Irp);
Ein Treiber auf höherer Ebene kann jedoch nicht das vorherige Verfahren verwenden, wenn ein niedrigerer Treiber möglicherweise STATUS_PENDING für eine solche Anforderung zurückgibt. In diesem Fall sollte der übergeordnete Treiber IoSetCompletionRoutine aufrufen, um eine IoCompletion-Routine zu registrieren. Wenn die IoCompletion-Routine aufgerufen wird, kann sie den E/A-status-Block überprüfen, um festzustellen, ob der IRP noch aussteht. Wenn dies der Grund ist, kann die IoCompletion-Routine die Anforderung wiederholen oder möglicherweise IoMarkIrpPending aufrufen, bevor IoCompleteRequest aufgerufen wird und STATUS_PENDING zurückgibt. Ein Treiber auf höherer Ebene darf keine IRP mit STATUS_PENDING abschließen, es sei denn, er hat zuerst IoMarkIrpPending für dieses IRP aufgerufen.
Wenn der zugrunde liegende Gerätetreiber viele Daten verarbeiten muss, die vom Gerät übertragen wurden, bevor die Anforderung abgeschlossen wird, kann ein Treiber auf höherer Ebene eine solche Gerätesteuerungsanforderung asynchron verarbeiten. Das heißt, der treiber der höheren Ebene kann IoSetCompletionRoutine aufrufen, um eine IoCompletion-Routine zu registrieren, den IRP an niedrigere Treiber weiterzuleiten und die Steuerung von seiner eigenen DispatchDeviceControl-Routine zurückzugeben.
Fast alle systemdefinierte E/A-Steuerungscodes erfordern, dass der zugrunde liegende Gerätetreiber nur bescheidene Datenmengen übertragen muss, in der Regel viel weniger als eine PAGE_SIZE Menge. In der Regel sollten treiber auf höherer Ebene diese Anforderungen synchron behandeln, wie im vorherigen Codefragment gezeigt, da die niedrigeren Treiber die Steuerung so schnell zurückgeben. Das heißt, der Mehraufwand beim Aufrufen der IoCompletion-Routine des übergeordneten Treibers kompensiert nicht die zusätzliche IRP-Verarbeitung, die der Treiber in einem so kurzen Intervall ausführen kann.
Ein Höherstufiger Treiber, der IRPs mit IoBuildDeviceIoControlRequest für einen zugrunde liegenden Gerätetreiber ordnet, kann diese Gerätesteuerungsanforderungen synchron verarbeiten. Der Treiber der höheren Ebene kann warten, bis ein optionales Ereignisobjekt an IoBuildDeviceIoControlRequest übergeben und dem vom Treiber zugewiesenen IRP zugeordnet wird.