【问题标题】:How to throw an std::system_error exception from a FAILED(HRESULT)?如何从 FAILED(HRESULT) 抛出 std::system_error 异常?
【发布时间】:2018-05-20 21:36:26
【问题描述】:

这是how to throw普通的Win32错误正确,自动检索错误描述,效果非常好:

if (!SomeWinFunc()) {
  throw std::system_error(GetLastError(),
    std::system_category(),
    "SomeWinFunc crashed badly");
}

但是,我不确定如何处理 COM 错误,检查 idiomatically 如下:

HRESULT hr = comObj->SomeFunc();
if (FAILED(hr)) {
  throw std::system_error(hr, // <-- is it correct here?
    std::system_category(),
    "SomeFunc crashed right now");
}

将HRESULT 传递给system_error 是否正确,或者还有其他方法可以从COM 函数中引发异常?

【问题讨论】:

  • 你有什么收获吗?
  • @MichaelGunter,我仍然没有实现 100% 正确的解决方案(可能从您的代码开始),但由于我的需求只是处理系统 COM 对象,所以我在问题中写的方法只是工作,我跑了几个测试。我计划一有时间就深入研究。

标签: c++ winapi exception com throw


【解决方案1】:

通常,我使用 Microsoft 标准 _com_error 异常类型来处理此问题,该异常类型可以通过以下方法之一轻松引发。

_com_util::CheckError(hr); // throws when FAILED(hr)
_com_issue_error(hr); // throws always

可以像这样将 Win32 错误转换为 HRESULT:

hr = HRESULT_FROM_WIN32(GetLastError());

但是,这意味着您必须处理新的异常类型,这可能会出现问题。要以纯 STL 方式执行此操作,我认为您需要派生一个新的 error_category 并使用它而不是 system_category。我会查看&lt;system_error&gt; 标头并复制system_category 的实现,并根据需要更新HRESULTs。

理想情况下,HRESULT 中的不同facility codes 将由不同的error_category 实现提供服务——这样做可以非常有效地传达异常及其来源。但这很棘手,您可能可以使用一个通常处理 HRESULTs 的 com_category 逃脱。

【讨论】:

  • 请务必注意,当使用std::system_category 作为上下文时,您不得传递HRESULT。该类别适用于GetLastError 返回的错误代码。例如,如果您传递 COM 成功代码 S_FALSE,它将被解释为 ERROR_INVALID_FUNCTION。有关如何实现自定义 error_category 的信息,请访问 System error support in C++0x - part 4。
  • @IInspectable S_FALSE 不是一个很好的例子,因为它不是错误代码。所以没有理由扔掉它。 HRESULT 可以表示的 error 值不会与 GetLastError 返回的错误代码重叠,因为 HRESULT 错误总是负数。所以在我看来,HRESULT 的特殊类别不是必需的,只要你只抛出 FAILED(hr)==true 的值。
  • @zett42:这取决于您的代码逻辑。成功的 COM 调用会产生一个条件,您无法从中恢复,需要抛出。即使不是这种情况,您仍然需要自定义错误类别来生成错误消息。虽然FormatMessage 可以与系统定义的HRESULT 值一起使用,但在处理客户定义的代码时情况会有所不同。您需要其他信息才能将它们转换为错误消息,即模块句柄。这需要在类别中进行编码,因为您无法在错误代码旁边传递其他信息。
  • 找到另一个为HRESULT 创建专用error_category 的理由:能够以通用方式检查错误代码。例如。以下不起作用:std::error_code e(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), std::system_category()); if(e == std::errc::no_such_file_or_directory){/*do something*/}。这可以通过在派生类中覆盖 std::error_category::default_error_condition() 来解决。
猜你喜欢
  • 2018-06-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-03
  • 2010-09-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多