Método IWDFIoRequest::UnmarkCancelable (wudfddi.h)

[Advertencia: UMDF 2 es la versión más reciente de UMDF y sustituye a UMDF 1. Todos los controladores UMDF nuevos deben escribirse con UMDF 2. No se agregan nuevas características a UMDF 1 y hay compatibilidad limitada con UMDF 1 en versiones más recientes de Windows 10. Los controladores universales de Windows deben usar UMDF 2. Para obtener más información, consulta Introducción con UMDF.

El método UnmarkCancelable deshabilita la cancelación de una solicitud de E/S.

Sintaxis

HRESULT UnmarkCancelable();

Valor devuelto

UnmarkCancelable devuelve uno de los siguientes valores:

Código devuelto Descripción
S_OK

UnmarkCancelable disabled use of the IRequestCallbackCancel::OnCancel method that was registered through a call to the IWDFIoRequest::MarkCancelable method.

HRESULT_FROM_WIN32 (ERROR_OPERATION_ABORTED)
La solicitud se está cancelando actualmente.

Comentarios

Un controlador puede llamar a IWDFIoRequest::UnmarkCancelable para deshabilitar la cancelación de una solicitud de E/S, si el controlador anteriormente llamado IWDFIoRequest::MarkCancelable para habilitar la cancelación de la solicitud.

Si el controlador llamó anteriormente a MarkCancelable, el controlador debe llamar a UnmarkCancelable antes de llamar a IWDFIoRequest::Complete fuera de una llamada a su método de devolución de llamada IRequestCallbackCancel::OnCancel .

Sin embargo, el controlador no debe llamar a UnmarkCancelable después de llamar a OnCancelcomplete.

Si UnmarkCancelable devuelve HRESULT_FROM_WIN32(ERROR_OPERATION_ABORTED) y, a continuación, OnCancel completa la solicitud, el controlador no debe usar posteriormente el objeto de solicitud.

Si UnmarkCancelable devuelve HRESULT_FROM_WIN32(ERROR_OPERATION_ABORTED), el controlador no debe completar la solicitud antes de que el marco llame a OnCancel. De lo contrario, el marco podría llamar a OnCancel del controlador con una solicitud no válida.

Ejemplos

En el ejemplo de código siguiente se muestra cómo un controlador podría llamar a IWDFIoRequest::UnmarkCancelable antes de llamar a IWDFIoRequest::Complete, fuera de una llamada a su método IRequestCallbackCancel::OnCancel .

En el ejemplo también se muestra cómo puede usar OnCancel para acelerar la finalización de una solicitud. En este caso, la devolución de llamada OnCancel no siempre completa o cancela la solicitud especificada.

//
// 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));
     } 
 
}


En el ejemplo de código siguiente, el controlador almacena solicitudes de E/S en un objeto de cola implementado por el controlador denominado MyQueue. La interfaz MyQueue del controlador implementa algunos métodos básicos para manipular la cola, como IsEmpty, RemoveHead, Cleanup, GetFirstNodePosition, GetAt y RemoveAt.

El controlador también define una estructura CommandInformation que contiene una única solicitud de E/S de MyQueue.

El método MyQueue::D eQueue quita una solicitud de E/S de la cola, llama a UnmarkCancelable para deshabilitar la cancelación de la solicitud y, a continuación, devuelve la solicitud de procesamiento.


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));
}



Vea también el ejemplo de código en WdfRequestUnmarkCancelable. Mientras se escribe para un controlador KMDF, en este ejemplo se muestra cómo puede usar la sincronización automática del marco para administrar la sincronización entre la devolución de llamada de cancelación y otro subproceso que llama a la rutina Unmark .

Requisitos

Requisito Value
Finalización del soporte técnico No disponible en UMDF 2.0 y versiones posteriores.
Plataforma de destino Escritorio
Versión mínima de UMDF 1.5
Encabezado wudfddi.h (incluya Wudfddi.h)
Archivo DLL WUDFx.dll

Consulte también

IRequestCallbackCancel::OnCancel

IWDFIoRequest

IWDFIoRequest::Complete

IWDFIoRequest::MarkCancelable