WdfIoTargetFormatRequestForIoctl 函数 (wdfiotarget.h)

[适用于 KMDF 和 UMDF]

WdfIoTargetFormatRequestForIoctl 方法为 I/O 目标生成设备控制请求,但不发送请求。

语法

NTSTATUS WdfIoTargetFormatRequestForIoctl(
  [in]           WDFIOTARGET       IoTarget,
  [in]           WDFREQUEST        Request,
  [in]           ULONG             IoctlCode,
  [in, optional] WDFMEMORY         InputBuffer,
  [in, optional] PWDFMEMORY_OFFSET InputBufferOffset,
  [in, optional] WDFMEMORY         OutputBuffer,
  [in, optional] PWDFMEMORY_OFFSET OutputBufferOffset
);

参数

[in] IoTarget

本地或远程 I/O 目标对象的句柄,该对象是从先前调用 WdfDeviceGetIoTargetWdfIoTargetCreate 或从专用 I/O 目标提供的方法获取的。

[in] Request

框架请求对象的句柄。 有关更多信息,请参见下面的“备注”部分。

[in] IoctlCode

I/O 控制代码 (IOCTL) I/O 目标支持。

[in, optional] InputBuffer

框架内存对象的句柄。 此对象表示包含将发送到 I/O 目标的数据的缓冲区。 有关更多信息,请参见下面的“备注”部分。

[in, optional] InputBufferOffset

指向调用方分配 的WDFMEMORY_OFFSET 结构的指针,该结构提供可选的字节偏移量和长度值。 框架使用这些值来确定输入缓冲区内数据传输的起始地址和长度。 如果此指针为 NULL,则数据传输从输入缓冲区的开头开始,传输大小为缓冲区大小。

[in, optional] OutputBuffer

框架内存对象的句柄。 此对象表示将从 I/O 目标接收数据的缓冲区。 有关更多信息,请参见下面的“备注”部分。

[in, optional] OutputBufferOffset

指向调用方分配 的WDFMEMORY_OFFSET 结构的指针,该结构提供可选的字节偏移量和长度值。 框架使用这些值来确定输出缓冲区内数据传输的起始地址和长度。 如果此指针为 NULL,则数据传输从输出缓冲区的开头开始,传输大小为缓冲区大小。

返回值

如果操作成功,WdfIoTargetFormatRequestForIoctl 将返回STATUS_SUCCESS。 否则,此方法可能会返回以下值之一:

返回代码 说明
STATUS_INVALID_PARAMETER
检测到无效的参数。
STATUS_INVALID_DEVICE_REQUEST
传输长度大于缓冲区长度,或者 I/O 请求已排队到 I/O 目标。
STATUS_INSUFFICIENT_RESOURCES
框架无法 (内存) 分配系统资源。
STATUS_REQUEST_NOT_ACCEPTED
请求参数表示的 I/O 请求数据包 (IRP) 不提供足够的IO_STACK_LOCATION结构来允许驱动程序转发请求。
 

此方法还可能返回其他 NTSTATUS 值

如果驱动程序提供无效的对象句柄,则会发生 bug 检查。

注解

使用 WdfIoTargetFormatRequestForIoctl 方法(后跟 WdfRequestSend 方法)以同步或异步方式发送设备控制请求。 或者,使用 WdfIoTargetSendIoctlSynchronously 方法以同步方式发送设备控制请求。

有关设备控制请求的详细信息,请参阅 使用 I/O 控制代码

可以转发驱动程序在 I/O 队列中收到的设备控制请求,也可以创建并发送新请求。 在任一情况下,框架都需要请求对象和一些缓冲区空间。

若要转发驱动程序在 I/O 队列中收到的设备控制请求,请执行以下操作:

  1. WdfIoTargetFormatRequestForIoctl 方法的 Request 参数指定接收的请求句柄。
  2. 将收到的请求的输入缓冲区用于 WdfIoTargetFormatRequestForIoctl 方法的 InputBuffer 参数。

    驱动程序必须调用 WdfRequestRetrieveInputMemory 以获取表示请求输入缓冲区的框架内存对象的句柄,并且它必须使用该句柄作为 InputBuffer 的值。

  3. 将收到的请求的输出缓冲区用于 WdfIoTargetFormatRequestForIoctl 方法的 OutputBuffer 参数。

    驱动程序必须调用 WdfRequestRetrieveOutputMemory 以获取请求输出缓冲区的句柄,并且它必须使用该句柄作为 OutputBuffer 的值。

有关转发 I/O 请求的详细信息,请参阅 转发 I/O 请求

驱动程序通常将收到的 I/O 请求划分为发送到 I/O 目标的较小请求,因此驱动程序可能会创建新请求。

创建新的 I/O 请求:

  1. 创建新的请求对象,并为 WdfIoTargetFormatRequestForIoctl 方法的 Request 参数提供其句柄。

    调用 WdfRequestCreate 以预分配一个或多个请求对象。 可以通过调用 WdfRequestReuse 重用这些请求对象。 驱动程序的 EvtDriverDeviceAdd 回调函数可以预分配设备的请求对象。

  2. 提供缓冲区空间,并为 WdfIoTargetFormatRequestForIoctl 方法的 InputBufferOutputBuffer 参数提供缓冲区的句柄。

    驱动程序必须将此缓冲区空间指定为框架托管内存的 WDFMEMORY 句柄。 驱动程序可以执行以下任一操作:

    请注意,如果驱动程序调用 WdfRequestRetrieveInputMemoryWdfRequestRetrieveOutputMemory 并将内存句柄传递给 WdfIoTargetFormatRequestForIoctl,则在驱动程序删除、重用或重新设置驱动程序创建的新请求对象之前,驱动程序不得完成收到的 I/O 请求。 (WdfIoTargetFormatRequestForIoctl 递增内存对象的引用计数。删除、重用或重新格式化请求对象会递减内存对象的引用 count.)
