6

我已经在以下位置查看了答案: 如何将错误字符串和错误代码从 ATL activex 控件返回到 VB6?

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

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

4

2 回答 2

5

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

HRESULT MakeVB6Error(UINT errCode) {
    assert(errCode > 0 && errCode < 65536 - 513);
    return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_CONTROL, errCode + 513);
}
于 2013-05-09T01:09:29.933 回答
4

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 与您的错误号进行或运算(假设它是 <= 65535)。在这种情况下,设施代码是 0x4 (FACILITY_ITF),这表明错误是从 coclass 的特定接口引发的。在实践中,这只会使我们的错误数很大且为负数,并且难以理解。

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

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

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

于 2013-05-08T23:40:07.627 回答