COM中的错误代码礼仪

COM中的错误代码礼仪,com,Com,在COM对象中,通常有两种方式指示函数失败(我知道): 返回S\u OK并使用[out]参数提供故障信息 返回故障HRESULT,并使用icreaterrorInfo设置信息 目前,我正在使用failure-HRESULT方法处理“非常糟糕”的故障,也就是说,由于此功能失败,我的对象基本上无法运行。例如,无法打开其配置文件 这是正确的,还是应该只为分派参数类型不匹配等情况保留失败HRESULT?简短版本: 在COM中,对于大多数/所有类型的错误情况,您应该使用HRESULTs(并努力使用IS

在COM对象中,通常有两种方式指示函数失败(我知道):

  • 返回
    S\u OK
    并使用
    [out]
    参数提供故障信息
  • 返回故障
    HRESULT
    ,并使用
    icreaterrorInfo
    设置信息
目前,我正在使用failure-
HRESULT
方法处理“非常糟糕”的故障,也就是说,由于此功能失败,我的对象基本上无法运行。例如,无法打开其配置文件

这是正确的,还是应该只为分派参数类型不匹配等情况保留失败HRESULT?

简短版本:

在COM中,对于大多数/所有类型的错误情况,您应该使用
HRESULT
s(并努力使用
ISupportErrorInfo
等)。
HRESULT
机制应视为异常抛出的一种形式。如果您熟悉这一点,可以将“错误条件”视为通常会在支持它们的语言中抛出异常的任何东西。对于通常不会使用异常的内容,请使用自定义返回值

例如,对无效参数、无效操作序列、网络故障、数据库错误、意外情况(如内存不足等)使用故障HRESULT。另一方面,对“轮询、数据尚未准备就绪”、EOF条件,可能是“已检查数据且未通过验证”等情况使用自定义输出参数。有很多讨论都在讨论每一个应该是什么(例如Stroustrup)。具体细节在很大程度上取决于特定对象的语义

较长版本:

从根本上讲,COM HRESULT机制只是一种错误代码机制,已被基础结构标准化。这主要是因为COM必须支持许多功能,如进程间(DCOM)和线程间(单元)执行、系统管理服务(COM+)等。基础结构需要知道什么时候出现了故障,并且需要向双方传达与基础结构相关的错误。每个人都需要就如何传达错误达成一致

每种语言和程序员都可以选择如何显示或处理这些错误。在C++中,我们通常将HEST作为错误代码处理(尽管如果您喜欢这样的错误处理,可以将它们转换为异常)。在.NET语言中,失败HRESULT被转换为异常,因为这是.NET中首选的错误机制

VB6支持“任意”。现在,我知道VB6所谓的异常处理有一个痛苦的语法和有限的处理程序范围选项,但如果您不想使用它,就不必使用它。如果您认为使用模式在特定情况下是合理的,则始终可以在错误恢复下使用
,并手动执行。只是没有写这样的东西:

statusCode = obj.DoSomething(param1)
If IS_FAILURE(statusCode) Then
    'handle error
End If
ON ERROR RESUME NEXT
...
obj.DoSomething param1
IF Error.Number <> 0 Then
    'handle error
End If
你可以这样写:

statusCode = obj.DoSomething(param1)
If IS_FAILURE(statusCode) Then
    'handle error
End If
ON ERROR RESUME NEXT
...
obj.DoSomething param1
IF Error.Number <> 0 Then
    'handle error
End If
出错时继续下一步
...
目标剂量测量参数1
如果出现错误,则为0
'处理错误
如果结束
VB6只是对方法调用隐藏错误代码返回值(并允许对象的程序员通过
[retval]
将其替换为“虚拟返回值”)

如果您建立自己的错误报告机制而不是使用
HRESULT
s,您将:

  • 花大量时间重新发明丰富的错误报告机制,该机制可能会反映ISupportsErrorInfo已经提供给您的信息(或者很可能不提供任何丰富的错误信息)
  • 从COM的基础结构中隐藏错误状态(这可能很重要,也可能无关紧要)
  • 强制您的VB6客户端在两个选项中做出一个特定的选择:它们必须执行显式逐行检查,或者更可能只是错误地忽略错误条件,即使它们更喜欢错误处理程序
  • 强制(比如)C#客户端以与语言自然风格相反的方式处理错误(必须显式检查每个方法调用,并且……可能手动抛出异常)

  • 最低级别的COM标准是返回HRESULT,不带out参数,不带ICREATERRORRINFO。ICreateErrorInfo与自动化更相关:因此它实际上取决于您的客户机/调用方是什么,或者是否有很多客户机,是否希望正确地支持它们。例如,一个客户端是VB6,如果我返回一个不正常的HRESULT而没有设置ErrorInfo,它会弹出一个显示“Method”~'of“~'failed”,这不是很有用-但是如果我设置了ErrorInfo,它会显示该信息。VB6是一个自动化客户端,所以是的,最好使用第二个选项。如果你在谷歌上搜索“icreaterrorinfo.net”,你会发现安德鲁·特罗尔森(Andrew Troelsen)的《COM和.net互操作性》(COM and.net Interoperability)一书第456和460页详细介绍了这一点。所有的COM书籍都是旧书IMHO:我已经使用了“专业DCOM编程”(不仅仅用于DCOM…)、“必要COM”、“专业ATL COM编程”、“ATL内部设备”(ATL是C++必须的,但是这些ATL图书可能因为ATL已经发展而过时),以及“.NET和COM:完全互操作指南”。对于使用NET的COM。您说您仅对灾难性故障使用故障HRESULT。你应该把它们用于大多数形式的失败,而不仅仅是关键的失败。谢谢,这是一篇很棒的文章,也是我一直在寻找的。