Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
In diesem Artikel wird beschrieben, wie Sie einen eindeutigen I/O-Steuerelementcode (IOCTL) erstellen. IOCTLs können sein:
- Öffentliche IOCTLs, die in der Regel von Microsoft systemdefiniert und dokumentiert sind.
- Private IOCTLs, die in der Regel ausschließlich von den Softwarekomponenten eines Anbieters verwendet werden sollen, um miteinander zu kommunizieren. Sie sind in der Regel in der Kopfzeilendatei eines Anbieters definiert und werden von Microsoft nicht dokumentiert.
IOCTL-Layout
Ein IOCTL ist ein 32-Bit-Wert, der aus mehreren Feldern besteht. Die folgende Abbildung zeigt das bitweise Layout eines IOCTL:

Jedes Feld im IOCTL hat einen bestimmten Zweck, wie in der folgenden Tabelle beschrieben:
| Feld | Bits in IOCTL | BESCHREIBUNG |
|---|---|---|
| allgemein | 31 | Anbieter müssen dieses Bit festlegen, wenn sie einen vom Anbieter zugewiesenen Wert für DeviceType verwenden. |
| DeviceType | 16-30 | Gibt den Gerätetyp an. Dieser Wert muss mit dem wert übereinstimmen, der im DeviceType-Element der DEVICE_OBJECT Struktur des Treibers festgelegt ist. Anbieter sollten einen Wert von 32768 bis 65535 (0x8000 bis 0xffff) verwenden und das allgemeine Bit festlegen. Die Werte 0 bis 32767 (0x0000 bis 0x7fff) sind für Microsoft reserviert. Weitere Informationen finden Sie unter Angeben von Gerätetypen. |
| Zugriff | 14-15 | 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 I/O-Manager erstellt IRPs und ruft den Treiber nur dann mit einem bestimmten IOCTL auf, wenn der Anrufer die angegebenen Zugriffsrechte angefordert hat. Dieses Feld wird mithilfe der folgenden systemdefinierten Konstanten angegeben: FILE_ANY_ACCESS, FILE_READ_DATA und FILE_WRITE_DATA. |
| Benutzerdefiniert | 13 | Wenn festgelegt, gibt an, dass es sich um ein vom Anbieter definiertes IOCTL handelt. |
| Funktion | 2-12 | Eindeutiger Code für den Treiber, der die auszuführende Funktion identifiziert. Verwenden Sie für einen vom Hersteller erstellten IOCTL den Wert 2048 bis 4095 (0x800 bis 0xfff), und legen Sie das benutzerdefinierte Bit fest. Werte unter 2048 (0x000 bis 0x7ff) sind für Microsoft reserviert. |
| Methode | 0-1 | Gibt an, wie das System Daten zwischen dem Aufrufer von DeviceIoControl (oder IoBuildDeviceIoControlRequest) und dem Treiber übergibt, der das IRP verarbeitet. Weitere Informationen finden Sie unter "Anleitungen zum Festlegen der Methodenbits". |
Makro zur Definition von E/A-Steuercodes
Verwenden Sie das vom System bereitgestellte CTL_CODE Makro, um neue E/A-Steuerungscodes zu definieren. Dieses Makro wird wie folgt in "devioctl.h " definiert:
#define CTL_CODE( DeviceType, Function, Method, Access ) ( \
((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \
)
Eine Beschreibung von DeviceType, Function, Method und Access finden Sie im vorherigen Abschnitt.
Beachten Sie beim Definieren neuer E/A-Steuerungscodes die folgenden Regeln:
Wenn ein neues IOCTL für Softwarekomponenten im Benutzermodus verfügbar ist, muss es mit IRP_MJ_DEVICE_CONTROL Anforderungen verwendet werden. Benutzermoduskomponenten rufen DeviceIoControl auf, um IRP_MJ_DEVICE_CONTROL Anforderungen zu senden.
Wenn eine neue IOCTL nur für Kernelmodustreiberkomponenten verfügbar ist, muss sie mit IRP_MJ_INTERNAL_DEVICE_CONTROL Anforderungen verwendet werden. Kernelmoduskomponenten können IRP_MJ_INTERNAL_DEVICE_CONTROL Anforderungen erstellen, indem IoBuildDeviceIoControlRequest aufgerufen wird. Weitere Informationen finden Sie unter Erstellen von IOCTL-Anforderungen in Treibern.
Die Definition eines neuen IOCTL-Codes verwendet das folgende Format, unabhängig davon, ob er für die Verwendung mit IRP_MJ_DEVICE_CONTROL oder IRP_MJ_INTERNAL_DEVICE_CONTROL-Anforderungen vorgesehen ist.
#define IOCTL_Device_Function CTL_CODE(DeviceType, Function, Method, Access)
Wählen Sie einen beschreibenden Konstantennamen für die IOCTL des Formulars IOCTL_Device_Function aus, wobei Device den Typ des Geräts und die Funktion angibt. Die vom System bereitgestellte IOCTL_VIDEO_ENABLE_CURSOR Konstante verwendet z. B. "VIDEO" für "Device " und "ENABLE_CURSOR" für "Function".
Anleitung zum Festlegen der Access-Bits
Beim Definieren einer neuen IOCTL müssen Sie einen Wert für das Access-Bitfeld auswählen, der den Typ des Zugriffs angibt, den ein Aufrufer anfordern muss, wenn das Dateiobjekt geöffnet wird, das das Gerät darstellt. Der I/O-Manager erstellt IRPs und ruft den Treiber nur dann mit einem bestimmten IOCTL auf, wenn der Anrufer die angegebenen Zugriffsrechte angefordert hat.
Access wird mithilfe der folgenden vom System definierten Konstanten angegeben:
FILE_ANY_ACCESS
Der E/A-Manager sendet die IRP für jeden Aufrufer, der ein Handle auf das Dateiobjekt besitzt, das das Ziel-Geräteobjekt darstellt. Bevor Sie FILE_ANY_ACCESS für einen neuen IOCTL-Code angeben, müssen Sie absolut sicher sein, dass der uneingeschränkte Zugriff auf Ihr Gerät keinen möglichen Pfad für böswillige Benutzer zum Kompromittieren des Systems erstellt.
FILE_READ_DATA
Der E/A-Manager sendet das IRP nur für einen Anrufer mit Lesezugriffsrechten, sodass der zugrunde liegende Gerätetreiber Daten vom Gerät in den Systemspeicher übertragen kann.
Datei_Schreib_Daten
Der E/A-Manager sendet das IRP nur für einen Anrufer 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 kombiniert werden, wenn der Aufrufer über Lese- und Schreibzugriffsrechte verfügen muss.
Einige systemdefinierte E/A-Steuerungscodes weisen einen Access-Wert von FILE_ANY_ACCESS auf, der es dem Aufrufer ermöglicht, den jeweiligen IOCTL unabhängig vom zugriff auf das Gerät zu senden. Beispiele sind E/A-Steuercodes, die an Treiber exklusiver Geräte gesendet werden.
Andere vom System definierte E/A-Steuerungscodes erfordern, dass der Aufrufer Leseberechtigungen, Schreibzugriffsrechte oder beides hat. Die folgende Definition der öffentlichen IOCTL_DISK_SET_PARTITION_INFO IOCTL zeigt beispielsweise, dass diese E/A-Anforderung nur an einen Treiber gesendet werden kann, wenn der Anrufer sowohl Lese- als auch Schreibzugriffsrechte hat:
#define IOCTL_DISK_SET_PARTITION_INFO\
CTL_CODE(IOCTL_DISK_BASE, 0x008, METHOD_BUFFERED,\
FILE_READ_DATA | FILE_WRITE_DATA)
Treiber können IoValidateDeviceIoControlAccess verwenden, um eine strengere Zugriffsüberprüfung durchzuführen als die durch die Access-Bits eines IOCTL bereitgestellte.
Anleitung zum Festlegen der Methodenbits
Beim Definieren eines neuen IOCTL müssen Sie einen Wert für das Bitfeld "Methode " auswählen, der angibt, wie das System Daten zwischen dem Aufrufer von DeviceIoControl (oder IoBuildDeviceIoControlRequest) und dem Treiber übergeben soll, der das IRP verarbeitet.
Verwenden Sie eine der folgenden vom System definierten Konstanten, um das Methodenfeld festzulegen.
METHOD_BUFFERED
Gibt die gepufferte E/A-Methode an, die in der Regel zum Übertragen kleiner Datenmengen pro Anforderung verwendet wird. Die meisten E/A-Steuercodes für Geräte- und Zwischentreiber verwenden diesen Wert.
Informationen dazu, wie das System Datenpuffer für METHOD_BUFFERED E/A-Steuerungscodes 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 normalerweise zum Lesen oder Schreiben großer Datenmengen mit DMA oder PIO verwendet wird, die schnell übertragen werden müssen.
Geben Sie METHOD_IN_DIRECT an, wenn der Aufrufer von DeviceIoControl oder IoBuildDeviceIoControlRequest Daten an den Treiber übergibt.
Geben Sie METHOD_OUT_DIRECT an, wenn der Aufrufer von DeviceIoControl oder IoBuildDeviceIoControlRequest Daten vom Treiber empfängt.
Informationen darüber, 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-Steuerungscodes.
Weitere Informationen zur direkten E/A finden Sie unter Verwenden von direct I/O.
METHODE_KEINES
Gibt an, dass die E/A-Methode nicht gepuffert oder direkt ist. Der E/A-Manager stellt keine Systempuffer oder MDLs bereit. Das IRP stellt die virtuellen Adressen des Benutzermodus 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-Steuercodes angibt, finden Sie unter Pufferbeschreibungen für E/A-Steuerungscodes.
Diese Methode kann nur verwendet werden, wenn garantiert ist, dass der Treiber im Kontext des Threads ausgeführt wird, der die E/A-Steuerelementanforderung ausgelöst hat. Es wird garantiert, dass nur ein Kernelmodustreiber auf höchster Ebene diese Bedingung erfüllt, sodass METHOD_NEITHER selten für IOCTLs verwendet wird, die an Gerätetreiber auf niedriger Ebene übergeben werden.
Bei dieser Methode muss der Treiber der höchsten Ebene:
- Muss bestimmen, ob gepufferter oder direkter Zugriff auf Benutzerdaten beim Empfang der Anforderung eingerichtet werden soll.
- Möglicherweise muss er den Benutzer-Puffer sperren.
- Muss den Zugriff auf den Benutzerpuffer in einem strukturierten Ausnahmehandler umschließen (siehe Behandeln von Ausnahmen).
Andernfalls kann der ursprüngliche Benutzermodus-Aufrufer die gepufferten Daten ändern, bevor der Treiber sie verwenden kann, oder der Aufrufer könnte so abgetauscht werden, wie der Treiber auf den Benutzerpuffer zugreift.
Weitere Informationen finden Sie unter Weder gepufferte noch direkte E/A verwenden.
Andere nützliche Makros
Die folgenden Makros eignen sich zum Extrahieren der 16-Bit-DeviceType- und 2-Bit-Method-Felder aus einem IOCTL.
#define DEVICE_TYPE_FROM_CTL_CODE(ctrlCode) (((ULONG)(ctrlCode & 0xffff0000)) >> 16)
#define METHOD_FROM_CTL_CODE(ctrlCode) ((ULONG)(ctrlCode & 3))
Diese Makros werden in Wdm.h und Ntddk.h definiert.