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. Es werden keine neuen Features zu UMDF 1 hinzugefügt, und es gibt eingeschränkte Unterstützung für UMDF 1 für neuere Versionen von Windows 10. 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 |
---|---|
|
UnmarkCancelable deaktivierte Verwendung der IRequestCallbackCancel::OnCancel-Methode, die zuvor über einen Aufruf der IWDFIoRequest::MarkCancelable-Methode registriert wurde. |
|
Die Anforderung wird zurzeit abgebrochen. |
Bemerkungen
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 MarkCancelableaufgerufen hat, muss der Treiber UnmarkCancelable aufrufen, bevor IWDFIoRequest::Complete außerhalb eines Aufrufs an seine IRequestCallbackCancel::OnCancel Callback-Methode aufgerufen wird.
Der Treiber darf jedoch nicht UnmarkCancelable aufrufen, nachdem OnCancel Aufrufe Completeaufgerufen wurde.
Wenn UnmarkCancelable HRESULT_FROM_WIN32(ERROR_OPERATION_ABORTED) zurückgibt, und OnCancel die Anforderung abschließt, darf der Treiber das Anforderungsobjekt nicht später verwenden.
Wenn UnmarkCancelable HRESULT_FROM_WIN32(ERROR_OPERATION_ABORTED) zurückgibt, darf der Treiber die Anforderung nicht abschließen, bevor das Framework OnCancelaufruft. Andernfalls ruft das Framework die OnCancel des Treibers mit einer ungültigen Anforderung auf.
Beispiele
Im folgenden Codebeispiel wird veranschaulicht, wie ein Treiber IWDFIoRequest::UnmarkCancelable aufrufen kann, bevor IWDFIoRequest::Completeaußerhalb eines Aufrufs an die IRequestCallbackCancel::OnCancel-Methode aufgerufen wird.
Das Beispiel zeigt auch, wie Sie OnCancel- verwenden können, um den Abschluss einer Anforderung zu beschleunigen. In diesem Fall schließt der OnCancel Rückruf die angegebene Anforderung nicht immer ab.
//
// 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, GetAtund RemoveAt.
Der Treiber definiert auch eine CommandInformation- Struktur, die eine einzelne E/A-Anforderung von MyQueueenthä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));
}
Siehe auch das Codebeispiel für WdfRequestUnmarkCancelable. In diesem Beispiel wird gezeigt, wie Sie die automatischen Synchronisierung des Frameworks verwenden können, um die Synchronisierung zwischen dem Abbruchrückruf und einem anderen Thread zu verwalten, der die Unmark Routine aufruft.
Anforderungen
Anforderung | Wert |
---|---|
Ende des Supports | In UMDF 2.0 und höher nicht verfügbar. |
Zielplattform- | Desktop |
Mindest-UMDF-Version | 1.5 |
Header- | wudfddi.h (include Wudfddi.h) |
DLL- | WUDFx.dll |