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


Метод 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 после вызова OnCancel вызовов Complete.

Если 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 (include Wudfddi.h)
DLL WUDFx.dll

См. также

IRequestCallbackCancel::OnCancel

IWDFIoRequest

IWDFIoRequest::Complete

IWDFIoRequest::MarkCancelable