如何从ATL activex控件向VB6返回错误字符串和错误代码?

时间:2009-07-01 14:51:58

标签: com vb6 error-handling activex atl

我正在尝试使用CComCoClass::Error向VB6返回详细错误,但似乎我只能返回错误代码/或/消息 - 但不能同时返回两者。

return Error(_T("Not connected"), __uuidof(IMyInterface), HRESULT_FROM_WIN32(ERROR_CONNECTION_INVALID));

导致VB6端的Err.Description中的对象'IMyInterface'失败的通用“方法'请求'失败”错误消息(但Err.Number中的ERROR_CONNECTION_INVALID),而

return Error(_T("Not connected"));

会产生相应的错误消息,但Err.Number中会出现一般错误代码。我如何才能充分利用这两个世界?

4 个答案:

答案 0 :(得分:5)

你不能,这似乎是设计的。详情如下,但简而言之,您有三种选择:

  • 根据此KB article,VB运行时返回没有消息和VB友好的COM错误,即一个众所周知的; VB运行时会将此“COM错误”转换为VB错误加消息。
  • 返回错误消息和DISP_E_EXCEPTION; VB运行时将通过此“服务器错误”和您的自定义错误消息。这就是您的第二个示例中隐含的内容,请参阅下面的详细信息。
  • 不返回任何消息和任何其他COM错误,即VB运行时未知; VB运行时将使用原始HRESULT加上通用消息“Method '~' of object '~' failed”。
    • 请注意,如果您在此处提供错误消息,此运行时行为也适用,即您的消息将被忽略!这就是您的第一个示例,请参阅下面的详细信息。

对于手头的任务,归结为两种选择:

  • 如果您想为自动化客户端(如VB)提供上下文正确的“COM错误”,则必须省略自定义错误消息。
  • 如果要为“服务器错误”提供自定义错误消息(即关于自动化服务器中的功能的自定义错误条件),您唯一的选择是DISP_E_EXCEPTION。

详细信息

VB运行时似乎只提供有关COM错误的非常有限的处理。这可能是出于VB实现方式的特定历史和/或技术原因,而不是特别感兴趣的(关键字只有IDispatch vs双接口,ActiveX作为COM的'子集')。

虽然我无法针对上述行为制定明确的规范,但可以通过挖掘其他来源来解决这个问题:

来自KB article justadreamer pointed out already

  

[...]打电话给   GetErrorInfo方法来检索   可用的错误信息。该   然后运行时确定是否   bstrDescription的值不是   空值。如果运行时找到值   除了NULL,[...],原始HRESULT   值在此方案中使用。如果   运行时发现一个NULL值,[...]   然后Visual Basic使用HRESULT   查找相应的Visual   基本错误。

这解释了有关您的第一个示例的行为:您确实提供了错误消息,因此运行时只需转到其通用消息“Method '~' of object '~' failed”加上您的HRESULT

在查看CComCoClass::Error的(第一个列出的)构造函数的定义后,第二个示例的行为也是一致的:它具有非指定参数的默认值,尤其是'hRes = 0'。 “备注”部分进一步指出“如果hRes为零,那么Error的前四个版本将返回DISP_E_EXCEPTION。”。因此,这隐含地触发了“服务器错误”传递行为。

最后,对于像自动化客户端行为这样的VB的具体C ++实现示例,请参阅Automating Microsoft Office 97 and Microsoft Office 2000中的段落“错误处理”和以下“练习5”。

答案 1 :(得分:0)

从ISupportErrorInfoImpl派生实现COM暴露接口的类,调用SetErrorInfo以设置错误的详细说明(如果有)。不要忘记将ISupportErrorInfo包含到您的类的COM_MAP中。

答案 2 :(得分:0)

我现在也在努力解决这个问题。到目前为止,我的挖掘表明错误代码实际上是HRESULT值。 VB6试图变得聪明并解释HRESULT,但它似乎有一个相当有限的HRESULT列表。对于VB6不熟悉的HRESULT,它只是将HRESULT放入Err.Number属性中,并希望开发人员足够聪明,可以弄清楚如何处理它。

我最接近返回错误号是使用MAKE_SCODE生成HRESULT,其中HRESULT的代码字段设置为我想要的,严重性标志设置以及我希望是正确的设施。

与CreateErrorInfo和SetErrorInfo一起在VB6中获取错误代码和错误描述。这让我们回到VB6,试图通过有限的错误列表来实现智能化。

答案 3 :(得分:0)

查看这篇文章http://support.microsoft.com/kb/827994。所以你的对象必须实现返回S_OK的方法ISupportsErrorInfo :: InterfaceSupportsErrorInfo()。然后在返回之前,必须使用指向实现IErrorInfo :: GetDescription()的COM对象的指针调用SetErrorInfo。 这里有一个例子: http://msdn.microsoft.com/en-us/library/ms221409.aspx

如果在返回之前有SetErrorInfo,VB将查询传递给SetErrorInfo的对象指针的GetDescription方法。

我对你使用的属性代码并不太深 - 我宁愿使用更多的原始COM测试它,这肯定总是很多样板代码 - 但至少它可以工作,那么你可以使用复杂的包装而不是它