Definieren von E/A-Steuerungscodes

Beim Definieren neuer IOCTLs ist es wichtig, sich die folgenden Regeln zu merken:

  • Wenn eine neue IOCTL für Softwarekomponenten im Benutzermodus verfügbar ist, muss die IOCTL mit IRP_MJ_DEVICE_CONTROL Anforderungen verwendet werden. Benutzermoduskomponenten senden IRP_MJ_DEVICE_CONTROL Anforderungen, indem sie deviceIoControl aufrufen, bei der es sich um eine Win32-Funktion handelt.
  • Wenn eine neue IOCTL nur für Kernelmodustreiberkomponenten verfügbar ist, muss die IOCTL mit IRP_MJ_INTERNAL_DEVICE_CONTROL Anforderungen verwendet werden. Kernelmoduskomponenten erstellen IRP_MJ_INTERNAL_DEVICE_CONTROL Anforderungen, indem Sie IoBuildDeviceIoControlRequest aufrufen. Weitere Informationen finden Sie unter Erstellen von IOCTL-Anforderungen in Treibern.

Ein E/A-Steuerelementcode ist ein 32-Bit-Wert, der aus mehreren Feldern besteht. Die folgende Abbildung veranschaulicht das Layout von E/A-Steuerelementcodes.

Diagramm zur Veranschaulichung des E/A-Steuerelementcodelayouts.

Verwenden Sie das vom System bereitgestellte CTL_CODE Makro, das in Wdm.h und Ntddk.h definiert ist, um neue E/A-Steuerungscodes zu definieren. Die Definition eines neuen IOCTL-Codes, der für die Verwendung mit IRP_MJ_DEVICE_CONTROL - oder IRP_MJ_INTERNAL_DEVICE_CONTROL-Anforderungen vorgesehen ist, verwendet das folgende Format:

#define IOCTL_Device_Function CTL_CODE(DeviceType, Function, Method, Access)

Wählen Sie einen beschreibenden Konstantennamen für die IOCTL im Format IOCTL_Device_Function aus, wobei Device den Gerätetyp und Function den Vorgang angibt. Ein Beispiel für einen konstanten Namen ist IOCTL_VIDEO_ENABLE_CURSOR.

Geben Sie die folgenden Parameter für das makro CTL_CODE an:

DeviceType
Gibt den Gerätetyp an. Dieser Wert muss mit dem Wert übereinstimmen, der im DeviceType-Member der DEVICE_OBJECT Struktur des Treibers festgelegt ist. (Siehe Angeben von Gerätetypen). Werte von kleiner als 0x8000 sind für Microsoft reserviert. Die Werte von 0x8000 und höher können von Anbietern verwendet werden. Beachten Sie, dass die vom Anbieter zugewiesenen Werte das Allgemeine Bit festlegen.

FunctionCode
Gibt die vom Treiber auszuführende Funktion an. Werte von kleiner als 0x800 sind für Microsoft reserviert. Die Werte von 0x800 und höher können von Anbietern verwendet werden. Beachten Sie, dass die vom Anbieter zugewiesenen Werte das benutzerdefinierte Bit festlegen.

TransferType
Gibt an, wie das System Daten zwischen dem Aufrufer von DeviceIoControl (oder IoBuildDeviceIoControlRequest) und dem Treiber übergibt, der die IRP verarbeitet.

Verwenden Sie eine der folgenden systemdefinierten Konstanten:

METHOD_BUFFERED
Gibt die gepufferte E/A-Methode an, die in der Regel für die Übertragung kleiner Datenmengen pro Anforderung verwendet wird. Die meisten E/A-Steuerungscodes für Geräte- und Zwischentreiber verwenden diesen TransferType-Wert .

Informationen dazu, wie das System Datenpuffer für METHOD_BUFFERED E/A-Steuercodes angibt, finden Sie unter Pufferbeschreibungen für E/A-Steuerungscodes.

Weitere Informationen zu gepufferten E/A-Vorgängen finden Sie unter Verwenden von gepufferten E/A-Vorgängen.

METHOD_IN_DIRECT oder METHOD_OUT_DIRECT
Gibt die direkte E/A-Methode an, die in der Regel zum Lesen oder Schreiben großer Datenmengen mithilfe von DMA oder PIO verwendet wird, die schnell übertragen werden müssen.

Geben Sie METHOD_IN_DIRECT an, ob der Aufrufer von DeviceIoControl oder IoBuildDeviceIoControlRequest Daten an den Treiber übergibt.

Geben Sie METHOD_OUT_DIRECT an, ob der Aufrufer von DeviceIoControl oder IoBuildDeviceIoControlRequest Daten vom Treiber empfängt.

Informationen dazu, wie das System Datenpuffer für METHOD_IN_DIRECT und METHOD_OUT_DIRECT E/A-Steuerungscodes angibt, finden Sie unter Pufferbeschreibungen für E/A-Steuercodes.

Weitere Informationen zu direkten E/A-Vorgängen finden Sie unter Verwenden von direkten E/A-Vorgängen.

