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 函数。