定義 I/O 控制程式碼
定義新的 IOCTL 時,請務必記住下列規則:
- 如果新的 IOCTL 可供使用者模式軟體元件使用,IOCTL 必須搭配 IRP_MJ_DEVICE_CONTROL 要求使用。 使用者模式元件會呼叫 Win32 函式的DeviceIoControl來傳送IRP_MJ_DEVICE_CONTROL要求。
- 如果新的 IOCTL 僅適用于核心模式驅動程式元件,則必須搭配 IRP_MJ_INTERNAL_DEVICE_CONTROL 要求使用 IOCTL。 核心模式元件會呼叫IoBuildDeviceIoControlRequest來建立IRP_MJ_INTERNAL_DEVICE_CONTROL要求。 如需詳細資訊,請參閱 在驅動程式中建立 IOCTL 要求。
I/O 控制項程式碼是包含數個欄位的 32 位值。 下圖說明 I/O 控制項代碼的配置。
使用系統提供的 CTL_CODE 宏,此巨集定義于 Wdm.h 和 Ntddk.h 中,以定義新的 I/O 控制程式碼。 新的 IOCTL 程式碼定義,無論是用於 IRP_MJ_DEVICE_CONTROL 或 IRP_MJ_INTERNAL_DEVICE_CONTROL 要求,都會使用下列格式:
#define IOCTL_Device_Function CTL_CODE(DeviceType, Function, Method, Access)
選擇 IOCTL 的描述性常數名稱,其格式為 IOCTL_Device_Function,其中 Device 會指出裝置的類型,而 Function 則表示作業。 範例常數名稱是IOCTL_VIDEO_ENABLE_CURSOR。
將下列參數提供給 CTL_CODE 宏:
DeviceType
識別裝置類型。 這個值必須符合驅動程式DEVICE_OBJECT結構之DeviceType成員中所設定的值。 (請參閱 指定裝置類型) 。 小於0x8000的值會保留給 Microsoft。 廠商可以使用0x8000和更高值。 請注意,廠商指派的值會設定 Common 位。
FunctionCode
識別驅動程式所要執行的函式。 小於0x800的值會保留給 Microsoft。 廠商可以使用0x800和更高值。 請注意,廠商指派的值會設定 自訂 位。
TransferType
指出系統如何在 DeviceIoControl (或 IoBuildDeviceIoControlRequest) 和處理 IRP 的驅動程式之間傳遞資料。
使用下列其中一個系統定義的常數:
METHOD_BUFFERED
指定 緩衝的 I/O 方法,這個方法通常用於傳送每個要求少量的資料。 裝置和中繼驅動程式的大部分 I/O 控制程式碼都會使用此 TransferType 值。
如需系統如何指定METHOD_BUFFERED I/O 控制程式碼之資料緩衝區的資訊,請參閱 I/O 控制代碼的緩衝區描述。
如需緩衝 I/O 的詳細資訊,請參閱 使用緩衝 I/O。
METHOD_IN_DIRECT或METHOD_OUT_DIRECT
指定 直接 I/O 方法,這個方法通常用於使用 DMA 或 PIO 快速傳輸的大量資料。
如果 DeviceIoControl 或 IoBuildDeviceIoControlRequest 的呼叫端將資料傳遞至驅動程式,請指定METHOD_IN_DIRECT。
如果 DeviceIoControl 或 IoBuildDeviceIoControlRequest 的呼叫端從驅動程式接收資料,請指定METHOD_OUT_DIRECT。
如需系統如何指定METHOD_IN_DIRECT和METHOD_OUT_DIRECT I/O 控制程式碼的資料緩衝區資訊,請參閱 I/O 控制代碼的緩衝區描述。
如需直接 I/O 的詳細資訊,請參閱 使用直接 I/O。
METHOD_NEITHER
指定 未緩衝處理或直接 I/O。 I/O 管理員不提供任何系統緩衝區或 MDL。 IRP 提供指定給 DeviceIoControl 或 IoBuildDeviceIoControlRequest之輸入和輸出緩衝區的使用者模式虛擬位址,而不會驗證或對應它們。
如需系統如何指定METHOD_NEITHER I/O 控制程式碼之資料緩衝區的資訊,請參閱 I/O 控制代碼的緩衝區描述。
只有在驅動程式可以保證在產生 I/O 控制項要求的執行緒內容中執行時,才能使用這個方法。 只有最高層級的核心模式驅動程式保證符合此條件,因此METHOD_NEITHER很少用於傳遞至低階設備磁碟機的 I/O 控制程式碼。
使用此方法時,最高層級驅動程式必須判斷是否要在收到要求時設定緩衝或直接存取使用者資料,可能必須鎖定使用者緩衝區,而且必須在結構化例外狀況處理常式中包裝對使用者緩衝區的存取權, (請參閱 處理例外 狀況) 。 否則,原始的使用者模式呼叫端可能會在驅動程式可以使用之前變更緩衝資料,或者呼叫端可以交換,就像驅動程式存取使用者緩衝區一樣。
如需詳細資訊,請參閱 使用未緩衝處理或直接 I/O。
RequiredAccess
指出呼叫端在開啟代表裝置的檔案物件時必須要求的存取類型, (會看到IRP_MJ_CREATE) 。 只有在呼叫端要求指定的存取權限時,I/O 管理員才會建立 IRP,並使用特定的 I/O 控制程式碼呼叫驅動程式。
RequiredAccess 是使用下列系統定義的常數來指定:
FILE_ANY_ACCESS
I/O 管理員會將任何具有控制碼的呼叫端的 IRP 傳送給代表目標裝置物件的檔案物件。
FILE_READ_DATA
I/O 管理員只會針對具有讀取存取許可權的呼叫端傳送 IRP,讓基礎設備磁碟機將資料從裝置傳輸到系統記憶體。
FILE_WRITE_DATA
I/O 管理員只會針對具有寫入存取權限的呼叫端傳送 IRP,讓基礎設備磁碟機將資料從系統記憶體傳輸到其裝置。
如果呼叫端必須同時具有讀取和寫入存取權限,FILE_READ_DATA和FILE_WRITE_DATA可以一起存取。
某些系統定義的 I/O 控制程式碼具有 RequiredAccess 值FILE_ANY_ACCESS,可讓呼叫端傳送特定 IOCTL,而不論授與裝置的存取權為何。 範例包括傳送至 專屬裝置驅動程式的 I/O 控制程式碼。
其他系統定義的 I/O 控制程式碼需要呼叫端具有讀取存取許可權、寫入存取權限或兩者。 例如,公用 I/O 控制項程式碼的下列定義IOCTL_DISK_SET_PARTITION_INFO顯示只有在呼叫端同時具有讀取和寫入存取權限時,才能將此 I/O 要求傳送至驅動程式:
#define IOCTL_DISK_SET_PARTITION_INFO\
CTL_CODE(IOCTL_DISK_BASE, 0x008, METHOD_BUFFERED,\
FILE_READ_DATA | FILE_WRITE_DATA)
注意
在為新的 IOCTL 程式碼指定FILE_ANY_ACCESS之前,您必須絕對確定允許不受限制存取裝置並不會建立惡意使用者入侵系統的可能性路徑。
驅動程式可以使用 IoValidateDeviceIoControlAccess 來執行比 IOCTL RequiredAccess 位所提供的更嚴格的存取檢查。
其他有用的宏
下列宏適用于從 IOCTL 程式碼擷取 16 位 DeviceType 和 2 位 TransferType 欄位:
#define DEVICE_TYPE_FROM_CTL_CODE(ctrlCode) (((ULONG)(ctrlCode & 0xffff0000)) >> 16)
#define METHOD_FROM_CTL_CODE(ctrlCode) ((ULONG)(ctrlCode & 3))
這些巨集定義于 Wdm.h 和 Ntddk.h 中。