Поделиться через


Метод IWDFIoRequest::UnmarkCancelable (wudfddi.h)

[Предупреждение: UMDF 2 является последней версией UMDF и заменяет UMDF 1. Все новые драйверы UMDF должны быть написаны с помощью UMDF 2. В UMDF 1 новые функции не добавляются, а поддержка UMDF 1 в более новых версиях Windows 10 ограничена. Универсальные драйверы Windows должны использовать UMDF 2. Дополнительные сведения см. в разделе начало работы с UMDF.]

Метод UnmarkCancelable отключает отмену запроса ввода-вывода.

Синтаксис

HRESULT UnmarkCancelable();

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

UnmarkCancelable возвращает одно из следующих значений:

Код возврата Описание
S_OK

UnmarkCancelable отключено использование метода IRequestCallbackCancel::OnCancel , который ранее был зарегистрирован с помощью вызова метода IWDFIoRequest::MarkCancelable .

HRESULT_FROM_WIN32 (ERROR_OPERATION_ABORTED)
Запрос в настоящее время отменен.

Комментарии

Драйвер может вызвать IWDFIoRequest::UnmarkCancelable , чтобы отключить отмену запроса ввода-вывода, если драйвер ранее вызывал IWDFIoRequest::MarkCancelable , чтобы включить отмену запроса.

Если драйвер ранее назывался MarkCancelable, драйвер должен вызвать UnmarkCancelable перед вызовом метода обратного вызова IWDFIoRequest::Complete вне вызова метода обратного вызова IRequestCallbackCancel::OnCancel .

Однако драйвер не должен вызывать UnmarkCancelable после вызова OnCancelComplete.

Если UnmarkCancelable возвращает HRESULT_FROM_WIN32(ERROR_OPERATION_ABORTED), а затем OnCancel завершает запрос, драйвер не должен впоследствии использовать объект запроса.

Если UnmarkCancelable возвращает HRESULT_FROM_WIN32(ERROR_OPERATION_ABORTED), драйвер не должен завершить запрос, прежде чем платформа вызовет OnCancel. В противном случае платформа может вызвать OnCancel драйвера с недопустимым запросом.

Примеры

В следующем примере кода показано, как драйвер может вызывать IWDFIoRequest::UnmarkCancelable перед вызовомIWDFIoRequest::Complete вне вызова метода IRequestCallbackCancel::OnCancel .

В примере также показано, как можно использовать OnCancel для ускорения выполнения запроса. В этом случае обратный вызов OnCancel не всегда завершает или отменяет указанный запрос.

//
// The driver calls CompletePendingRequest when it is ready to complete the request with error/success.
// You must previously initialize m_CompleteCancelledRequest to zero.
//
VOID
CompletePendingRequest( 
    HRESULT hr,
    DWORD   information
    )
{
    LONG shouldComplete = 1;

    if (m_PendingRequest) {
        HRESULT hrUnmark = m_PendingRequest->UnmarkCancelable();
        if (HRESULT_FROM_WIN32(ERROR_OPERATION_ABORTED) == hrUnmark) { 
            //
            // We are racing with OnCancel.  We cannot complete m_PendingRequest until after
            // both IWDFIoRequest::Complete and OnCancel have finished with it. To
            // guarantee this, the last to run (either OnCancel or CompletePendingRequest) will
            // be the one to complete the request. 
            //
            shouldComplete = InterlockedExchange(&m_CompleteCancelledRequest, 1);
        }

        // 
        // If we were first to set m_CompleteCancelledRequest to 1, then drop out here
        // and rely on OnCancel to complete the request.
        // 

        if (1 == shouldComplete) { 
            IWDFIoRequest *FxRequest = (IWDFIoRequest*)InterlockedExchangePointer((PVOID *)&m_PendingRequest, NULL);
            InterlockedExchange(&m_CompleteCancelledRequest, 0);
            FxRequest->SetInformation(information);
            FxRequest->Complete(hr);
        }
   }
}

