IWDFIoRequest::UnmarkCancelable-Methode (wudfddi.h)

[Warnung: UMDF 2 ist die neueste Version von UMDF und ersetzt UMDF 1. Alle neuen UMDF-Treiber sollten mit UMDF 2 geschrieben werden. UMDF 1 werden keine neuen Features hinzugefügt, und die Unterstützung für UMDF 1 für neuere Versionen von Windows 10 ist eingeschränkt. Universelle Windows-Treiber müssen UMDF 2 verwenden. Weitere Informationen finden Sie unter Erste Schritte mit UMDF.]

Die UnmarkCancelable-Methode deaktiviert das Abbrechen einer E/A-Anforderung.

Syntax

HRESULT UnmarkCancelable();

Rückgabewert

UnmarkCancelable gibt einen der folgenden Werte zurück:

Rückgabecode BESCHREIBUNG
S_OK

UnmarkCancelable hat die Verwendung der IRequestCallbackCancel::OnCancel-Methode deaktiviert, die zuvor über einen Aufruf der IWDFIoRequest::MarkCancelable-Methode registriert wurde.

HRESULT_FROM_WIN32 (ERROR_OPERATION_ABORTED)
Die Anforderung wird derzeit abgebrochen.

Hinweise

Ein Treiber kann IWDFIoRequest::UnmarkCancelable aufrufen, um den Abbruch einer E/A-Anforderung zu deaktivieren, wenn der Treiber zuvor IWDFIoRequest::MarkCancelable aufgerufen hat, um den Abbruch der Anforderung zu aktivieren.

Wenn der Treiber zuvor MarkCancelable genannt hat, muss der Treiber UnmarkCancelable aufrufen, bevor er IWDFIoRequest::Complete außerhalb eines Aufrufs seiner IRequestCallbackCancel::OnCancelcel-Rückrufmethode aufruft.

Der Treiber darf jedoch nicht UnmarkCancelable aufrufen, nachdem OnCancelComplete aufgerufen hat.

Wenn UnmarkCancelable HRESULT_FROM_WIN32(ERROR_OPERATION_ABORTED) zurückgibt und onCancel die Anforderung dann abgeschlossen hat, darf der Treiber das Anforderungsobjekt anschließend nicht verwenden.

Wenn UnmarkCancelable HRESULT_FROM_WIN32(ERROR_OPERATION_ABORTED) zurückgibt, darf der Treiber die Anforderung nicht abschließen, bevor das Framework OnCancel aufruft. Andernfalls ruft das Framework möglicherweise onCancel des Treibers mit einer ungültigen Anforderung auf.

Beispiele

Im folgenden Codebeispiel wird veranschaulicht, wie ein Treiber IWDFIoRequest::UnmarkCancelable aufrufen kann, bevor er IWDFIoRequest::Complete aufruft, außerhalb eines Aufrufs seiner IRequestCallbackCancel::OnCancel-Methode .

Das Beispiel zeigt auch, wie Sie onCancel verwenden können, um die Vervollständigung einer Anforderung zu beschleunigen. In diesem Fall wird die angegebene Anforderung nicht immer durch den OnCancel-Rückruf abgeschlossen bzw. abgebrochen.

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


Im nächsten Codebeispiel speichert der Treiber E/A-Anforderungen in einem vom Treiber implementierten Warteschlangenobjekt namens MyQueue. Die MyQueue-Schnittstelle des Treibers implementiert einige grundlegende Methoden zum Bearbeiten der Warteschlange, z. B. IsEmpty, RemoveHead, Cleanup, GetFirstNodePosition, GetAt und RemoveAt.

Der Treiber definiert auch eine CommandInformation-Struktur , die eine einzelne E/A-Anforderung von MyQueue enthält.

Die MyQueue::D eQueue-Methode entfernt eine E/A-Anforderung aus der Warteschlange, ruft UnmarkCancelable auf, um das Abbrechen der Anforderung zu deaktivieren, und gibt dann die Anforderung zur Verarbeitung zurück.


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



Sehen Sie sich auch das Codebeispiel auf WdfRequestUnmarkCancelable an. Dieses Beispiel wird für einen KMDF-Treiber geschrieben und veranschaulicht, wie Sie die automatische Synchronisierung des Frameworks verwenden können, um die Synchronisierung zwischen dem Rückruf zum Abbrechen und einem anderen Thread zu verwalten, der die Unmarking-Routine aufruft.

Anforderungen

Anforderung Wert
Ende des Supports In UMDF 2.0 und höher nicht verfügbar.
Zielplattform Desktop
UMDF-Mindestversion 1.5
Kopfzeile wudfddi.h (include Wudfddi.h)
DLL WUDFx.dll

Weitere Informationen

IRequestCallbackCancel::OnCancel

IWDFIoRequest

IWDFIoRequest::Complete

IWDFIoRequest::MarkCancelable