如何在C++中调用COM时包装错误?

3
为了遵循典型的COM流程,每当出现任何错误时,必须执行以下操作:
  1. 使用FAILED或类似方法检查HRESULT,以查看是否发生了错误。
  2. 创建一个变量来保存IErrorInfo(通常为CComPtr<IErrorInfo>)。
  3. 调用::GetErrorInfo(0, &var)
  4. 通过调用IErrorInfo::GetDescription获得可读版本。
  5. BSTR转换为std::wstring
  6. std::wstring转换为某种形式的char const*
  7. 抛出用户定义的异常类型,该类型派生自std::exception,并公开上述位1、5和6。
所有这些都似乎是一堆样板代码,必须在COM中的几乎每个函数调用周围进行。
我知道MSVC++编译器提供了许多东西,使与COM的交互更加容易,例如ATL和编译器特定的COM扩展_com_error_com_raise_error等,但我不确定如何使用这些东西,或者它们是否甚至是用于用户代码的。
在异常安全和竞争条件安全的情况下,是否有任何典型策略用于管理此复杂性?

1
从 #import 指令开始,其余部分会自动落位。 - Hans Passant
1
那就别管它,你得自己包装它。只需编写一个CheckHR()函数即可。 - Hans Passant
1
@HansPassant:是的,我可以自己包装它,而不需要太多的努力;但如果已经有一种在使用大量COM的人中间半标准的方法来做到这一点,我想按照典型的方式来做,而不是发明新东西。 - Billy ONeal
@MSalters:你需要一个 const char* 来实现 std::exception::what - Billy ONeal
@AlexandreC:能否给我解释一下?也许我对COM的这个方面有所误解。 - Billy ONeal
显示剩余4条评论
2个回答

4
"显而易见"的解决方案是使用ComException。它可以处理几乎所有步骤 - 你只需要获取HRESULT用于构造函数并抛出结果对象(步骤1和7)。
甚至可以编写


HRESULT check(HRESULT hr)
{
  if(FAILED(hr)) throw ComException(hr);
  return hr; // Success comes in different forms. 
}

如果您希望让步骤7自动完成,可以使用以下代码: check(pUnk->QueryInterface(MyID, &pMyIf));


@AlexandreC.:这将发生在ComException::ComException(HRESULT)中。 - MSalters
ComException如何检索指向IErrorInfo的指针?你必须以某种方式将指向你首先调用函数的接口的指针传递给它,是吗? - Alexandre C.
@AlexandreC.:不是,那是通过::GetErrorInfo完成的。 - MSalters

1

恐怕没有半标准的方法可以为您提供,即使您查看 MSDN 上的示例应用程序和 API 用法,它们都会向您展示如何手动执行所有繁琐的 HResult 检查、检查 IPtr 是否有效等操作。您将不得不编写自己的函数来包装所有这些内容,以便您不会重复代码,这应该不是问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接