Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I return both an error string and error code to VB6 from an ATL activex control?

Tags:

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.

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

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

results in the appropriate error message, but a generic error code in Err.Number. How can I get the best of both worlds?

like image 766
bdonlan Avatar asked Jul 01 '09 14:07

bdonlan


1 Answers

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, i.e. one well known by the VB runtime according to this KB article; the VB runtime will translate this 'COM error' to a VB error plus message.
  • Return an error message and DISP_E_EXCEPTION; the VB runtime will pass through this 'Server error' and your custom error message. This is what's implicitly happening on your second example, see below for details.
  • Return no message and any other COM error, i.e. one not known by the VB runtime; the VB runtime will resort to the raw HRESULT plus the generic message "Method '~' of object '~' failed".
    • Please note that this runtime behavior does also apply, if you do supply an error message here, i.e. 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.
  • If you want to supply custom error messages for 'Server errors' (i.e. a custom error conditions regarding the functionality within your automation server) your only option is DISP_E_EXCEPTION.

Details

The VB runtime seems to offer only very restricted handling in regard to COM errors. 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).

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:

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

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.

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'. The 'Remarks' section further states that "If hRes is zero, then the first four versions of Error return 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.

like image 94
Steffen Opel Avatar answered Oct 04 '22 18:10

Steffen Opel