IoBuildAsynchronousFsdRequest 函式 (wdm.h)

IoBuildAsynchronousFsdRequest 例程會配置並設定要傳送至較低層級驅動程式的 IRP。

語法

__drv_aliasesMem PIRP IoBuildAsynchronousFsdRequest(
  [in]           ULONG            MajorFunction,
  [in]           PDEVICE_OBJECT   DeviceObject,
  [in, out]      PVOID            Buffer,
  [in, optional] ULONG            Length,
  [in, optional] PLARGE_INTEGER   StartingOffset,
  [in, optional] PIO_STATUS_BLOCK IoStatusBlock
);

參數

[in] MajorFunction

要設定在 IRP 中的主要函式程式碼。 此程式代碼可以是 IRP_MJ_PNPIRP_MJ_READIRP_MJ_WRITEIRP_MJ_FLUSH_BUFFERSIRP_MJ_SHUTDOWN

[in] DeviceObject

下一個較低驅動程式裝置物件的指標。 這個物件代表讀取、寫入、排清或關機作業的目標裝置。

[in, out] Buffer

讀取數據或從中寫入數據之緩衝區的指標。 這個自變數的值是清除和關機要求的 NULL

[in, optional] Length

Buffer 所指向之緩衝區的長度,以位元組為單位。 對於磁碟之類的裝置,此值必須是扇區大小的整數倍數。 從 Windows 8 開始,扇區大小可以是 4,096 或 512 個字節。 在舊版 Windows 中,扇區大小一律為 512 個字節。 讀取和寫入要求需要此參數,但排清和關機要求必須是零。

[in, optional] StartingOffset

輸入/輸出媒體上起始位移的指標。 排清和關機要求的這個自變數值為零。

[in, optional] IoStatusBlock

I/O 狀態區塊位址的指標,其中要呼叫的驅動程式會傳回所要求作業的最終狀態。

傳回值

IoBuildAsynchronousFsdRequest 會傳回 IRP 的指標,如果無法配置 IRP,則傳回 NULL 指標。

備註

中繼或最高層級驅動程式可以呼叫 IoBuildAsynchronousFsdRequest 來設定傳送至較低層級驅動程式的要求 IRP。 呼叫驅動程序必須提供 IRP 的 IoCompletion 例程,才能使用 IoFreeIrp 解除分配 IRP。 如需 IRP 解除分配的詳細資訊,請參閱範例。

所建置的 IRP 只包含足夠的資訊,可啟動作業並完成 IRP。 因為異步要求與內容無關,所以不會追蹤其他內容資訊。

較低層級的驅動程式可能會對提供給此例程的參數施加限制。 例如,磁碟驅動器可能需要為 LengthStartingOffset 提供的值是裝置扇區大小的整數倍數。

中繼或最高層級驅動程式也可以呼叫 IoBuildDeviceIoControlRequestIoAllocateIrpIoBuildSynchronousFsdRequest 來設定傳送至較低層級驅動程式的要求。 只有最高層級的驅動程式可以呼叫 IoMakeAssociatedIrp

IoBuildAsynchronousFsdRequest 呼叫期間,I/O 管理員會將 IRP 結構的 Tail.Overlay.Thread 成員設定為指向呼叫端的線程物件,但不會代表呼叫端接受線程物件的計數參考。 呼叫端將 IRP 傳送至目標裝置的驅動程序之後,此驅動程式可能會使用 Tail.Overlay.Thread 成員來存取線程物件。 例如,記憶體驅動程式可能會呼叫 IoSetHardErrorOrVerifyDevice 例程,並提供IRP的指標作為輸入參數。 在此呼叫期間, IoSetHardErrorOrVerifyDevice 會使用 Tail.Overlay.Thread 成員來存取線程物件。 以這種方式存取線程物件時,呼叫 IoBuildAsynchronousFsdRequest 的驅動程式會負責配置 IRP,以確保在處理 IRP 時線程物件保持有效。

若要讓線程物件保持有效,呼叫 IoBuildAsynchronousFsdRequest 的驅動程式可以在傳送 IRP 之前,先在線程物件上取得計數參考。 例如,此驅動程式可以呼叫 ObReferenceObjectByPointerWithTag 例程,並以 Object 參數的形式提供 IRP 結構的 Tail.Overlay.Thread 成員中的對象指標。 稍後,此驅動程式的完成例程可以藉由呼叫 ObDereferenceObjectWithTag 之類的例程來取值物件。

驅動程式可能會在一個線程中呼叫 IoBuildAsynchronousFsdRequest ,並在另一個線程中傳送此呼叫所配置的 IRP。 傳送 IRP 之前,此驅動程式應該設定 IRP 的 Tail.Overlay.Thread 成員,以指向傳送線程的線程物件。 一般而言,驅動程式會呼叫 PsGetCurrentThread 例程來取得線程對象指標。

呼叫 IoBuildAsynchronousFsdRequest 來配置 IRP 的驅動程式不一定需要在 IRP 的 Tail.Overlay.Thread 成員所指向的線程物件上取得計數參考。 驅動程式可能會改用另一種技術來保證此線程對象在處理 IRP 時仍有效。 例如,如果驅動程式建立了線程,線程可以等到 IRP 完成以終止本身為止。

範例

呼叫 IoFreeIrp 之前,如果需要額外的步驟,才能釋出 IoBuildAsynchronousFsdRequest 所建置之 IRP 的緩衝區,如果下列全都成立:

  • 緩衝區已從系統記憶體集區配置。

  • 在目標裝置的裝置物件中,DO_DIRECT_IO旗標是在 DeviceObject-Flags> 字段中設定。

  • Irp-MdlAddress> 字段為非 NULL。

在釋放這個 IRP 的緩衝區之前,請先使用 Irp-MdlAddress> 呼叫 MmUnlockPages 例程做為參數值。 此呼叫會遞減 IoBuildAsynchronousFsdRequest 新增至 MDL 中集區頁面的額外參考計數。 否則, 後續對 IoFreeMdl 的呼叫將會進行錯誤檢查,因為這些集區頁面的參考計數會是 2,而不是 1。 下列程式代碼範例顯示此案例的 MmUnlockPagesIoFreeMdlIoFreeIrp 呼叫:

if (((DeviceObject->Flags & DO_DIRECT_IO) == DO_DIRECT_IO) &&
    (Irp->MdlAddress != NULL))
{
    MmUnlockPages(Irp->MdlAddress);
}

IoFreeMdl(Irp->MdlAddress);
IoFreeIrp(Irp);

規格需求

需求
目標平台 Universal
標頭 wdm.h (包括 Wdm.h、Ntddk.h、Ntifs.h)
程式庫 NtosKrnl.lib
Dll NtosKrnl.exe
IRQL IRQL <= APC_LEVEL
DDI 合規性規則 ForwardedAtBadIrqlFsdAsync (wdm) HwStorPortProhibitedDIs (storport ) 、 IoBuildFsdComplete (wdm ) 、 IoBuildFsdForward (wdm) IoBuildFsdFree (wdm)

另請參閱

IO_STACK_LOCATION

IRP

IoAllocateIrp

IoBuildDeviceIoControlRequest

IoBuildSynchronousFsdRequest

IoCallDriver

IoFreeIrp

IoFreeMdl

IoMakeAssociatedIrp

IoSetCompletionRoutine

IoSetHardErrorOrVerifyDevice

MmUnlockPages

ObDereferenceObjectWithTag

ObReferenceObjectByPointerWithTag

PsGetCurrentThread