Método IWDFIoRequest::UnmarkCancelable (wudfddi.h)
[Aviso: UMDF 2 é a versão mais recente do UMDF e substitui UMDF 1. Todos os novos drivers UMDF devem ser gravados usando UMDF 2. Nenhum novo recurso está sendo adicionado ao UMDF 1 e há suporte limitado para UMDF 1 em versões mais recentes do Windows 10. Os drivers universais do Windows devem usar o UMDF 2. Para obter mais informações, consulte Introdução com UMDF.]
O método UnmarkCancelable desabilita o cancelamento de uma solicitação de E/S.
Sintaxe
HRESULT UnmarkCancelable();
Retornar valor
UnmarkCancelable retorna um dos seguintes valores:
Código de retorno | Descrição |
---|---|
|
UnmarkCancelable desabilitou o uso do método IRequestCallbackCancel::OnCancel que foi registrado anteriormente por meio de uma chamada para o método IWDFIoRequest::MarkCancelable . |
|
No momento, a solicitação está sendo cancelada. |
Comentários
Um driver pode chamar IWDFIoRequest::UnmarkCancelable para desabilitar o cancelamento de uma solicitação de E/S, se o driver anteriormente chamou IWDFIoRequest::MarkCancelable para habilitar o cancelamento da solicitação.
Se o driver anteriormente chamado MarkCancelable, o driver deverá chamar UnmarkCancelable antes de chamar IWDFIoRequest::Complete fora de uma chamada para seu método de retorno de chamada IRequestCallbackCancel::OnCancel .
No entanto, o driver não deve chamar UnmarkCancelable após OnCancel chamar Complete.
Se UnmarkCancelable retornar HRESULT_FROM_WIN32(ERROR_OPERATION_ABORTED) e , em seguida, OnCancel concluir a solicitação, o driver não deverá usar posteriormente o objeto de solicitação.
Se UnmarkCancelable retornar HRESULT_FROM_WIN32(ERROR_OPERATION_ABORTED), o driver não deverá concluir a solicitação antes que a estrutura chame OnCancel. Caso contrário, a estrutura pode chamar OnCancel do driver com uma solicitação inválida.
Exemplos
O exemplo de código a seguir demonstra como um driver pode chamar IWDFIoRequest::UnmarkCancelable antes de chamar IWDFIoRequest::Complete, fora de uma chamada para seu método IRequestCallbackCancel::OnCancel .
O exemplo também mostra como você pode usar o OnCancel para agilizar a conclusão de uma solicitação. Nesse caso, o retorno de chamada OnCancel nem sempre conclui/cancela a solicitação 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));
}
}
No próximo exemplo de código, o driver armazena solicitações de E/S em um objeto de fila implementado pelo driver chamado MyQueue. A interface MyQueue do driver implementa alguns métodos básicos para manipular a fila, como IsEmpty, RemoveHead, Cleanup, GetFirstNodePosition, GetAt e RemoveAt.
O driver também define uma estrutura CommandInformation que contém uma única solicitação de E/S do MyQueue.
O método MyQueue::D eQueue remove uma solicitação de E/S da fila, chama UnmarkCancelable para desabilitar o cancelamento da solicitação e retorna a solicitação de processamento.
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));
}
Consulte também o exemplo de código em WdfRequestUnmarkCancelable. Enquanto gravado para um driver KMDF, este exemplo demonstra como você pode usar a sincronização automática da estrutura para gerenciar a sincronização entre o retorno de chamada de cancelamento e outro thread que chama a rotina da Dinamarca .
Requisitos
Requisito | Valor |
---|---|
Fim do suporte | Indisponível no UMDF 2.0 e posterior. |
Plataforma de Destino | Área de Trabalho |
Versão mínima do UMDF | 1.5 |
Cabeçalho | wudfddi.h (inclua Wudfddi.h) |
DLL | WUDFx.dll |