在驅動程式中建立 IOCTL 要求

類別驅動程式或其他較高層級驅動程式可以配置 I/O 控制要求的 IRP,並將其傳送至下一個較低的驅動程式,如下所示:

  1. 使用主要函式程式碼IRP_MJ_DEVICE_CONTROLIRP_MJ_INTERNAL_DEVICE_CONTROL,配置或重複使用IRP (IRP) 。 您可以使用 IoBuildDeviceIoControlRequest 常式來特別配置 IOCTL IRP。 您也可以使用一般用途 IRP 建立和初始化常式,例如 IoAllocateIrpIoReuseIrpIoInitializeIrp。 如需 IRP 配置的詳細資訊,請參閱 為Lower-Level驅動程式建立 IRP

  2. 使用 IOCTL_XXX 程式碼和適當的參數,為 IRP 設定較低的驅動程式 I/O 堆疊位置。

  3. 如果要以非同步方式完成 IOCTL 要求,請呼叫 KeInitializeEvent 常式,將事件物件初始化為通知事件。 驅動程式會使用此事件來等候 I/O 作業完成。

  4. 使用 IRP 呼叫 IoSetCompletionRoutine ,讓上層驅動程式可以視需要提供 IoCompletion 常式來執行下列動作:

    • 判斷較低驅動程式如何處理指定的要求。

    • 在較低驅動程式完成要求的作業之後,重複使用 IRP 來傳送另一個要求或處置驅動程式建立的 IRP。 驅動程式無法重複使用 IoBuildDeviceIoControlRequest 所建立的 IRP。 如需詳細資訊,請參閱 重複使用 IRP

  5. 呼叫 IoCallDriver 以將要求傳遞至較低的驅動程式。

  6. 如果 IoCallDriver 傳回STATUS_PENDING,請呼叫 KeWaitForSingleObject 常式,讓目前的執行緒進入等候狀態。 驅動程式會將常式的 Object 參數設定為呼叫 KeInitializeEvent中所初始化之事件物件的位址。

    注意 如果驅動程式呼叫 KeWaitForSingleObject ,並將其 Timeout 參數設定為 Null 或設定為包含非零值的變數位址,則驅動程式必須在非位執行緒內容中于 IRQL < = APC_LEVEL執行。 否則,驅動程式必須在 IRQL < = DISPATCH_LEVEL上執行。

當 IOCTL 要求完成時,事件會由其 IoCompletion 常式發出訊號。 事件發出訊號之後,執行緒就會繼續執行。

重要 如果驅動程式將事件物件配置為堆疊上的區域變數,驅動程式必須呼叫 KeWaitForSingleObject ,並將其 WaitMode 參數設定為 KernelMode。 此參數值可防止堆疊分頁。

為了避免同步處理問題和可能的存取違規,I/O 控制程式碼的參數很少包含內嵌指標。 除了特定 SCSI 要求之外,Irp-AssociatedIrp> 上的緩衝區。SystemBufferIrp-MdlAddress > 和 Parameters。DeviceIoControl。驅動程式 I/O 堆疊位置中的Type3InputBuffer不包含其他資料緩衝區的指標,也不會包含包含系統定義 I/O 控制項代碼指標的結構。 如需如何搭配包含 I/O 控制程式碼之 IRP 使用資料緩衝區的詳細資訊,請參閱 I/O 控制代碼的緩衝區描述

不過,定義內部 I/O 控制程式碼的一對類別/埠驅動程式可以將內嵌指標傳遞至從較高層級驅動程式到較低層級驅動程式的驅動程式配置記憶體。 這類一對類別/埠驅動程式負責確保下列情況成立:

  • 一次只能有一個驅動程式存取資料。

  • 私人資料緩衝區可在埠驅動程式的任意執行緒內容中存取。

顯示驅動程式可以呼叫 GDI 函式 EngDeviceIoControl ,以透過系統視訊埠驅動程式向下傳送私人定義的裝置特定 I/O 控制要求,以及系統定義的公用 I/O 控制要求,向下傳送至對應的介面卡特定 視訊迷你埠驅動程式

驅動程式套件的任何使用者模式元件都可以呼叫 DeviceIoControl ,將 I/O 控制要求傳送至驅動程式堆疊。 I/O 管理員會建立 IRP_MJ_DEVICE_CONTROL 要求,並將它傳遞給最高層級的驅動程式。