//
// The framework calls OnCancel when an application cancels a pending I/O request. 
//
VOID
STDMETHODCALLTYPE
OnCancel(
    _In_ IWDFIoRequest *pWdfRequest
    )
{
    if (m_PendingRequest != pWdfRequest) {
        TraceEvents(TRACE_LEVEL_ERROR, 
                    YOURDEVICE_TRACE_DEVICE, 
                    "%!FUNC! Cancelled request does not match pending request.");
    }

    // 
    // Add your code to speed up the completion of the request.  Maybe you need to reset the hardware or 
    // do some other domain-specific task.
    //

    //
    // Since we only complete the request if we were the last to run (see comment in
    // CompletePendingRequest), if we are *not* the last to run we rely on CompletePendingRequest 
    // to complete this request.
    //

    LONG shouldComplete = InterlockedExchange(&m_CompleteCancelledRequest, 1);
    if (1 == shouldComplete) { 
        //
        // Enter this block only if we are the last to run.
        // Otherwise, rely on CompletePendingRequest to complete this request.
        //
        (void*) InterlockedExchangePointer((PVOID *)&m_PendingRequest, NULL);
        InterlockedExchange(&m_CompleteCancelledRequest, 0);
        pWdfRequest->Complete(HRESULT_FROM_WIN32(ERROR_CANCELLED));
     } 
 
}


В следующем примере кода драйвер сохраняет запросы ввода-вывода в реализуемом драйвером объекте очереди MyQueue. Интерфейс MyQueue драйвера реализует некоторые основные методы для управления очередью, такие как IsEmpty, RemoveHead, Cleanup, GetFirstNodePosition, GetAt и RemoveAt.

Драйвер также определяет структуру CommandInformation , которая содержит один запрос ввода-вывода из MyQueue.

Метод MyQueue::D eQueue удаляет запрос ввода-вывода из очереди, вызывает UnmarkCancelable , чтобы отключить отмену запроса, а затем возвращает запрос на обработку.


void MyQueue::DeQueue(__out CommandInformation* CommandInfo)
{
    CComCritSecLock<CComAutoCriticalSection> scopeLock(m_CriticalSection);

    if (NULL != CommandInfo)
    {
        for (;;) 
        {
            if (TRUE == IsEmpty()) 
            {
                ZeroMemory(CommandInfo, sizeof(CommandInformation));
                break;
            }
            //
            // If queue is not empty, retrieve the first element from the list.
            //
            *CommandInfo = RemoveHead(); 
            if (HRESULT_FROM_WIN32(ERROR_OPERATION_ABORTED) != (CommandInfo->Request)->UnmarkCancelable())
            {
                //
                // UnmarkCancelable was successful.
                // Ownership of this request has been transferred back to this driver.
                //
                break;
            }
            else
            {
                //
                // If UMDF returns HRESULT_FROM_WIN32(ERROR_OPERATION_ABORTED) for UnmarkCancelable,
                // that means UMDF is planning on cancelling the request. However, since this call
                // popped the request off our internal queue, let’s cleanup the generic command object
                // and let OnCancel complete the request.               
                //                
                CommandInfo->Cleanup();
            }
        }    
    }
}

//
// The framework calls OnCancel when an application cancels a dispatched I/O request.
//
void MyQueue::OnCancel(__in IWDFIoRequest* Request)
{
    {
        CComCritSecLock<CComAutoCriticalSection> scopeLock(m_CriticalSection);

        POSITION pos = GetFirstNodePosition();

        while (NULL != pos)
        {
            //
            // Find the request and remove it from our driver-implemented queue.
            //
            CommandInformation commandInfo = GetAt(pos);
            if (Request == commandInfo.Request)
            {
                RemoveAt(pos);
                commandInfo.Cleanup();
                break;
            }

            GetNext(pos);
        }
    }

    //
    // Cancel/Complete the request.
    //
    // The request might not be in the queue when the framework calls OnCancel. 
    // This occurs if DeQueue receives HRESULT_FROM_WIN32(ERROR_OPERATION_ABORTED)
    // when it calls UnmarkCancelable for the request. In this case, as soon as
    // DeQueue releases the scopeLock, the framework calls OnCancel to cancel the request.
    //
    Request->Complete(HRESULT_FROM_WIN32(ERROR_CANCELLED));
}



См. также пример кода в WdfRequestUnmarkCancelable. В этом примере, написанном для драйвера KMDF, показано, как использовать автоматическую синхронизацию платформы для управления синхронизацией между обратным вызовом отмены и другим потоком, вызывающим подпрограмму Unmark .

Требования

Требование Значение
Дата окончания поддержки Недоступно в UMDF 2.0 и более поздних версиях.
Целевая платформа Персональный компьютер
Минимальная версия UMDF 1.5
Верхняя часть wudfddi.h (включая Wudfddi.h)
DLL WUDFx.dll

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

IRequestCallbackCancel::OnCancel

IWDFIoRequest

IWDFIoRequest::Complete

IWDFIoRequest::MarkCancelable