Ausnahmen (C++/CX)
Die Fehlerbehandlung in C++/CX basiert auf Ausnahmen. Auf der grundlegendsten Ebene melden Windows-Runtime Komponenten Fehler als HRESULT-Werte. In C++/CX werden diese Werte in stark typierte Ausnahmen konvertiert, die einen HRESULT-Wert und eine Zeichenfolgenbeschreibung enthalten, auf die Sie programmgesteuert zugreifen können. Ausnahmen werden als ref class
implementiert, die von Platform::Exception
abgeleitet ist. Der Namespace Platform
definiert verschiedene Ausnahmeklassen für die häufigsten HRESULT-Werte. Alle anderen Werte werden über die Klasse Platform::COMException
gemeldet. Alle Ausnahmeklassen haben ein Feld Exception::HResult , das Sie verwenden können, um den ursprünglichen HRESULT-Wert abzurufen. Sie können auch Aufrufstapelinformationen für Benutzercode im Debugger untersuchen, mit der die ursprüngliche Quelle der Ausnahme angeheftet werden kann, auch wenn sie aus Code stammt, der in einer anderen Sprache als C++ geschrieben wurde.
Ausnahmen
In Ihrem C++-Programm können Sie eine Ausnahme auslösen und abfangen, die aus einem Windows-Runtime-Vorgang, einer Ausnahme stammt, die von std::exception
einem benutzerdefinierten Typ abgeleitet ist. Sie müssen eine Windows-Runtime Ausnahme nur auslösen, wenn sie die Grenze der Binären Schnittstelle (Application Binary Interface, ABI) überschreitet, z. B. wenn der Code, der Ihre Ausnahme abfangen, in JavaScript geschrieben wird. Wenn eine nicht Windows-Runtime C++-Ausnahme die ABI-Grenze erreicht, wird die Ausnahme in eine Platform::FailureException
Ausnahme übersetzt, die ein E_FAIL HRESULT darstellt. Weitere Informationen zur ABI finden Sie unter Creating Windows Runtime Components in C++.
Sie können eine Platform::Exception deklarieren, indem Sie einen von zwei Konstruktoren verwenden, die entweder einen HRESULT-Parameter oder einen HRESULT-Parameter und einen Platform::String^-Parameter verwenden, der über die ABI an jede Windows-Runtime App übergeben werden kann, die sie behandelt. Alternativ dazu können Sie eine Ausnahme deklarieren, indem Sie eine von zwei Exception::CreateException -Methodenüberladungen verwenden, die entweder einen HRESULT-Parameter oder einen HRESULT-Parameter und einen Platform::String^
-Parameter akzeptieren.
Standardausnahmen
C++/CX unterstützt eine Reihe von Standard exceptions, die typische HRESULT-Fehler darstellen. Jede Standardausnahme wird von Platform::COMExceptionabgeleitet, die wiederum von Platform::Exception
abgeleitet wird. Wenn Sie eine Ausnahme über die ABI-Grenze hinweg auslösen, müssen Sie eine der Standardausnahmen auslösen.
Sie können keinen eigenen Ausnahmetyp von Platform::Exception
ableiten. Verwenden Sie zum Auslösen einer benutzerdefinierten Ausnahme ein benutzerdefiniertes HRESULT, um ein COMException
-Objekt zu erstellen.
In der folgenden Tabelle sind die Standardausnahmen aufgelistet.
Name | Zugrunde liegendes HRESULT | Beschreibung |
---|---|---|
COMException | Benutzerdefiniertes HRESULT | Wird ausgelöst, wenn ein COM-Methodenaufruf ein unbekanntes HRESULT zurückgibt. |
AccessDeniedException | E_ACCESSDENIED | Wird ausgelöst, wenn der Zugriff auf eine Ressource oder eine Funktion verweigert wird. |
ChangedStateException | E_CHANGED_STATE | Wird ausgelöst, wenn Methoden eines Auflistungsiterators oder einer Auflistungsansicht aufgerufen werden, nachdem die übergeordnete Auflistung geändert wurde, wodurch die Ergebnisse der Methode ungültig wurden. |
ClassNotRegisteredException | REGDB_E_CLASSNOTREG | Wird ausgelöst, wenn eine COM-Klasse nicht registriert wurde. |
DisconnectedException | RPC_E_DISCONNECTED | Wird ausgelöst, wenn ein Objekt von den Clients getrennt wurde. |
FailureException | E_FAIL | Wird ausgelöst, wenn ein Vorgang fehlschlägt. |
InvalidArgumentException | E_INVALIDARG | Wird ausgelöst, wenn eines der Argumente für eine Methode ungültig ist. |
InvalidCastException | E_NOINTERFACE | Wird ausgelöst, wenn ein Typ nicht in einen anderen Typ umgewandelt werden kann. |
NotImplementedException | E_NOTIMPL | Wird ausgelöst, wenn eine Schnittstellenmethode nicht bei der Klasse implementiert wurde. |
NullReferenceException | E_POINTER | Wird ausgelöst, wenn der Versuch gemacht wird, einen Verweis auf ein NULL-Objekt zu dereferenzieren. |
ObjectDisposedException | RO_E_CLOSED | Wird ausgelöst, wenn ein Vorgang für ein verworfenes Objekt ausgeführt wird. |
OperationCanceledException | E_ABORT | Wird nach dem Abbrechen eines Vorgangs ausgelöst. |
OutOfBoundsException | E_BOUNDS | Wird ausgelöst, wenn ein Vorgang versucht, auf Daten außerhalb des gültigen Bereichs zuzugreifen. |
OutOfMemoryException | E_OUTOFMEMORY | Wird ausgelöst, wenn nicht genügend Arbeitsspeicher vorhanden ist, um den Vorgang abzuschließen. |
WrongThreadException | RPC_E_WRONG_THREAD | Wird ausgelöst, wenn ein Thread über einen Schnittstellenzeiger aufruft, der für ein Proxyobjekt ist, das nicht zum Apartment des Threads gehört. |
HResult- und Meldungseigenschaften
Alle Ausnahmen verfügen über eine -HResult -Eigenschaft und eine -Meldungseigenschaft . Die Exception::HResult -Eigenschaft ruft den der Ausnahme zugrunde liegenden numerischen HRESULT-Wert ab. Die Exception::Message -Eigenschaft ruft die vom System bereitgestellte Zeichenfolge ab, die die Ausnahme beschreibt. In Windows 8 ist die Nachricht nur im Debugger verfügbar und schreibgeschützt. Dies bedeutet, dass Sie sie nicht ändern können, wenn Sie die Ausnahme erneut auslösen. In Windows 8.1 können Sie auf die Meldungszeichenfolge programmgesteuert zugreifen und eine neue Nachricht bereitstellen, wenn Sie die Ausnahme erneut auslösen. Bessere Aufruflisteninformationen einschließlich Aufruflisten für asynchrone Methodenaufrufe sind auch im Debugger verfügbar.
Beispiele
In diesem Beispiel wird gezeigt, wie eine Windows-Runtime Ausnahme für synchrone Vorgänge ausgelöst wird:
String^ Class1::MyMethod(String^ argument)
{
if (argument->Length() == 0)
{
auto e = ref new Exception(-1, "I'm Zork bringing you this message from across the ABI.");
//throw ref new InvalidArgumentException();
throw e;
}
return MyMethodInternal(argument);
}
Im nächsten Beispiel wird gezeigt, wie die Ausnahme abgefangen wird.
void Class2::ProcessString(String^ input)
{
String^ result = nullptr;
auto obj = ref new Class1();
try
{
result = obj->MyMethod(input);
}
catch (/*InvalidArgument*/Exception^ e)
{
// Handle the exception in a way that's appropriate
// for your particular scenario. Assume
// here that this string enables graceful
// recover-and-continue. Why not?
result = ref new String(L"forty two");
// You can use Exception data for logging purposes.
Windows::Globalization::Calendar calendar;
LogMyErrors(calendar.GetDateTime(), e->HResult, e->Message);
}
// Execution continues here in both cases.
//#include <string>
std::wstring ws(result->Data());
//...
}
Um Ausnahmen abzufangen, die während eines asynchronen Vorgangs ausgelöst werden, verwenden Sie die Aufgabenklasse, und fügen Sie eine Fortsetzung der Fehlerbehandlung hinzu. Die Fehlerbehandlungsfortsetzung marshallt Ausnahmen, die für andere Threads ausgelöst und zurück an den aufrufenden Thread gegeben werden, damit Sie alle potenziellen Ausnahmen an nur einem Punkt im Code behandeln können. Weitere Informationen finden Sie unter Asynchrone Programmierung in C++.
UnhandledErrorDetected-Ereignis
In Windows 8.1 können Sie das statische Ereignis "Windows::ApplicationModel::Core::CoreApplication::UnhandledErrorDetected" abonnieren, das Zugriff auf unbehandelte Fehler ermöglicht, die den Prozess heruntersetzen. Unabhängig davon, wodurch der Fehler verursacht wurde, erreicht er diesen Handler als Windows::ApplicationModel::Core::UnhandledError -Objekt, das mit den Ereignisargumenten übergeben wird. Wenn Sie Propagate
für das Objekt aufrufen, wird eine Platform::*Exception
des Typs, der dem Fehlercode entspricht, erstellt und ausgelöst. In catch-Blöcken können Sie bei Bedarf den Benutzerzustand speichern und dann zulassen, dass der Prozess beendet wird, indem Sie throw
aufrufen. Sie können auch etwas unternehmen, um das Programm in einen bekannten Zustand zurückzuführen. Das grundlegende Muster wird im folgenden Beispiel veranschaulicht:
In "app.xaml.h":
void OnUnhandledException(Platform::Object^ sender, Windows::ApplicationModel::Core::UnhandledErrorDetectedEventArgs^ e);
In app.xaml.cpp:
// Subscribe to the event, for example in the app class constructor:
Windows::ApplicationModel::Core::CoreApplication::UnhandledErrorDetected += ref new EventHandler<UnhandledErrorDetectedEventArgs^>(this, &App::OnUnhandledException);
// Event handler implementation:
void App::OnUnhandledException(Platform::Object^ sender, Windows::ApplicationModel::Core::UnhandledErrorDetectedEventArgs^ e)
{
auto err = e->UnhandledError;
if (!err->Handled) //Propagate has not been called on it yet.
{
try
{
err->Propagate();
}
// Catch any specific exception types if you know how to handle them
catch (AccessDeniedException^ ex)
{
// TODO: Log error and either take action to recover
// or else re-throw exception to continue fail-fast
}
}
Hinweise
C++/CX verwendet die finally
Klausel nicht.