我已在How can I return both an error string and error code to VB6 from an ATL activex control?
检查了答案我能够返回自定义否定错误代码,即设置了严重性位,以及自定义错误消息。但是,我希望能够生成一个代码,VB6将为Err.Number提供一个积极的#,用户会发现它更容易使用。我很确定它可以完成,因为微软的DAO 3.6 DLL能够。例如,如果表不存在,则返回Err.Number = 3078,其中包含Err.Description“Microsoft Jet数据库...”。
请注意,我已经实现了ISupportErrorInfo等错误报告。
答案 0 :(得分:5)
注释Mark的答案。他说使用FACILITY_CONTROL是正确的。此外,您必须确保错误代码大于512,因此它不会干扰VB6运行时错误代码。所以使用这样的东西:
HRESULT MakeVB6Error(UINT errCode) {
assert(errCode > 0 && errCode < 65536 - 513);
return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_CONTROL, errCode + 513);
}
答案 1 :(得分: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.设施不同,并告诉您这是什么类型的错误。在这种情况下,设施代码是0x007(FACILITY_WIN32),这意味着这是标准的Win32错误。较低的两个字节表示实际错误。查看winerror.h,此错误为2 - ERROR_FILE_NOT_FOUND。 VB非常聪明,可以将此错误映射到标准VB错误53“找不到文件”。
在VB文档中,我们总是鼓励在从VB组件中提取时将常量vbObjectError添加到我们的错误号中。这几乎相当于将32位整数0x80040000与您的错误号进行ORing(假设它是&lt; = 65535)。在这种情况下,设施代码是0x4(FACILITY_ITF),表示错误是从coclass的特定接口引发的。在实践中,这只是使我们的错误数字大而负,而且难以理解。
我们真正应该做的是忽略文档并提出直接的错误号。在幕后,VB OR了自己的设施代码 - 0xA(FACILITY_CONTROL)。但是,任何看到带有该设施代码的HRESULT的VB组件都会自动清除前两个字节,因此我们会看到该数字是正数 - 而不是负数。
我建议你使用FACILITY_CONTROL作为你自己的错误号。其他COM客户端可能会感到困惑,但VB客户端会将您的错误号视为正数。
或者,您可以忽略返回值的常规HRESULT机制。而是返回HRESULT = S_OK,并在函数末尾使用[retval,out]参数使其看起来好像是VB函数。