VB makes many mappings of HRESULT values ββto Err.Number values. For example, if HRESULT was 0x8007002, VB breaks them according to 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 upper nibble is always 8. The mechanism varies and tells you what type of error it is. In this case, the object code is 0x007 (FACILITY_WIN32), which means that this is a standard Win32 error. The bottom two bytes represent the actual error. Looking in winerror.h, this error is 2 - ERROR_FILE_NOT_FOUND. VB is smart enough to correlate this error with the standard error VB 53 "File not found".
In VB documentation, we are always advised to add the vbObjectError constant to our error numbers when they increase from the VB component. This was almost equivalent to ORing a 32-bit integer 0x80040000 to your error number (assuming it is <= 65535). In this case, the object code was 0x4 (FACILITY_ITF), which indicated that the error was raised using a specific interface in the class. In practice, this simply made our error numbers large and negative, and hard to understand.
We really had to ignore the documentation and just raise the direct error numbers. Behind the scenes, VB OR'd has its own object code - 0xA (FACILITY_CONTROL). However, any VB component, seeing HRESULT with this object code, will automatically clear the upper two bytes, so we will see that the number will be positive - not negative.
I suggest you use FACILITY_CONTROL for your own error numbers. Other COM clients may be confused, but VB clients see your error number as positive.
Alternatively, you can ignore the usual HRESULT mechanism for return values. Instead, return HRESULT = S_OK and use the [retval, out] parameter at the end of the function to make it look like it is a VB function.