驱动程序调用 WdfIoTargetFormatRequestForIoctl 以格式化设备控制请求后,驱动程序必须调用 WdfRequestSend 以同步或异步方式将请求 () 发送到 I/O 目标。

对使用同一请求的 WdfIoTargetFormatRequestForIoctl 的多次调用不会导致额外的资源分配。 因此,为了降低 WdfRequestCreate 返回STATUS_INSUFFICIENT_RESOURCES的可能性,驱动程序的 EvtDriverDeviceAdd 回调函数可以调用 WdfRequestCreate 来预分配设备的一个或多个请求对象。 驱动程序随后可以重复使用 (调用 WdfRequestReuse) 、重新格式化 (调用 WdfIoTargetFormatRequestForIoctl) ,并重新发送 (调用 WdfRequestSend) 每个请求对象,而不会因以后调用 WdfRequestCreate 而STATUS_INSUFFICIENT_RESOURCES返回值。 如果参数值不更改,则对 WdfIoTargetFormatRequestForIoctl 的所有后续调用都将返回STATUS_SUCCESS。 (如果驱动程序不每次调用相同的请求格式设置方法,可能会分配其他资源。此外,如果 I/O 控制代码 指定METHOD_BUFFERED的传输类型,则框架必须为每个请求分配系统缓冲区,并且该分配可能因内存资源不足而失败。)

有关在 I/O 请求完成后获取状态信息的信息,请参阅 获取完成信息

有关 WdfIoTargetFormatRequestForIoctl 的详细信息,请参阅 向常规 I/O 目标发送 I/O 请求

有关 I/O 目标的详细信息,请参阅 使用 I/O 目标

示例

以下代码重复使用预先分配的请求对象和预先分配的内存对象。 该示例将输入和输出缓冲区分配给内存对象、设置请求对象的格式、注册 CompletionRoutine 回调函数,并将请求发送到 I/O 目标。

NTSTATUS
NICSendOidRequestToTargetAsync(
    IN WDFIOTARGET  IoTarget,
    IN WDFREQUEST  Request,
    IN PFILE_OBJECT  FileObject,
    IN ULONG  IoctlControlCode,
    IN OUT PVOID  InputBuffer,
    IN ULONG  InputBufferLength,
    IN OUT PVOID  OutputBuffer,
    IN ULONG  OutputBufferLength,
    OUT PULONG  BytesReadOrWritten
    )
{
    NTSTATUS  status;
    PREQUEST_CONTEXT  reqContext;
    WDF_REQUEST_REUSE_PARAMS  params;
    WDFMEMORY  inputMem, outputMem;
 
    WDF_REQUEST_REUSE_PARAMS_INIT(
                                  &params, 
                                  WDF_REQUEST_REUSE_NO_FLAGS, 
                                  STATUS_SUCCESS
                                  );
    status = WdfRequestReuse(Request, &params);
    if (!NT_SUCCESS(status)){
        return status;
    }

    reqContext = GetRequestContext(Request);

    inputMem = outputMem = NULL;
 
    if (InputBuffer != NULL) {
        status = WdfMemoryAssignBuffer(
                                       reqContext->InputMemory,
                                       InputBuffer, 
                                       InputBufferLength
                                       );
        if (!NT_SUCCESS(status)) {
             return status;
        }
        inputMem = reqContext->InputMemory;
    }

    if (OutputBuffer != NULL) {
        status = WdfMemoryAssignBuffer(
                                       reqContext->OutputMemory,
                                       OutputBuffer, 
                                       OutputBufferLength
                                       );
        if (!NT_SUCCESS(status)) {
            return status;
        }
        outputMem = reqContext->OutputMemory;
    }

    status = WdfIoTargetFormatRequestForIoctl(
                                              IoTarget,
                                              Request,
                                              IoctlControlCode,
                                              inputMem,
                                              NULL,
                                              outputMem,
                                              NULL
                                              );
    if (!NT_SUCCESS(status)) {
        return status;
    }

    WdfRequestSetCompletionRoutine(
                                   Request,
                                   NICSendOidRequestToTargetAsyncCompletionRoutine,
                                   BytesReadOrWritten
                                   );

    if (WdfRequestSend(
                       Request,
                       IoTarget,
                       WDF_NO_SEND_OPTIONS
                       ) == FALSE) {
        status = WdfRequestGetStatus(Request);
    }
    return status;
}

要求

要求
目标平台 通用
最低 KMDF 版本 1.0
最低 UMDF 版本 2.0
标头 wdfiotarget.h (包括 Wdf.h)
Library Wdf01000.sys (KMDF) ;WUDFx02000.dll (UMDF)
IRQL <=DISPATCH_LEVEL
DDI 符合性规则 DriverCreate (kmdf) KmdfIrql (kmdf) KmdfIrql2 (kmdf) 、 KmdfIrqlExplicit (kmdf) , RequestFormattedValid (kmdf) RequestSendAndForgetNoFormatting (kmdf) RequestSendAndForgetNoFormatting2 (kmdf)

另请参阅

EvtDriverDeviceAdd

WDFMEMORY_OFFSET

WdfDeviceGetIoTarget

WdfIoTargetCreate

WdfIoTargetFormatRequestForInternalIoctl

WdfIoTargetSendIoctlSynchronously

WdfMemoryCreate

WdfMemoryCreatePreallocated

WdfRequestCreate

WdfRequestRetrieveInputMemory

WdfRequestRetrieveOutputMemory

WdfRequestReuse

WdfRequestSend