METHOD_NEITHER
Gibt weder gepufferte noch direkte E/A-Vorgänge an. Der E/A-Manager stellt keine Systempuffer oder MDLs bereit. Das IRP stellt die virtuellen Benutzermodusadressen der Eingabe- und Ausgabepuffer bereit, die für DeviceIoControl oder IoBuildDeviceIoControlRequest angegeben wurden, ohne sie zu überprüfen oder zuzuordnen.

Informationen dazu, wie das System Datenpuffer für METHOD_NEITHER E/A-Steuerungscodes angibt, finden Sie unter Pufferbeschreibungen für E/A-Steuerungscodes.

Diese Methode kann nur verwendet werden, wenn sichergestellt werden kann, dass der Treiber im Kontext des Threads ausgeführt wird, der aus der E/A-Steuerelementanforderung stammt. Nur ein Kernelmodustreiber der obersten Ebene erfüllt diese Bedingung, sodass METHOD_NEITHER selten für die E/A-Steuercodes verwendet wird, die an Gerätetreiber auf niedriger Ebene übergeben werden.

Bei dieser Methode muss der Treiber der obersten Ebene bestimmen, ob der gepufferte oder direkte Zugriff auf Benutzerdaten nach Eingang der Anforderung eingerichtet werden soll, möglicherweise den Benutzerpuffer sperren und seinen Zugriff auf den Benutzerpuffer in einem strukturierten Ausnahmehandler umschließen muss (siehe Behandeln von Ausnahmen). Andernfalls kann der ursprüngliche Benutzermodusaufrufer die gepufferten Daten ändern, bevor der Treiber sie verwenden kann, oder der Aufrufer kann ausgetauscht werden, während der Treiber auf den Benutzerpuffer zugreift.

Weitere Informationen finden Sie unter Verwenden von weder gepufferten noch direkten E/A-Vorgängen.

RequiredAccess
Gibt den Typ des Zugriffs an, den ein Aufrufer beim Öffnen des Dateiobjekts anfordern muss, das das Gerät darstellt (siehe IRP_MJ_CREATE). Der E/A-Manager erstellt IRPs und ruft den Treiber mit einem bestimmten E/A-Steuerungscode nur auf, wenn der Aufrufer die angegebenen Zugriffsrechte angefordert hat. RequiredAccess wird mithilfe der folgenden systemdefinierten Konstanten angegeben:

FILE_ANY_ACCESS
Der E/A-Manager sendet den IRP für jeden Aufrufer, der über ein Handle verfügt, an das Dateiobjekt, das das Zielgerätobjekt darstellt.

FILE_READ_DATA
Der E/A-Manager sendet die IRP nur an einen Aufrufer mit Lesezugriffsrechten, sodass der zugrunde liegende Gerätetreiber Daten vom Gerät in den Systemspeicher übertragen kann.

FILE_WRITE_DATA
Der E/A-Manager sendet die IRP nur für einen Aufrufer mit Schreibzugriffsrechten, sodass der zugrunde liegende Gerätetreiber Daten aus dem Systemspeicher auf sein Gerät übertragen kann.

FILE_READ_DATA und FILE_WRITE_DATA können gemeinsam aufgehoben werden, wenn der Aufrufer über Lese- und Schreibzugriffsrechte verfügen muss.

Einige systemdefinierte E/A-Kontrollcodes weisen den RequiredAccess-Wert FILE_ANY_ACCESS auf, der es dem Aufrufer ermöglicht, die jeweilige IOCTL unabhängig vom Zugriff auf das Gerät zu senden. Beispiele hierfür sind E/A-Steuercodes, die an Treiber exklusiver Geräte gesendet werden.

Andere systemdefinierte E/A-Steuerungscodes erfordern, dass der Aufrufer über Lesezugriffsrechte, Schreibzugriffsrechte oder beides verfügt. Die folgende Definition des öffentlichen E/A-Steuerungscodes IOCTL_DISK_SET_PARTITION_INFO zeigt beispielsweise, dass diese E/A-Anforderung nur dann an einen Treiber gesendet werden kann, wenn der Aufrufer über Lese- und Schreibzugriffsrechte verfügt:

#define IOCTL_DISK_SET_PARTITION_INFO\
        CTL_CODE(IOCTL_DISK_BASE, 0x008, METHOD_BUFFERED,\
        FILE_READ_DATA | FILE_WRITE_DATA)

Hinweis

Bevor Sie FILE_ANY_ACCESS für einen neuen IOCTL-Code angeben, müssen Sie absolut sicher sein, dass das Zulassen des uneingeschränkten Zugriffs auf Ihr Gerät keinen möglichen Pfad für böswillige Benutzer schafft, um das System zu kompromittieren.

Treiber können IoValidateDeviceIoControlAccess verwenden, um eine strengere Zugriffsüberprüfung durchzuführen, als dies von den RequiredAccess-Bits einer IOCTL bereitgestellt wird.

Weitere nützliche Makros

Die folgenden Makros sind nützlich, um die 16-Bit-Felder DeviceType und 2-Bit TransferType aus einem IOCTL-Code zu extrahieren:

#define DEVICE_TYPE_FROM_CTL_CODE(ctrlCode)   (((ULONG)(ctrlCode & 0xffff0000)) >> 16)
#define METHOD_FROM_CTL_CODE(ctrlCode)        ((ULONG)(ctrlCode & 3))

Diese Makros sind in Wdm.h und Ntddk.h definiert.