C++ の例外は、COM モジュールの境界を超えることはできません。
したがって、COM メソッド body にいて、潜在的にスローするC++メソッド/関数が呼び出されたとします (たとえば、STL クラスが使用されているため、これがスローされる可能性があります)。
STDMETHODIMP CSomeComServer::DoSomething()
{
CppDoSomething(); // <--- This may throw C++ exceptions
return S_OK;
}
Q1. 上記のコードは実行可能な実装ですか? たとえば、そのコードがコンテキスト メニューのシェル拡張機能の一部である場合、C++CppDoSomething()
関数が C++ 例外をスローすると、エクスプローラーはどうするでしょうか? C++ 例外をキャッチし、シェル拡張機能をアンロードしますか? フェイルファーストアプローチに従って、Explorer をクラッシュさせる (クラッシュ ダンプを使用して問題を分析できるようにする) だけですか?
Q2. このような実装はより良いでしょうか?
STDMETHODIMP CSomeComServer::DoSomething()
{
//
// Wrap the potentially-throwing C++ code call in a safe try/catch block.
// C++ exceptions are caught and transformed to HRESULTs.
//
try
{
CppDoSomething(); // <--- This may throw C++ exceptions
return S_OK;
}
//
// Map C++ std::bad_alloc exception to E_OUTOFMEMORY HRESULT.
//
catch(const std::bad_alloc& ex)
{
// ... Log the exception what() message somewhere,
// e.g. using OutputDebugString().
....
return E_OUTOFMEMORY;
}
//
// Map C++ std::exception exception to generic E_FAIL.
//
catch(const std::exception& ex)
{
// ... Log the exception what() message somewhere,
// e.g. using OutputDebugString().
....
return E_FAIL;
}
}
Q3. または、C++ 例外がスローされた場合は、内部フラグ (bool m_invalid
データ メンバーなど) を設定して、COM サーバーを動作不能な状態にするだけで、そのメソッドを連続して呼び出すたびに、E_FAIL
またはその他の特定のエラーのようなエラーコードを返しますか?
Q4. 最後に、Q2/Q3 が適切な実装ガイドラインであると仮定するとtry/catch
、いくつかの便利なプリプロセッサ マクロ (すべての COM メソッド本体で再利用できる) で冗長ガードを非表示にすることができます。
#define COM_EXCEPTION_GUARD_BEGIN try \
{
#define COM_EXCEPTION_GUARD_END return S_OK; \
} \
catch(const std::bad_alloc& ex) \
{ \
.... \
return E_OUTOFMEMORY; \
} \
catch(const std::exception& ex) \
{ \
.... \
return E_FAIL; \
}
//
// May also add other mappings, like std::invalid_argument --> E_INVALIDARG ...
//
STDMETHODIMP CSomeComServer::DoSomething()
{
COM_EXCEPTION_GUARD_BEGIN
CppDoSomething(); // <--- This may throw C++ exceptions
COM_EXCEPTION_GUARD_END
}
STDMETHODIMP CSomeComServer::DoSomethingElse()
{
COM_EXCEPTION_GUARD_BEGIN
CppDoSomethingElse(); // <--- This may throw C++ exceptions
COM_EXCEPTION_GUARD_END
}
最新の C++11/14 を使用して、前述のプリプロセッサ マクロを、より便利でエレガントな、より良いものに置き換えることは可能ですか?