C++ 异常不能跨越 COM 模块边界。
所以,假设我们在一个 COM 方法体中,并且调用了一些 C++可能抛出的方法/函数(这可能会抛出,因为例如使用了 STL 类):
STDMETHODIMP CSomeComServer::DoSomething()
{
CppDoSomething(); // <--- This may throw C++ exceptions
return S_OK;
}
Q1。上面的代码是一个可行的实现吗?例如,如果该代码是上下文菜单外壳扩展的一部分,如果 C++CppDoSomething()
函数抛出 C++ 异常,Explorer 会做什么?它是否捕获 C++ 异常并卸载 shell 扩展?它是否只是按照快速失败的方法使 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,是否可以用其他更方便、更优雅、更好的东西替换上述预处理器宏?