Metodo IWDFIoRequest::UnmarkCancelable (wudfddi.h)

[Avviso: UMDF 2 è la versione più recente di UMDF e sostituisce UMDF 1. Tutti i nuovi driver UMDF devono essere scritti usando UMDF 2. Nessuna nuova funzionalità viene aggiunta a UMDF 1 ed è disponibile un supporto limitato per UMDF 1 nelle versioni più recenti di Windows 10. I driver di Windows universali devono usare UMDF 2. Per altre informazioni, vedere Introduzione con UMDF.]

Il metodo UnmarkCancelable disabilita l'annullamento di una richiesta di I/O.

Sintassi

HRESULT UnmarkCancelable();

Valore restituito

UnmarkCancelable restituisce uno dei valori seguenti:

Codice restituito Descrizione
S_OK

L'uso disabilitato UnmarkCancelable del metodo IRequestCallbackCancel::OnCancel registrato in precedenza tramite una chiamata al metodo IWDFIoRequest::MarkCancelable.

HRESULT_FROM_WIN32 (ERROR_OPERATION_ABORTED)
La richiesta è attualmente annullata.

Commenti

Un driver può chiamare IWDFIoRequest::UnmarkCancelable per disabilitare l'annullamento di una richiesta di I/O, se il driver chiamato in precedenza IWDFIoRequest::MarkCancelable per abilitare l'annullamento della richiesta.

Se il driver chiamato in precedenza MarkCancelable, il driver deve chiamare UnmarkCancelable prima di chiamare IWDFIoRequest::Complete all'esterno di una chiamata al relativo metodo IRequestCallbackCancel::OnCancel callback.

Tuttavia, il driver non deve chiamare UnmarkCancelable dopo le chiamate OnCancelcomplete.

Se UnmarkCancelable restituisce HRESULT_FROM_WIN32(ERROR_OPERATION_ABORTED) e onCancel completa la richiesta, il driver non deve successivamente usare l'oggetto request.

Se UnmarkCancelable restituisce HRESULT_FROM_WIN32(ERROR_OPERATION_ABORTED), il driver non deve completare la richiesta prima che il framework chiami OnCancel. In caso contrario, il framework potrebbe chiamare OnCancel del driver con una richiesta non valida.

Esempio

Nell'esempio di codice seguente viene illustrato come un driver potrebbe chiamare IWDFIoRequest::UnmarkCancelable prima di chiamare IWDFIoRequest::Complete, all'esterno di una chiamata al relativo metodo IRequestCallbackCancel::OnCancel.

L'esempio illustra anche come usare OnCancel per accelerare il completamento di una richiesta. In questo caso, il callback OnCancel non viene sempre completato/annulla la richiesta specificata.

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


Nell'esempio di codice successivo, il driver archivia le richieste di I/O in un oggetto coda implementato dal driver denominato MyQueue. L'interfaccia MyQueue del driver implementa alcuni metodi di base per modificare la coda, ad esempio IsEmpty, RemoveHead, Cleanup,GetFirstNodePosition, GetAt e RemoveAt.

Il driver definisce anche una struttura CommandInformation che contiene una singola richiesta di I/O da MyQueue.

Il metodo MyQueue::D eQueue rimuove una richiesta di I/O dalla coda, chiama UnmarkCancelable per disabilitare l'annullamento della richiesta e quindi restituisce la richiesta di elaborazione.


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



Vedere anche l'esempio di codice in WdfRequestUnmarkCancelable. Durante la scrittura per un driver KMDF, questo esempio illustra come usare la sincronizzazione automatica del framework per gestire la sincronizzazione tra il callback annulla e un altro thread che chiama la routine Unmark .

Requisiti

Requisito Valore
Fine del supporto Non disponibile in UMDF 2.0 e versioni successive.
Piattaforma di destinazione Desktop
Versione UMDF minima 1.5
Intestazione wudfddi.h (include Wudfddi.h)
DLL WUDFx.dll

Vedi anche

IRequestCallbackCancel::OnCancel

IWDFIoRequest

IWDFIoRequest::Complete

IWDFIoRequest::MarkCancelable