例外 (C++/CX)
C++/CX のエラー処理は、例外に基づいています。 上位の基本 Windows ランタイム コンポーネントは、HRESULT 値としてエラーを報告します。 C++/CX では、これらの値はプログラムでアクセスできる HRESULT 値、および文字列による説明を含む厳密に型指定された例外に変換されます。 例外は、 ref class
から派生した Platform::Exception
として実装されます。 Platform
名前空間は、ほとんどの共通 HRESULT 値のために異なる例外クラスを定義します。それ以外のすべての値は、 Platform::COMException
クラスで報告されます。 すべての例外クラスには、元の HRESULT を取得するために使用できる Exception::HResult フィールドがあります。 C++ 以外の言語で作成されたコードで例外が発生した場合でも、例外の元の発生場所を正確に突き止めるのに役立つ、ユーザー コードに関するコール スタック情報をデバッガー内で確認することもできます。
例外
C++ プログラムでは、Windows ランタイム操作から派生した例外、std::exception
から派生した派生、またはユーザー定義型をスローおよびキャッチできます。 Windows ランタイム例外をスローする必要があるのは、例外をキャッチするコードが JavaScript で記述されている場合など、例外がアプリケーション バイナリ インターフェイス (ABI) の境界を越える場合のみです。 Windows ランタイムではない C++ 例外が ABI 境界に達すると、例外は、E_FAIL HRESULT を表す Platform::FailureException
例外に変換されます。 ABI の詳細については、「 Creating Windows Runtime Components in C++」を参照してください。
1 つの HRESULT パラメーターを受け取るコンストラクター、または 1 つの HRESULT パラメーターと、処理を行う Windows ランタイム アプリに ABI を通じて渡すことができる 1 つの Platform::String ^ パラメーターを受け取るコンストラクターのいずれかを使用して、 Platform::Exceptionを宣言することができます。 または、1 つの HRESULT パラメーター、または 1 つの HRESULT パラメーターと パラメーターのいずれかを受け取る 2 つの Exception::CreateException メソッド Platform::String^
オーバーロードの 1 つを使用して、例外を宣言できます。
標準の例外
C++/CX は、一般的な HRESULT エラーを表す標準の例外をサポートしています。 この標準例外は Platform::COMExceptionから派生し、その例外は Platform::Exception
から派生します。 ABI の境界を越えて例外をスローするときは、標準の例外の 1 つをスローする必要があります。
Platform::Exception
から独自の例外の種類を派生させることはできません。 カスタム例外をスローするには、ユーザー定義の HRESULT を使用して COMException
オブジェクトを構築します。
次の表は、標準の例外の一覧を示しています。
Name | 基になる HRESULT | 説明 |
---|---|---|
COMException | ユーザー定義の hresult | COM メソッドの呼び出しから認識されない HRESULT が返されるとスローされます。 |
AccessDeniedException | E_ACCESSDENIED | リソースや機能へのアクセスが拒否されるとスローされます。 |
ChangedStateException | E_CHANGED_STATE | コレクション反復子またはコレクション ビューのメソッドが、親コレクションの変更後に呼び出さたときにスローされます。これにより、メソッドの結果は無効になります。 |
ClassNotRegisteredException | REGDB_E_CLASSNOTREG | COM クラスが登録されていないときにスローされます。 |
DisconnectedException | RPC_E_DISCONNECTED | オブジェクトがクライアントから接続を切断されるとスローされます。 |
FailureException | E_FAIL | 操作が失敗したときにスローされます。 |
InvalidArgumentException | E_INVALIDARG | メソッドに提供された引数のいずれかが有効でない場合にスローされます。 |
InvalidCastException | E_NOINTERFACE | 型が別の型にキャストできないときにスローされます。 |
NotImplementedException | E_NOTIMPL | インターフェイス メソッドがクラスに実装されていないときにスローされます。 |
NullReferenceException | E_POINTER | null オブジェクト参照を逆参照しようするとスローされます。 |
ObjectDisposedException | RO_E_CLOSED | 破棄されたオブジェクトで操作が実行されるとスローされます。 |
OperationCanceledException | E_ABORT | 操作が中止されるとスローされます。 |
OutOfBoundsException | E_BOUNDS | 操作が有効範囲外のデータにアクセスを試みるとスローされます。 |
OutOfMemoryException | E_OUTOFMEMORY | メモリが不足して操作を完了できないときにスローされます。 |
WrongThreadException | RPC_E_WRONG_THREAD | スレッドが、スレッドのアパートメントに属さないプロキシ オブジェクト用のインターフェイス ポインターを通じて呼び出すときにスローされます。 |
HResult および Message プロパティ
すべての例外に、 HResult プロパティと Message プロパティがあります。 Exception::HResult プロパティは、例外の基になる数値 HRESULT 値を取得します。 Exception::Message プロパティは、例外を記述するシステム指定文字列を取得します。 Windows 8 では、メッセージはデバッガーでのみ使用でき、また読み取り専用です。 これは、例外を再スローするときに、例外を変更できないことを意味します。 Windows 8.1 では、例外を再スローする場合に、プログラムでメッセージの文字列にアクセスし、新しいメッセージを提供することができます。 非同期メソッド呼び出しに関する呼び出し履歴を含め、より詳細な呼び出し履歴情報もデバッガーで使用できます。
例
この例は、同期操作の Windows ランタイム例外をスローする方法を示しています。
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);
}
次の例は、例外をキャッチする方法を示しています。
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());
//...
}
非同期操作中にスローされた例外をキャッチするには、タスク クラスを使用し、エラー処理の継続を追加します。 エラー処理コードの継続は、他のスレッドでスローされる例外を呼び出し元のスレッドにマーシャリングして、発生する可能性があるすべての例外をコード中の 1 つのポイントで処理できるようにします。 詳しくは、「 C++ での非同期プログラミング」を参照してください。
UnhandledErrorDetected イベント
Windows 8.1 では、静的イベント Windows::ApplicationModel::Core::CoreApplication::UnhandledErrorDetected にサブスクライブできます。このイベントは、プロセスをダウンさせようとしている未処理のエラーへのアクセスを提供します。 エラーがどこで発生したかにかかわりなく、イベントの引数によって渡される Windows::ApplicationModel::Core::UnhandledError オブジェクトという形で、このハンドラーに到達します。 オブジェクトに対して Propagate
を呼び出した場合、エラー コードに対応する型の Platform::*Exception
が生成され、スローされます。 catch ブロックで、必要に応じて、ユーザー状態を保存することができ、その後、プロセスが throw
を呼び出して終了すること、またはプログラムを既知の状態に戻すために他の作業を実行することを許可できます。 次の例に、基本的なパターンを示します。
app.xaml.h 内で:
void OnUnhandledException(Platform::Object^ sender, Windows::ApplicationModel::Core::UnhandledErrorDetectedEventArgs^ e);
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
}
}
解説
C++/CX は、finally
句を使用しません。