例外 (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 オブジェクトを構築します。

次の表は、標準の例外の一覧を示しています。

名前 基になる 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 句を使用しません。

関連項目

C++/CX 言語リファレンス
名前空間参照