WdfRequestMarkCancelableEx 函数 (wdfrequest.h)

[适用于 KMDF 和 UMDF]

WdfRequestMarkCancelableEx 方法允许取消指定的 I/O 请求。

语法

NTSTATUS WdfRequestMarkCancelableEx(
  [in] WDFREQUEST             Request,
  [in] PFN_WDF_REQUEST_CANCEL EvtRequestCancel
);

参数

[in] Request

框架请求对象的句柄。

[in] EvtRequestCancel

指向驱动程序定义的 EvtRequestCancel 回调函数的指针,框架在取消 I/O 请求时调用该函数。

返回值

如果 WdfRequestMarkCancelableEx 成功启用指定 I/O 请求的取消,则返回STATUS_SUCCESS。 否则,此方法可能会返回以下值之一:

返回代码 说明
STATUS_CANCELLED
I/O 请求已取消。 有关详细信息,请参阅“备注”。
STATUS_INVALID_DEVICE_REQUEST
  • 驱动程序不拥有 I/O 请求。
  • I/O 请求已可取消。
 

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

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

注解

在驱动程序收到来自框架的 I/O 请求 后,驱动程序可以调用 WdfRequestMarkCancelable ,或者从 KMDF 版本 1.9 开始调用 WdfRequestMarkCancelableEx 以使请求可取消。 有关在两种方法之间进行选择的信息,请参阅 WdfRequestMarkCancelable

调用 WdfRequestMarkCancelableEx 时,驱动程序必须指定 EvtRequestCancel 回调函数。 如果 I/O 管理器或其他驱动程序尝试取消 I/O 请求,框架将调用回调函数。

如果 WdfRequestMarkCancelableEx 返回失败,驱动程序必须执行 与 EvtRequestCancel 回调函数相同的取消活动。 例如:

  1. 完成或停止处理请求,以及它可能已创建的子请求。
  2. 调用 WdfRequestComplete,将状态值指定为 STATUS_CANCELLED。
有关实现,请参阅下面的代码示例。

由于 WdfRequestMarkCancelableEx 从不调用 EvtRequestCancel,因此此方法可以免受 WdfRequestMarkCancelable 备注中所述的死锁风险。

启用取消后处理请求

在驱动程序调用 WdfRequestMarkCancelableEx 以启用取消后,该请求在驱动程序 拥有 请求对象时保持可取消状态,除非驱动程序调用 WdfRequestUnmarkCancelable

如果驱动程序已调用 WdfRequestMarkCancelableEx,并且驱动程序的 EvtRequestCancel 回调函数尚未执行并调用 WdfRequestComplete,则驱动程序必须先调用 WdfRequestUnmarkCancelable,然后才能在 EvtRequestCancel 回调函数外部调用 WdfRequestComplete

如果驱动程序调用 WdfRequestForwardToIoQueue 将请求转发到其他队列,则以下规则适用:

  • 当驱动程序将 I/O 请求转发到其他队列时,无法取消这些请求。

    通常,驱动程序不应调用 WdfRequestMarkCancelableEx 来启用在调用 WdfRequestForwardToIoQueue 之前取消请求。 如果驱动程序确实使请求可取消,则必须调用 WdfRequestUnmarkCancelable 以在调用 WdfRequestForwardToIoQueue 之前禁用取消。

  • 当请求位于第二个队列中时,框架拥有它,并且可以取消它,而无需通知驱动程序。

    如果驱动程序需要取消通知 (以便它可以解除分配在调用 WdfRequestForwardToIoQueue) 之前可能已分配的任何资源,则驱动程序应注册 EvtIoCanceledOnQueue 回调函数,并且它应使用特定于请求的上下文内存来存储有关请求的资源的信息。

  • 框架从第二个队列中取消请求的排队并将其传递到驱动程序后,驱动程序可以调用 WdfRequestMarkCancelableEx 以启用取消。
