Freigeben über


Erstellen von IOCTL-Anforderungen in Treibern

Ein Klassentreiber oder ein anderer treiber höherer Ebene kann IRPs für E/A-Steuerungsanforderungen zuordnen und sie wie folgt an den nächstniedrigen Treiber senden:

  1. Ordnen Sie ein E/A-Anforderungspaket (IRP) mit dem Hauptfunktionscode IRP_MJ_DEVICE_CONTROL oder IRP_MJ_INTERNAL_DEVICE_CONTROL zu, oder verwenden Sie sie wieder. Sie können die IoBuildDeviceIoControlRequest-Routine verwenden, um eine IOCTL-IRP speziell zuzuordnen. Sie können auch allgemeine IRP-Erstellungs- und Initialisierungsroutinen wie IoAllocateIrp, IoReuseIrp oder IoInitializeIrp verwenden. Weitere Informationen zur IRP-Zuordnung finden Sie unter Erstellen von IRPs für Lower-Level-Treiber.

  2. Richten Sie den E/A-Stapelspeicherort des niedrigeren Treibers für den IRP mit dem IOCTL_XXX-Code und den entsprechenden Parametern ein.

  3. Wenn die IOCTL-Anforderung asynchron abgeschlossen werden soll, rufen Sie die KeInitializeEvent-Routine auf, um ein Ereignisobjekt als Benachrichtigungsereignis zu initialisieren. Der Treiber verwendet dieses Ereignis, um auf den Abschluss eines E/A-Vorgangs zu warten.

  4. Rufen Sie IoSetCompletionRoutine mit dem IRP auf, damit der obere Treiber bei Bedarf eine IoCompletion-Routine bereitstellen kann, um folgendes auszuführen:

    • Bestimmen Sie, wie der niedrigere Treiber eine bestimmte Anforderung verarbeitet hat.

    • Verwenden Sie das IRP wieder, um eine weitere Anforderung zu senden oder das vom Treiber erstellte IRP zu löschen, nachdem der niedrigere Treiber einen angeforderten Vorgang abgeschlossen hat. Der Treiber kann die von IoBuildDeviceIoControlRequest erstellten IRPs nicht wiederverwenden. Weitere Informationen finden Sie unter Wiederverwenden von IRPs.

  5. Rufen Sie IoCallDriver auf, um die Anforderung an den unteren Treiber zu übergeben.

  6. Wenn IoCallDriver STATUS_PENDING zurückgibt, rufen Sie die KeWaitForSingleObject-Routine auf, um den aktuellen Thread in einen Wartezustand zu versetzen. Der Treiber legt den Object-Parameter der Routine auf die Adresse des Ereignisobjekts fest, das im Aufruf von KeInitializeEvent initialisiert wurde.

    Hinweis Wenn der Treiber KeWaitForSingleObject mit seinem Timeout-Parameter aufruft, der entweder auf NULL oder auf die Adresse einer Variablen festgelegt ist, die einen Wert ungleich null enthält, muss der Treiber unter IRQL <= APC_LEVEL in einem nichtarbiträren Threadkontext ausgeführt werden. Andernfalls muss der Treiber unter IRQL <= DISPATCH_LEVEL ausgeführt werden.

Das Ereignis wird von seiner IoCompletion-Routine signalisiert, wenn die IOCTL-Anforderung abgeschlossen wurde. Sobald das Ereignis signalisiert wurde, setzt der Thread die Ausführung fort.

Wichtig Wenn der Treiber das Ereignisobjekt als lokale Variable im Stapel zuordnet, muss der Treiber KeWaitForSingleObject aufrufen, wobei der WaitMode-Parameter auf KernelMode festgelegt ist. Dieser Parameterwert verhindert, dass der Stapel ausgelagert wird.

Um Synchronisierungsprobleme und mögliche Zugriffsverletzungen zu vermeiden, enthalten Parameter für E/A-Kontrollcodes selten eingebettete Zeiger. Mit Ausnahme bestimmter SCSI-Anforderungen werden die Puffer bei Irp-AssociatedIrp> verwendet. SystemBuffer, bei Irp-MdlAddress> und unterParameters. DeviceIoControl. Type3InputBuffer am E/A-Stapelspeicherort eines Treibers enthält weder Zeiger auf andere Datenpuffer noch Strukturen, die Zeiger für systemdefinierte E/A-Steuercodes enthalten. Weitere Informationen zur Verwendung von Datenpuffern mit IRPs, die E/A-Steuercodes enthalten, finden Sie unter Pufferbeschreibungen für E/A-Steuerungscodes.

Dennoch kann ein Paar von Klassen-/Porttreibern, die interne E/A-Steuerungscodes definieren, einen eingebetteten Zeiger auf den vom Treiber zugewiesenen Speicher vom Treiber auf höherer Ebene an den Treiber der niedrigeren Ebene übergeben. Ein solches Paar von Klassen-/Porttreibern ist dafür verantwortlich, sicherzustellen, dass Folgendes zutrifft:

  • Nur jeweils ein Treiber kann auf die Daten zugreifen.

  • Auf private Datenpuffer kann in einem beliebigen Threadkontext über den Porttreiber zugegriffen werden.

Anzeigetreiber können die GDI-Funktion EngDeviceIoControl aufrufen, um privat definierte, gerätespezifische E/A-Steuerungsanforderungen sowie systemdefinierte öffentliche E/A-Steuerungsanforderungen über den Systemvideoporttreiber an die entsprechenden adapterspezifischen Video-Miniporttreiber zu senden.

Jede Benutzermoduskomponente eines Treiberpakets kann DeviceIoControl aufrufen, um E/A-Steuerungsanforderungen an einen Treiberstapel zu senden. Der E/A-Manager erstellt eine IRP_MJ_DEVICE_CONTROL-Anforderung und übermittelt sie an den Treiber der höchsten Ebene.