Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to return positive error code from ATL to VB6?

Tags:

c++

com

vb6

atl

I have checked out the answer at: How can I return both an error string and error code to VB6 from an ATL activex control?

I am able to return custom negative error codes, ie with the severity bit set, and a custom error message. But, I would like to be able to generate a code that VB6 will present as a positive # for Err.Number that the user will find easier to use. I'm pretty sure that it can be done since Microsoft's DAO 3.6 DLL is able to. For example, it returns Err.Number= 3078 with Err.Description "The Microsoft Jet database..." if a table does not exist.

Note that I have implemented ISupportErrorInfo, etc. for error reporting.

like image 898
veneff Avatar asked May 08 '13 19:05

veneff


2 Answers

Annotating Mark's answer a bit. He's right about using FACILITY_CONTROL. In addition you must ensure that the error code is larger than 512 so it doesn't interfere with VB6 runtime error codes. So use something like this:

HRESULT MakeVB6Error(UINT errCode) {
    assert(errCode > 0 && errCode < 65536 - 513);
    return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_CONTROL, errCode + 513);
}
like image 196
Hans Passant Avatar answered Nov 10 '22 22:11

Hans Passant


VB does a lot of mapping of HRESULT values to Err.Number values. For instance, if the HRESULT was 0x8007002, VB breaks down them using the COM standard as follows:

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

In practice the top nibble is always 8. The Facility varies, and tells you what type of error that this is. In this case, the facility code is 0x007 (FACILITY_WIN32), which means that this is a standard Win32 error. The lower two bytes represent the actual error. Looking in winerror.h, this error is 2 - ERROR_FILE_NOT_FOUND. VB is clever enough to map this error to the standard VB error 53 "File not found".

In the VB documentation, we were always encouraged to add the constant vbObjectError to our error numbers when raising them from a VB component. This was almost equivalent to ORing the 32 bit integer 0x80040000 to your error number (assuming it was <= 65535). In this case, the facility code was 0x4 (FACILITY_ITF) which indicated that the error was raised from a coclass's specific interface. In practice this just made our error numbers large and negative, and hard to understand.

What we should have really done was to ignore the documentation and just raise the straight error numbers. Behind the scenes, VB OR'd its own facility code - 0xA (FACILITY_CONTROL). However, any VB component seeing an HRESULT with that facility code would automatically clear the top two bytes, so we would see the number as being positive - not negative.

I suggest that you use FACILITY_CONTROL for your own error numbers. Other COM clients may possibly get confused, but VB clients see your error number as positive.

Alternatively, you could ignore the normal HRESULT mechanism for return values. Instead return HRESULT = S_OK, and use a [retval, out] parameter at the end of the function to make it look as if it is a VB function.

like image 45
Mark Bertenshaw Avatar answered Nov 10 '22 21:11

Mark Bertenshaw