다음을 통해 공유


IWDFIoRequest::UnmarkCancelable 메서드(wudfddi.h)

[경고: UMDF 2는 UMDF의 최신 버전이며 UMDF 1을 대체합니다. 모든 새 UMDF 드라이버는 UMDF 2를 사용하여 작성해야 합니다. UMDF 1에 새 기능이 추가되지 않으며 최신 버전의 Windows 10 UMDF 1에 대한 지원이 제한됩니다. 유니버설 Windows 드라이버는 UMDF 2를 사용해야 합니다. 자세한 내용은 UMDF를 사용하여 시작 참조하세요.]

UnmarkCancelable 메서드는 I/O 요청 취소를 사용하지 않도록 설정합니다.

구문

HRESULT UnmarkCancelable();

반환 값

UnmarkCancelable 은 다음 값 중 하나를 반환합니다.

반환 코드 Description
S_OK

IWDFIoRequest::MarkCancelable 메서드에 대한 호출을 통해 이전에 등록된 IRequestCallbackCancel::OnCancel 메서드를 사용할 수 없습니다.

HRESULT_FROM_WIN32(ERROR_OPERATION_ABORTED)
요청이 현재 취소되고 있습니다.

설명

드라이버가 이전에 IWDFIoRequest::MarkCancelable 을 호출하여 요청 취소를 사용하도록 설정한 경우 드라이버는 IWDFIoRequest::UnmarkCancelable 을 호출하여 I/O 요청 취소를 사용하지 않도록 설정할 수 있습니다.

드라이버가 이전에 MarkCancelable을 호출한 경우 드라이버는 IWDFIoRequest::Complete를 호출하기 전에 IRequestCallbackCancel::OnCancel 콜백 메서드를 호출하지 않고 UnmarkCancelable을 호출해야 합니다.

그러나 OnCancel이 Complete를 호출한 후에는 드라이버가 UnmarkCancelable 호출하지 않아야 합니다.

UnmarkCancelable이 HRESULT_FROM_WIN32(ERROR_OPERATION_ABORTED)을 반환하고 OnCancel이 요청을 완료하는 경우 드라이버는 이후에 요청 개체를 사용하지 않아야 합니다.

UnmarkCancelable이 HRESULT_FROM_WIN32(ERROR_OPERATION_ABORTED)를 반환하는 경우 프레임워크가 OnCancel을 호출하기 전에 드라이버가 요청을 완료하지 않아야 합니다. 그렇지 않으면 프레임워크가 잘못된 요청으로 드라이버의 OnCancel 을 호출할 수 있습니다.

예제

다음 코드 예제에서는 IWDFIoRequest::Complete를 호출하기 전에 해당 IRequestCallbackCancel::OnCancel 메서드를 호출하지 않고 드라이버가 IWDFIoRequest::UnmarkCancelable을 호출하는 방법을 보여 줍니다.

또한 이 예제에서는 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라는 드라이버 구현 큐 개체에 I/O 요청을 저장합니다. 드라이버의 MyQueue 인터페이스는 IsEmpty, RemoveHead, Cleanup, GetFirstNodePosition, GetAtRemoveAt와 같은 큐를 조작하는 몇 가지 기본 메서드를 구현합니다.

또한 드라이버는 MyQueue의 단일 I/O 요청을 보유하는 CommandInformation 구조를 정의합니다.

MyQueue::D eQueue 메서드는 큐에서 I/O 요청을 제거하고 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 드라이버용으로 작성된 동안 이 예제에서는 프레임워크의 자동 동기화 를 사용하여 취소 콜백과 표시 해제 루틴을 호출하는 다른 스레드 간의 동기화를 관리하는 방법을 보여 줍니다.

요구 사항

요구 사항
지원 종료 UMDF 2.0 이상에서는 사용할 수 없습니다.
대상 플랫폼 데스크톱
최소 UMDF 버전 1.5
머리글 wudfddi.h(Wudfddi.h 포함)
DLL WUDFx.dll

추가 정보

IRequestCallbackCancel::OnCancel

IWDFIoRequest

IWDFIoRequest::Complete

IWDFIoRequest::MarkCancelable