[英]How can I return both an error string and error code to VB6 from an ATL activex control?
I'm trying to return a detailed error to VB6 using CComCoClass::Error , but it seems I can only return an error code /or/ a message - but not both. 我试图使用CComCoClass :: Error向VB6返回一个详细的错误 ,但似乎我只能返回错误代码/或/消息 - 但不是两者。
return Error(_T("Not connected"), __uuidof(IMyInterface), HRESULT_FROM_WIN32(ERROR_CONNECTION_INVALID));
results in a generic "Method 'Request' of object 'IMyInterface' failed" error message in Err.Description on the VB6 side (but ERROR_CONNECTION_INVALID in Err.Number), while 导致VB6端的Err.Description中的对象'IMyInterface'失败的通用“方法'请求'错误消息”(但Err.Number中的ERROR_CONNECTION_INVALID),而
return Error(_T("Not connected"));
results in the appropriate error message, but a generic error code in Err.Number. 导致相应的错误消息,但Err.Number中的一般错误代码。 How can I get the best of both worlds? 我怎样才能充分利用这两个世界?
You can't, this appears to be by design. 你不能,这似乎是设计的。 Details further below, but in short you have three options: 详细信息如下,但简而言之,您有三种选择:
Method '~' of object '~' failed
". VB运行时将使用原始HRESULT加上Method '~' of object '~' failed
“通用消息” Method '~' of object '~' failed
。
For the task at hand it boils down to two choices: 对于手头的任务,归结为两种选择:
The VB runtime seems to offer only very restricted handling in regard to COM errors. VB运行时似乎只提供有关COM错误的非常有限的处理。 This is likely for historic and/or technical reasons specific to the way VB has been implemented and not of particular interest here (keywords would be IDispatch only vs dual interface and ActiveX as a 'subset' of COM). 这可能是出于特定于VB实现方式的历史和/或技术原因而不是特别感兴趣的(关键字将仅IDispatch与双接口和ActiveX作为COM的'子集')。
While I've been unable to surface an explicit specification for the behavior outlined above one can figure it from digging through other sources: 虽然我无法针对上面列出的行为制定明确的规范,但可以通过挖掘其他来源来解决这个问题:
From the KB article justadreamer pointed out already : 来自KB文章 justadreamer 已经指出 :
[...] a call is made to the GetErrorInfo method to retrieve the available error information. [...]调用GetErrorInfo方法以检索可用的错误信息。 The runtime then determines whether bstrDescription has a value other than NULL. 然后,运行时确定bstrDescription是否具有NULL以外的值。 If the runtime finds a value other than NULL, [...], the raw HRESULT value is used in this scenario. 如果运行时发现的值不是NULL [...],则在此方案中使用原始HRESULT值。 If the runtime finds a NULL value, [...] Visual Basic then uses HRESULT to look up the corresponding Visual Basic error. 如果运行时发现NULL值,则[...] Visual Basic然后使用HRESULT查找相应的Visual Basic错误。
This explains the behavior regarding your fist example: you did supply an error message, hence the runtime simply resorts to its generic message " Method '~' of object '~' failed
" plus your HRESULT
. 这解释了关于你的第一个例子的行为:你确实提供了一条错误消息,因此运行时只是转向它的通用消息“ Method '~' of object '~' failed
”加上你的HRESULT
。
The behavior of your second example is also consistent once you look at the definition of the (first listed) constructor for CComCoClass::Error
: it has defaults for the non specified parameters, especially 'hRes = 0'. 一旦您查看CComCoClass::Error
的原因(第一个列出的)构造函数的定义,您的第二个示例的行为也是一致的CComCoClass::Error
:它具有非指定参数的默认值,尤其是'hRes = 0'。 The 'Remarks' section further states that "If hRes is zero, then the first four versions of Error return DISP_E_EXCEPTION.". “备注”部分进一步指出“如果hRes为零,那么Error的前四个版本将返回DISP_E_EXCEPTION。”。 Consequently this implicitly triggers the 'Server error' pass through behavior. 因此,这会隐式触发“服务器错误”传递行为。
Finally, for a concrete C++ implementation sample of a VB like automation client behavior see for example paragraphs 'Error handling' and the following 'Exercise 5' in Automating Microsoft Office 97 and Microsoft Office 2000 . 最后,对于像自动化客户端行为这样的VB的具体C ++实现示例,请参阅自动化Microsoft Office 97和Microsoft Office 2000中的段落“错误处理”和以下“练习5”。
Derive the class that implements your COM-exposed interface from ISupportErrorInfoImpl, call SetErrorInfo to set the detailed explanation of the error if any occurs. 从ISupportErrorInfoImpl派生实现COM暴露接口的类,调用SetErrorInfo以设置错误的详细说明(如果有)。 Don't forget to include ISupportErrorInfo into the COM_MAP of your class. 不要忘记将ISupportErrorInfo包含到您的类的COM_MAP中。
I'm struggling with this right now too. 我现在也在努力解决这个问题。 So far my digging indicates that the error code is really the HRESULT value. 到目前为止,我的挖掘表明错误代码实际上是HRESULT值。 VB6 tries to be smart and interpret the HRESULT but it seems to have a fairly limited list of HRESULTs it understands. VB6试图变得聪明并解释HRESULT,但它似乎有一个相当有限的HRESULT列表。 For the HRESULTs VB6 is not familiar with, it just puts the HRESULT into the Err.Number property and hopes that the developer is smart enough to figure out what to do with it. 对于HR6不熟悉的HRESULT,它只是将HRESULT放入Err.Number属性中,并希望开发人员足够聪明,可以弄清楚如何处理它。
The closest I've come to returning an error number is by using MAKE_SCODE to generate an HRESULT with the code field of the HRESULT set to what I want, the severity flag set and what I hope is the right facility. 我最接近返回错误号是通过使用MAKE_SCODE生成HRESULT,HRESULT的代码字段设置为我想要的,严重性标志设置和我希望是正确的设施。
That in conjunction with CreateErrorInfo and SetErrorInfo get me an error code and an error description in VB6. 与CreateErrorInfo和SetErrorInfo一起在VB6中获取错误代码和错误描述。 And that brings us back to VB6 trying to be smart with a limited list of errors. 这让我们回到VB6,试图通过有限的错误列表来实现智能。
Checkout this article http://support.microsoft.com/kb/827994 . 查看这篇文章http://support.microsoft.com/kb/827994 。 So your object must implement method ISupportsErrorInfo::InterfaceSupportsErrorInfo() which returns S_OK. 所以你的对象必须实现返回S_OK的方法ISupportsErrorInfo :: InterfaceSupportsErrorInfo()。 and then before returning you must call SetErrorInfo with a pointer to a COM object which implements IErrorInfo::GetDescription(). 然后在返回之前,必须使用指向实现IErrorInfo :: GetDescription()的COM对象的指针调用SetErrorInfo。 There is an example here: http://msdn.microsoft.com/en-us/library/ms221409.aspx . 这里有一个例子: http : //msdn.microsoft.com/en-us/library/ms221409.aspx 。
If you SetErrorInfo before return, VB will query the GetDescription method of the object pointer you passed to SetErrorInfo. 如果在返回之前有SetErrorInfo,VB将查询传递给SetErrorInfo的对象指针的GetDescription方法。
I am not too deep in the attributed code you are using - I would prefer to test it using more raw COM which is surely always a lot of boilerplate code - but at least it works, then you could use sophisticated wrappers instead of it. 我对你使用的属性代码并不太深 - 我宁愿使用更多的原始COM来测试它,这肯定总是很多样板代码 - 但至少它可以工作,那么你可以使用复杂的包装而不是它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.