当WINAPI调用我的代码并抛出异常时,我应该捕获它并返回HRESULT吗



我已经实现了IThumbnailProvider,它被编译到dll中,然后使用regsvr32注册。

在代码中,我使用了STL容器,如std::vector:

std::vector<double> someRGBAccumulatorForDownsamplingToThumbnail = std::vector<double>(1234567);

因为STL容器在很大程度上是围绕RAII构建的,所以没有对失败的内存分配进行null检查。相反,上面的代码将在内存不足的情况下抛出一个异常。发生这种情况时,我是否应该捕获此异常以返回HRESULT(上下文:GetThumbnail的实现(?

try {
// ...
} catch (bad_alloc& ex) {
return E_OUTOFMEMORY;
}

或者WINAPI可以安全地处理我允许异常";冒泡";?

我之所以这么问,是因为我读到WINAPI是基于C的,而且C没有例外。

IThumbnailProvider是一个COM接口。组件对象模型是一个与语言无关的协议,它描述了客户端和接口实现者之间的二进制契约。它建立了一个具有明确规则的边界(应用程序二进制接口,ABI(1

由于协议与语言无关,因此允许跨越ABI的内容仅限于最小公分母。它最终比C函数所称的支持略低。任何特定于语言的构造(如C++异常(都不能跨越ABI。

在C++中实现COM接口时,必须确保C++异常永远不会跨越ABI。你能做的最起码的事情就是将所有接口方法标记为noexcept:

HRESULT MyThumbnailProvider::GetThumbnail(UINT, HBITMAP*, WTS_ALPHATYPE*) noexcept {
// ...
}

虽然这满足了COM协定的所有要求,但通常不希望出现未捕获的异常导致COM对象所在的整个进程中断。

更详细的解决方案是捕获所有异常并将其转换为HRESULT错误代码(请参阅COM中的错误处理(,类似于有问题的代码:

HRESULT MyThumbnailProvider::GetThumbnail(UINT, HBITMAP*, WTS_ALPHATYPE*) noexcept {
try {
// ...
} catch(...) {
return E_FAIL;
}
}

同样,这是完全有效的,尽管任何COM开发人员都害怕看到0x80004005错误代码,这在语义上等同于"出了问题">。在尝试诊断问题时几乎没有用处。

更有用的实现将尝试将某些众所周知的C++异常类型映射到标准HRESULT值(例如std::bad_alloc->E_OUTOFMEMORYstd::system_error到调用HRESULT_FROM_WIN32的结果(。虽然可以在每个接口方法实现上手动实现catch级联,但已经有库为您实现了。Windows实现库(WIL(为此提供了异常保护,将详细信息排除在代码之外。

以下是使用WIL的可能接口方法实现:

HRESULT MyThumbnailProvider::GetThumbnail(UINT, HBITMAP*, WTS_ALPHATYPE*) noexcept {
try {
// ...
}
CATCH_RETURN();
}

顺便说一句,我在后两个实现中保留了noexcept说明符,仅作为防御措施;它们不是严格要求的,但要保持接口的有效性,以防将来实现发生变化,从而允许C++异常逃逸。


1我不知道有官方文件阐明了这些规则。我们必须假设编译器就是规范。顺便说一句,微软的C和C++编译器并不同意,Direct2D团队发现了这一点

相关内容

  • 没有找到相关文章

最新更新