简体   繁体   English

如何从ATL activex控件向VB6返回错误字符串和错误代码?

[英]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: 详细信息如下,但简而言之,您有三种选择:

  • Return no message and a VB friendly COM error, ie one well known by the VB runtime according to this KB article ; 不返回任何消息和VB友好的COM错误,即VB运行时根据此知识库文章 所熟知的错误; the VB runtime will translate this 'COM error' to a VB error plus message. VB运行时会将此“COM错误”转换为VB错误加消息。
  • Return an error message and DISP_E_EXCEPTION; 返回错误消息和DISP_E_EXCEPTION; the VB runtime will pass through this 'Server error' and your custom error message. VB运行时将通过此“服务器错误”和您的自定义错误消息。 This is what's implicitly happening on your second example, see below for details. 这是你的第二个例子隐含发生的事情,详见下文。
  • Return no message and any other COM error, ie one not known by the VB runtime; 不返回任何消息和任何其他COM错误,即VB运行时不知道的错误; the VB runtime will resort to the raw HRESULT plus the generic message " Method '~' of object '~' failed ". VB运行时将使用原始HRESULT加上Method '~' of object '~' failed “通用消息” Method '~' of object '~' failed
    • Please note that this runtime behavior does also apply, if you do supply an error message here, ie your message will simply be ignored! 请注意,如果您在此处提供错误消息,则此运行时行为也适用,即您的消息将被忽略! This is what's happening on your first example, see below for details. 这就是您的第一个示例,请参阅下面的详细信息。

For the task at hand it boils down to two choices: 对于手头的任务,归结为两种选择:

  • If you want to supply contextually correct 'COM errors' for automation clients like VB (and likely you should) you must omit custom error messages. 如果要为自动化客户端(如VB)提供上下文正确的“COM错误”,则必须省略自定义错误消息。
  • If you want to supply custom error messages for 'Server errors' (ie a custom error conditions regarding the functionality within your automation server) your only option is DISP_E_EXCEPTION. 如果您想为“服务器错误”(即关于您的自动化服务器的功能的自定义错误条件)提供自定义错误消息你唯一的选择是DISP_E_EXCEPTION。

Details 细节

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.

相关问题 如何将正向错误代码从ATL返回到VB6? - How to return positive error code from ATL to VB6? 从ATL ActiveX控件返回对象的数组 - Return Array of object from ATL ActiveX Control 是否可以从同一项目中的另一个ATL简单对象访问ActiveX项目功能? - Can I access in ActiveX project functions from another ATL simple object in the same project? 如何从.ocx文件动态实例化ActiveX控件? - How can I dynamically instantiate an ActiveX control from an .ocx file? 从ATL控件返回等效的DateTime - Return DateTime equivalent from ATL control GetObject和VB6 ActiveX exe - GetObject and VB6 ActiveX exe 如何处理与 VB6 ActiveX dll 的对话,该 ActiveX dll 具有来自 .NET Z3055DD731D7924089A62F3 的 OCX 依赖项 - How to handle talking to VB6 ActiveX dll that has OCX dependencies from a .NET WPF application 错误C2664:无法从&#39;const ATL :: CAdapt转换参数2 <ATL::CComPtr<IZipFileEntry> &gt; *&#39;&#39;ATL :: CAdapt <ATL::CComPtr<IZipFileEntry> &gt; *&#39; - error C2664: cannot convert argument 2 from 'const ATL::CAdapt<ATL::CComPtr<IZipFileEntry>> *' to 'ATL::CAdapt<ATL::CComPtr<IZipFileEntry>> *' 我如何从ActiveX控件中读取Web浏览器生成的Cookie - how can i read cookie generated by web browser from activex control 如何在 VB6 和 C# 之间共享接口? - How can I share an interface between VB6 and C#?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM