Функция WdfRequestMarkCancelableEx (wdfrequest.h)

[Применимо к KMDF и UMDF]

Метод WdfRequestMarkCancelableEx позволяет отменить указанный запрос ввода-вывода.

Синтаксис

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

Параметры

[in] Request

Дескриптор объекта запроса платформы.

[in] EvtRequestCancel

Указатель на определяемую драйвером функцию обратного вызова EvtRequestCancel , которую платформа вызывает, если отменяет запрос ввода-вывода.

Возвращаемое значение

WdfRequestMarkCancelableEx возвращает STATUS_SUCCESS, если успешно включает отмену указанного запроса ввода-вывода. В противном случае этот метод может возвращать одно из следующих значений:

Код возврата Описание
STATUS_CANCELLED
Запрос ввода-вывода отменен. Дополнительные сведения см. в разделе Примечания.
STATUS_INVALID_DEVICE_REQUEST
  • Драйвер не является владельцем запроса ввода-вывода.
  • Запрос ввода-вывода уже можно отменить.
 

Этот метод также может возвращать другие значения NTSTATUS.

Ошибка проверка возникает, если драйвер предоставляет недопустимый дескриптор объекта.

Комментарии

После того как драйвер получит запрос ввода-вывода от платформы, драйвер может вызвать WdfRequestMarkCancelable или, начиная с KMDF версии 1.9, WdfRequestMarkCancelableEx , чтобы сделать запрос отмененным. Сведения о выборе между этими двумя методами см. в разделе WdfRequestMarkCancelable.

При вызове WdfRequestMarkCancelableEx драйвер должен указать функцию обратного вызова EvtRequestCancel . Платформа вызывает функцию обратного вызова, если диспетчер ввода-вывода или другой драйвер пытается отменить запрос ввода-вывода.

Если WdfRequestMarkCancelableEx возвращает ошибку, драйвер должен выполнять те же действия отмены, что и функция обратного вызова EvtRequestCancel . Пример:

  1. Завершите или остановите обработку запроса вместе с вложенными запросами, которые он мог создать.
  2. Вызовите WdfRequestComplete, указав значение состояния STATUS_CANCELLED.
См. примеры кода ниже для реализации.

Поскольку WdfRequestMarkCancelableEx никогда не вызывает EvtRequestCancel, этот метод защищен от риска взаимоблокировки, описанного в примечаниях WdfRequestMarkCancelable.

Обработка запроса после включения отмены

После того как драйвер вызывает WdfRequestMarkCancelableEx для включения отмены, запрос остается отменяемым, пока драйвер является владельцем объекта запроса, если драйвер не вызывает WdfRequestUnmarkCancelable.

Если драйвер вызывает WdfRequestMarkCancelableEx, а функция обратного вызова EvtRequestCancel драйвера не выполняется и вызывает WdfRequestComplete, драйвер должен вызвать WdfRequestUnmarkCancelable перед вызовомWdfRequestComplete вне функции обратного вызова EvtRequestCancel .

Если драйвер вызывает WdfRequestForwardToIoQueue для переадресации запроса в другую очередь, применяются следующие правила:

  • Запросы ввода-вывода нельзя отменить, если драйвер перенаправит их в другую очередь.

    Как правило, драйвер не должен вызывать WdfRequestMarkCancelableEx , чтобы включить отмену запроса перед вызовом WdfRequestForwardToIoQueue. Если драйвер делает запрос отмененным, он должен вызвать WdfRequestUnmarkCancelable , чтобы отключить отмену перед вызовом WdfRequestForwardToIoQueue.

  • Пока запрос находится во второй очереди, платформа владеет им и может отменить его, не уведомляя драйвер.

    Если драйвер требует уведомления об отмене (чтобы он мог освободить все ресурсы, которые он мог выделить перед вызовом WdfRequestForwardToIoQueue), драйвер должен зарегистрировать функцию обратного вызова EvtIoCanceledOnQueue и использовать контекстную память для конкретного запроса для хранения сведений о ресурсах запроса.

  • После того как платформа вывела запрос из второй очереди и доставит его драйверу, драйвер может вызвать WdfRequestMarkCancelableEx , чтобы включить отмену.
Дополнительные сведения о WdfRequestMarkCancelableEx см. в разделе Отмена запросов ввода-вывода.

Примеры

В следующих примерах кода показаны части двух функций обратного вызова:

  • Функция обратного вызова EvtIoRead , которая выполняет работу по конкретному запросу (например, создает вложенные запросы для отправки в целевой объект ввода-вывода), а затем включает отмену полученного запроса ввода-вывода.
  • Функция обратного вызова 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)
Библиотека 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), MarkCancOnCancReqLocal(kmdf), ReqIsCancOnCancReq(kmdf), ReqMarkCancelableSend(kmdf), ReqNotCanceledLocal(kmdf), RequestCompleted(kmdf), RequestCompletedLocal( kmdf)

См. также раздел

EvtRequestCancel

WdfRequestComplete

WdfRequestForwardToIoQueue

WdfRequestMarkCancelable

WdfRequestUnmarkCancelable