如何通过COM公开使用结构化异常处理捕获的异常?

5

我的Visual C++实现的COM服务器使用了很多其他C++代码。那些C++代码有时会用__try-__except将代码包装起来,并将结构化异常转换为自定义的C++异常。我无法更改这一部分。

我的COM服务器的任何方法都不应该让这些异常传播到COM边界,因此它必须捕获并将它们转换为HRESULT。那些自定义的C++异常包含了在翻译过程中获得的原始错误代码 - 它像 EXCEPTION_ACCESS_VIOLATION 这样。问题是如何制定一个适当的HRESULT值,以便客户端尽可能地了解发生了什么(并且可以在看到访问冲突后决定重新启动服务器(和inproc的情况下重新启动自己))。

假设它是WinBase.h中定义的EXCEPTION_ACCESS_VIOLATION

#define EXCEPTION_ACCESS_VIOLATION STATUS_ACCESS_VIOLATION

后者在WinNT.h中被定义。

#define STATUS_ACCESS_VIOLATION ((DWORD)0xC0000005L)

如果它最初是Win32错误,那么我可以使用HRESULT_FROM_WIN32()将该代码转换为HRESULT

我是否应在此处使用HRESULT_FROM_WIN32(),还是使用其他方式进行翻译?


也许在这里使用“ IErrorInfo”基础设施会很方便。 “_com_error”保存了指向它的指针。在被调用方面,我记得有类似于SetErrorInfo的东西...当时我使用了ATL... 咳嗽是10年前吗? - BitTickler
即使使用 IErrorInfo,我仍然需要负责构建 HRESULT 值。 - sharptooth
HRESULT_FROM_NT() 对于这个值更合适,不是吗?假设异常代码==NT状态代码,无论如何... - andlabs
@user2225104 好的,你看到它“失败”了。你会怎么做?也许你会抛出一个异常,这个异常会冒泡到某个合理的层面,那个层面必须“做些什么”。那个层面可能很容易想要不同地处理不同的HRESULT。 - sharptooth
2
@sharptooth 或者另一种解释我的观点:如果作为调用该C++代码的函数的实现者,您不知道如何处理那个结构化异常,那么调用者更有可能也不知道。对于所有重要的事情,他甚至不知道/关心您是否使用该C++代码进行实现。在直接调用者之上的人会更加不关心。随着您向上移动调用树,您也应该提高错误抽象水平。然后,他们在更高级别上需要的唯一信息是“我的功能/功能失败了,原因是COM对象xy”。 - BitTickler
显示剩余4条评论
1个回答

4
你需要返回HRESULT代码,选择适当的代码来指示操作的状态。它不一定是一个失败代码,但通常你想显示一些满足FAILED(...)宏的东西,例如E_FAIL,或DISP_E_EXCEPTIONHRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION)
调用者极少会比较具体的异常相关HRESULT,因此具体的失败代码更适合用于诊断。此外,在从COM方法退出之前完成处理异常,因此没有必要返回特定的HRESULT代码,因为不需要任何其他操作。
为了提供附加信息,可以使用ISupportErrorInfoIErrorInfo和friends。调用者可以检索自由文本描述和许多流行环境中的这个自动信息,因此例如.NET调用者将在异常消息上获得此附加信息,而不是从HRESULT代码生成的标准消息。

ATL提供AtlReportError来包装SetErrorInfo API,该API还建议生成HRESULT代码:

...如果hRes为零,则前四个版本的AtlReportError返回DISP_E_EXCEPTION。后两个版本返回宏MAKE_HRESULT(1, FACILITY_ITF, nID)的结果。


我认为OP不确定接口传递的HRESULT是否应该代表根本原因。也许你可以强调,通常没有必要在接口边界上携带特定的信息。你的前两段已经说明了这一点,但明确地表述可能会有所帮助。 - IInspectable
1
@IInspectable 对于调用者来说,根本原因可能非常重要 - 如果有结构化异常,服务器可能会崩溃,客户端最好重新启动服务器(如果它是进程内服务器,则还需重新启动自身)。 - sharptooth
@IInspectable:在这里,传递异常并没有什么不确定性。而是关于使用COM策略返回标准内容的问题。然而,COM只强制处理异常并返回HRESULT代码,因此将客户端/服务器定义为指示致命错误的特定代码。 - Roman R.
1
@sharptooth:通常,对调用者感兴趣的唯一信息是操作是否成功,这由HRESULT的最高有效位表示。根本原因对于调用者来说并不重要。然而,对于支持工程师来说,这是有帮助的。处理此问题的一种方法是在异常处理程序中编写minidump(用于诊断),并向调用者传递某些失败代码。 - IInspectable

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