有关 WdfRequestMarkCancelableEx 的详细信息,请参阅 取消 I/O 请求

示例

以下代码示例显示了两个回调函数的一部分:

  • EvtIoRead 回调函数执行特定于请求的工作 (,例如创建要发送到 I/O 目标) 的子请求,然后取消收到的 I/O 请求。
  • 取消 I/O 请求的 EvtRequestCancel 回调函数。
在第一个示例中,驱动程序使用框架的 自动同步。 在第二个示例中,驱动程序使用旋转锁提供自己的同步。

示例 1:使用自动同步的驱动程序。

VOID
MyEvtIoRead(
    IN WDFQUEUE  Queue,
    IN WDFREQUEST  Request,
    IN size_t  Length
    )
{
...
    NTSTATUS status;
...
    // Perform request-specific work here
    // (such as creating subrequests 
    // to send to an I/O target). 
...
    status = WdfRequestMarkCancelableEx(
                                        Request,
                                        MyEvtRequestCancel
                                        );

    if (!NT_SUCCESS(status)) {
       // Remove request-specific work here, because
       // we don't want the work to be done if the
       // request was canceled or an error occurred.

        WdfRequestComplete (Request, status);
    }
...
}

VOID
MyEvtRequestCancel(
    IN WDFREQUEST  Request
 )
{
    // Remove request-specific work here, because
    // we don't want the work to be done if the
    // request was canceled.

    WdfRequestComplete(
                       Request,
                       STATUS_CANCELLED
                       );
}

示例 2:使用其自身同步的驱动程序。

VOID
MyEvtIoRead(
    IN WDFQUEUE  Queue,
    IN WDFREQUEST  Request,
    IN size_t  Length
    )
{
...
    NTSTATUS status;
...
    WdfSpinlockAcquire(MyCancelSpinLock);
    // Perform request-specific work here
    // (such as creating subrequests 
    // to send to an I/O target). 
...
    status = WdfRequestMarkCancelableEx(
                                        Request,
                                        MyEvtRequestCancel
                                        );

    if (!NT_SUCCESS(status)) {
        // Remove request-specific work here, because
        // we don't want the work to be done if the
        // request was canceled or an error occurred.
     }
    WdfSpinlockRelease(MyCancelSpinLock);
    if (!NT_SUCCESS(status)) {
        WdfRequestComplete (
                            Request,
                            Status
                            );
    }
...
}
VOID
MyEvtRequestCancel(
    IN WDFREQUEST  Request
 )
{
    WdfSpinlockAcquire(MyCancelSpinLock);
    // Remove request-specific work here, because
    // we don't want the work to be done if the
    // request was canceled.
    WdfSpinlockRelease(MyCancelSpinLock);
    WdfRequestComplete (Request, STATUS_CANCELLED);
}

要求

要求
目标平台 通用
最低 KMDF 版本 1.9
最低 UMDF 版本 2.0
标头 wdfrequest.h (包括 Wdf.h)
Library Wdf01000.sys (KMDF) ;WUDFx02000.dll (UMDF)
IRQL <=DISPATCH_LEVEL
DDI 符合性规则 DeferredRequestCompleted (kmdf) DriverCreate (kmdf) EvtIoStopCancel (kmdf) InvalidReqAccess (kmdf) InvalidReqAccessLocal (kmdf) KmdfIrql (kmdf) KmdfIrql2 (kmdf) 、 KmdfIrqlExplicit (kmdf) , MarkCancCancReqLocal (kmdf) ReqIsCancCancCancReq (kmdf) ReqMarkCancelableSend (kmdf) ReqNotCanceledLocal (kmdf) RequestCompleted (kmdf) RequestCompletedLocal (kmdf)

另请参阅

EvtRequestCancel

WdfRequestComplete

WdfRequestForwardToIoQueue

WdfRequestMarkCancelable

WdfRequestUnmarkCancelable