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

bdo*_*lan 5 vb6 com error-handling activex atl

我试图使用CComCoClass :: Error向VB6返回一个详细的错误,但似乎我只能返回错误代码/或/消息 - 但不是两者.

return Error(_T("Not connected"), __uuidof(IMyInterface), HRESULT_FROM_WIN32(ERROR_CONNECTION_INVALID));
Run Code Online (Sandbox Code Playgroud)

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

return Error(_T("Not connected"));
Run Code Online (Sandbox Code Playgroud)

导致相应的错误消息,但Err.Number中的一般错误代码.我怎样才能充分利用这两个世界?

Ste*_*pel 5

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

  • 不返回任何消息和VB友好的COM错误,即VB运行时根据此知识库文章所熟知的错误; VB运行时会将此"COM错误"转换为VB错误加消息.
  • 返回错误消息和DISP_E_EXCEPTION; VB运行时将通过此"服务器错误"和您的自定义错误消息.这是你的第二个例子隐含发生的事情,详见下文.
  • 不返回任何消息和任何其他COM错误,即VB运行时不知道的错误; VB运行时将使用原始HRESULT和通用消息" Method '~' of object '~' failed".
    • 请注意,如果您在此处提供错误消息,则此运行时行为也适用,即您的消息将被忽略!这就是您的第一个示例,请参阅下面的详细信息.

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

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

细节

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

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

来自KB文章 justadreamer 已经指出:

[...]调用GetErrorInfo方法以检索可用的错误信息.然后,运行时确定bstrDescription是否具有NULL以外的值.如果运行时发现的值不是NULL [...],则在此方案中使用原始HRESULT值.如果运行时发现NULL值,则[...] Visual Basic然后使用HRESULT查找相应的Visual Basic错误.

这解释了关于你的第一个例子的行为:你确实提供了一条错误消息,因此运行时只是转向它的通用消息" Method '~' of object '~' failed"加上你的HRESULT.

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

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