How can I return the error string and error code in VB6 from an activex ATL control?

I am trying to return a detailed error in VB6 using CComCoClass :: Error , but it looks like I can return an error code / or / message, but not both.

return Error(_T("Not connected"), __uuidof(IMyInterface), HRESULT_FROM_WIN32(ERROR_CONNECTION_INVALID)); 

displays a general "method request" for the error message "IMyInterface" of the Error object in the Err.Description message on the VB6 side (but ERROR_CONNECTION_INVALID in Err.Number),

 return Error(_T("Not connected")); 

the corresponding error message is displayed, but the common error code is in Err.Number. How can I get the best of both worlds?

+5
source share
4 answers

You can't, it looks by design. Details are below, but in short you have three options:

  • Do not return a message and a VB-friendly COM error, that is, one well-known VB runtime in accordance with this KB article ; VB runtime will translate this “COM error” into a VB error message.
  • Returns an error message and DISP_E_EXCEPTION; The VB runtime will go through this “Server Error” and your error message. This is what happens implicitly in the second example, see below for details.
  • Do not return a message or any other COM error, i.e. one unknown at runtime VB; the VB runtime will use raw HRESULT plus the generic message " Method '~' of object '~' failed ".
    • Please note that this behavior during operation also applies if you deliver an error message here, that is, your message will simply be ignored! This is what happens in your first example, see below for details.

For this task, it comes down to two options:

  • If you want to provide contextually correct "COM errors" for automation clients such as VB (and most likely you should), you should omit the error messages.
  • If you want to provide custom error messages for "Server Errors" (that is, custom error conditions regarding functionality within the automation server), the only option is DISP_E_EXCEPTION.

More details

The VB runtime seems to offer only very limited processing regarding COM errors. This is probably due to historical and / or technical reasons specific to the way VB is implemented, and not of particular interest (the keywords will be IDispatch only against the dual interface and ActiveX as a “subset” of COM).

While I could not handle the explicit specification of the behavior described above, you can understand how it delved into other sources:

From an article in KB justadreamer already states :

[...] a call is made to the GetErrorInfo method to retrieve the available error information. runtime determines whether bstrDescription has a value other than ZERO. If the runtime finds a value other than NULL, [...] the raw HRESULT value is used in this script. If runtime finds a NULL value, [...] Then Visual Basic uses HRESULT to find the corresponding Visual Basic error.

This explains the behavior of your example: you sent an error message, so the runtime simply uses its generic message “ Method '~' of object '~' failed " plus your HRESULT .

The behavior of your second example is also consistent if you look at the constructor definition (first list) for CComCoClass::Error : it has default values ​​for parameters not specified, especially "hRes = 0". The Remarks section further states that "If hRes is zero, then the first four versions of Error return DISP_E_EXCEPTION." Therefore, this implicitly raises a “Server Error” error through behavior.

Finally, for a specific example of a C ++ implementation for VB, such as the behavior of an automation client, see, for example, the paragraphs “Error handling” and the following “Exercise 5” in Automating Microsoft Office 97 and Microsoft Office 2000 .

+5
source

Derive a class that implements your interface, opened via COM, from ISupportErrorInfoImpl, call SetErrorInfo to establish a detailed explanation of the error if this happens. Remember to include ISupportErrorInfo in the COM_MAP of your class.

0
source

I am also struggling with this now. So far, my digging indicates that the error code is indeed an HRESULT value. VB6 is trying to be smart and interpret HRESULT, but it seems to have a fairly limited HRESULT list, which it understands. For HRESULTs VB6 is not familiar, it just turns HRESULT into an Err.Number property and hopes that the developer is smart enough to understand what to do with it.

The closest I came to return the error number is to use MAKE_SCODE to generate HRESULT with the HRESULT code field set for what I want, set with the severity flag and what I hope is the right tool.

In combination with CreateErrorInfo and SetErrorInfo, get the error code and error description in VB6. And that brings us back to VB6, trying to be smart with a limited list of bugs.

0
source

Checkout http://support.microsoft.com/kb/827994 . Therefore, your object must implement the ISupportsErrorInfo :: InterfaceSupportsErrorInfo () method, which returns S_OK. and then before returning you must call SetErrorInfo with a pointer to a COM object that implements IErrorInfo :: GetDescription (). Here is an example: http://msdn.microsoft.com/en-us/library/ms221409.aspx .

If you set SetErrorInfo before returning, VB will call the GetDescription method of the pointer of the object you passed to SetErrorInfo.

I do not know much about the attribute code you are using. I would prefer to test it using the more crude COM, which certainly always has a lot of template code, but at least it works, then you can use complex wrappers instead of it.

0
source

Source: https://habr.com/ru/post/944566/


All Articles