如何从 ATL 返回正错误代码到 VB6?

Posted

技术标签:

【中文标题】如何从 ATL 返回正错误代码到 VB6?【英文标题】:How to return positive error code from ATL to VB6? 【发布时间】:2013-05-03 03:05:40 【问题描述】:

我已经查看了答案:How can I return both an error string and error code to VB6 from an ATL activex control?

我能够返回自定义的否定错误代码,即设置了严重性位和自定义错误消息。但是,我希望能够生成一个代码,VB6 将显示为 Err.Number 的正数,用户会发现它更易于使用。我很确定它可以做到,因为 Microsoft 的 DAO 3.6 DLL 能够做到。例如,如果表不存在,则返回 Err.Number= 3078 和 Err.Description "The Microsoft Jet database..."。

请注意,我已经实现了 ISupportErrorInfo 等用于错误报告。

【问题讨论】:

【参考方案1】:

VB 将 HRESULT 值映射到 Err.Number 值。例如,如果 HRESULT 是 0x8007002,VB 使用 COM 标准将它们分解如下:

Bit 31 - Severity (set to 1 in all errors)
Bit 30 - Reserved
Bit 29 - Customer Bit
Bit 28 - Reserved
Bit 27 
  - 16   Facility code
Bit 15 
  -  0   Error code

实际上,最高半字节始终是 8。Facility 会有所不同,并告诉您这是什么类型的错误。在这种情况下,设施代码是 0x007 (FACILITY_WIN32),这意味着这是一个标准的 Win32 错误。低两个字节代表实际错误。查看 winerror.h,此错误为 2 - ERROR_FILE_NOT_FOUND。 VB 很聪明,可以将此错误映射到标准的 VB 错误 53“找不到文件”。

在 VB 文档中,总是鼓励我们在从 VB 组件引发错误编号时将常量 vbObjectError 添加到错误编号中。这几乎等同于将 32 位整数 0x80040000 与您的错误号进行或运算(假设它是

我们真正应该做的是忽略文档并直接提出错误编号。在幕后,VB 对自己的设施代码进行了 OR 运算 - 0xA (FACILITY_CONTROL)。但是,任何看到带有该设施代码的 HRESULT 的 VB 组件都会自动清除前两个字节,因此我们会将数字视为正数 - 而不是负数。

我建议您将 FACILITY_CONTROL 用于您自己的错误编号。其他 COM 客户端可能会感到困惑,但 VB 客户端会将您的错误编号视为肯定的。

或者,您可以忽略返回值的正常 HRESULT 机制。而是返回 HRESULT = S_OK,并在函数末尾使用 [retval, out] 参数使其看起来像一个 VB 函数。

【讨论】:

【参考方案2】:

稍微注释一下马克的答案。他对使用 FACILITY_CONTROL 是正确的。此外,您必须确保错误代码大于 512,以免干扰 VB6 运行时错误代码。所以使用这样的东西:

HRESULT MakeVB6Error(UINT errCode) 
    assert(errCode > 0 && errCode < 65536 - 513);
    return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_CONTROL, errCode + 513);

【讨论】:

这里有一个类似的答案,关于如何从 C# 做同样的事情(对于那些通过谷歌到达这里的人):Raise positive VB style error codes via COM interop from C#

以上是关于如何从 ATL 返回正错误代码到 VB6?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 ATL 创建 VB6 集合对象

如何从 E_FAIL 获取详细的错误信息?

atl.dll已加载,但对dllregisterserver的调用失败,错误代码0x8002801c怎么办

尝试从C#调试到VB6会产生TYPE_E_CANTLOADLIBRARY?

如何在 VB6 中处理 OCR 扫描错误

将字符串数组从 VB6 传递到 COM 对象