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 |
---|---|
|
IWDFIoRequest::MarkCancelable 메서드에 대한 호출을 통해 이전에 등록된 IRequestCallbackCancel::OnCancel 메서드를 사용할 수 없습니다. |
|
요청이 현재 취소되고 있습니다. |
설명
드라이버가 이전에 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, GetAt 및 RemoveAt와 같은 큐를 조작하는 몇 가지 기본 메서드를 구현합니다.
또한 드라이버는 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 |