Méthode IWDFIoRequest ::UnmarkCancelable (wudfddi.h)
[Avertissement : UMDF 2 est la dernière version d’UMDF et remplace UMDF 1. Tous les nouveaux pilotes UMDF doivent être écrits à l’aide d’UMDF 2. Aucune nouvelle fonctionnalité n’est ajoutée à UMDF 1 et la prise en charge d’UMDF 1 est limitée sur les versions plus récentes de Windows 10. Les pilotes Windows universels doivent utiliser UMDF 2. Pour plus d’informations, consultez Prise en main avec UMDF.]
La méthode UnmarkCancelable désactive l’annulation d’une demande d’E/S.
Syntaxe
HRESULT UnmarkCancelable();
Valeur de retour
UnmarkCancelable retourne l’une des valeurs suivantes :
Code de retour | Description |
---|---|
|
UnmarkCancelable a désactivé l’utilisation de la méthode IRequestCallbackCancel ::OnCancel précédemment inscrite via un appel à la méthode IWDFIoRequest ::MarkCancelable . |
|
La demande est en cours d’annulation. |
Remarques
Un pilote peut appeler IWDFIoRequest ::UnmarkCancelable pour désactiver l’annulation d’une demande d’E/S, si le pilote a précédemment appelé IWDFIoRequest ::MarkCancelable pour permettre l’annulation de la demande.
Si le pilote a précédemment appelé MarkCancelable, il doit appeler UnmarkCancelable avant d’appeler IWDFIoRequest ::Complete en dehors d’un appel à sa méthode de rappel IRequestCallbackCancel ::OnCancel .
Toutefois, le pilote ne doit pas appeler UnmarkCancelable après l’appel d’OnCancelterminé.
Si UnmarkCancelable retourne HRESULT_FROM_WIN32(ERROR_OPERATION_ABORTED), puis si OnCancel termine la demande, le pilote ne doit pas utiliser l’objet request.
Si UnmarkCancelable retourne HRESULT_FROM_WIN32(ERROR_OPERATION_ABORTED), le pilote ne doit pas terminer la demande avant que l’infrastructure appelle OnCancel. Sinon, l’infrastructure peut appeler OnCancel du pilote avec une requête non valide.
Exemples
L’exemple de code suivant montre comment un pilote peut appeler IWDFIoRequest ::UnmarkCancelable avant d’appeler IWDFIoRequest ::Complete, en dehors d’un appel à sa méthode IRequestCallbackCancel ::OnCancel .
L’exemple montre également comment utiliser OnCancel pour accélérer l’exécution d’une demande. Dans ce cas, le rappel OnCancel ne termine pas/annule toujours la demande spécifiée.
//
// 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));
}
}
Dans l’exemple de code suivant, le pilote stocke les demandes d’E/S dans un objet de file d’attente implémenté par le pilote appelé MyQueue. L’interface MyQueue du pilote implémente certaines méthodes de base pour manipuler la file d’attente, telles que IsEmpty, RemoveHead, Cleanup, GetFirstNodePosition, GetAt et RemoveAt.
Le pilote définit également une structure CommandInformation qui contient une seule requête d’E/S de MyQueue.
La méthode MyQueue ::D eQueue supprime une demande d’E/S de la file d’attente, appelle UnmarkCancelable pour désactiver l’annulation de la demande, puis retourne la demande pour traitement.
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));
}
Consultez également l’exemple de code sur WdfRequestUnmarkCancelable. Bien qu’il soit écrit pour un pilote KMDF, cet exemple montre comment utiliser la synchronisation automatique de l’infrastructure pour gérer la synchronisation entre le rappel d’annulation et un autre thread qui appelle la routine Unmark .
Configuration requise
Condition requise | Valeur |
---|---|
Fin de la prise en charge | Non disponible dans UMDF 2.0 et versions ultérieures. |
Plateforme cible | Desktop (Expérience utilisateur) |
Version UMDF minimale | 1.5 |
En-tête | wudfddi.h (inclure Wudfddi.h) |
DLL | WUDFx.dll |