February 16, 2024

VBA CVErr() and the Err.Raise() test

Last modified: Wed Mar 13 21:17:35 UTC+0100 2024 © Attila Tarpai

VBA CVErr() and the Err.Raise() test


About HRESULT

Win uses a 32-bit HRESULT value system to standardize error handling mechanism.

HRESULT: as a signed integer a negative value indicates failure and other values indicate success.

31        26                    15                              0
+-+-+-+-+-+-+---+---+---+---+---+---+---+---+---+---+---+---+---+
|S R C N r|       Facility      |             Code              |
+-+-+-+-+-+-+---+---+---+---+---+---+---+---+---+---+---+---+---+

S=0 success
S=1 failure

The R, C, N, and r bits are reserved in the HRESULT

Facility is a 11-bit field: for 2048 different sub-systems for error origin (ex. FACILITY_STORAGE=3, FACILITY_DISPATCH=2, FACILITY_WIN32=7)

Code is the unsigned 16-bit error code itself 0-65535.

Facility 0Ah is used by VBA to generate Legacy BASIC error codes (see below).

VBA vbObjectError = &H80040000. This is failure from FACILITY_ITF.


CVErr() makes HRESULT

The conversion function CVErr(Code):

  • returns Variant of type Variant/Error (vbError=10) that stores a 32-bit HRESULT value
  • Code is a Long value with valid range of 00000000-0000FFFF (16-bits). Any other value gives Run-time error 5, Invalid procedure call or argument.

CVErr(0) returns all zero Success HRESULT in the Variant, others generate "Automation error" S=1 failure with Facility=0A. Here is a memory dump:

CVErr(0)         --->  0A00-000000000000-0000000000000000-0000000000000000    64-bit Variant/Error (S=0 success)

CVErr(1..65535)  --->  0A00-000000000000-xxxx0A8000000000-0000000000000000    64-bit Variant/Error (S=1 failure)

When converting Variant/Error to Long we get only the lower 16-bits:

31                              15                              0
+-------------------------------+---+---+---+---+---+---+---+---+
|                               |             Code              |  Long
+-------------------------------+---+---+---+---+---+---+---+---+

                                                | CVErr(Code)
                                                |
                                                V
31        26                    15                              0
+-+-+-+-+-+-+---+---+---+---+---+---+---+---+---+---+---+---+---+
|S 0 0 0 0|           0A        |             Code              |  HRESULT in Variant/Error
+-+-+-+-+-+-+---+---+---+---+---+---+---+---+---+---+---+---+---+

                                                | CLng(Variant)
                                                |
                                                V
31                              15                              0
+-------------------------------+---+---+---+---+---+---+---+---+
|                               |             Code              |  Long
+-------------------------------+---+---+---+---+---+---+---+---+

Excel also uses some of the Variant/Error values. When a UDF function returns Variant/Error into a cell, f. ex. CVErr(2042), Excel will display it as #N/A.

Constant      Error number    Cell error value
xlErrDiv0     2007            #DIV/0!
xlErrNA       2042            #N/A
xlErrName     2029            #NAME?
xlErrNull     2000            #NULL!
xlErrNum      2036            #NUM!
xlErrRef      2023            #REF!
xlErrValue    2015            #VALUE!

The VBA Err() function

Err() is a Public function of Module Information. It returns an instance of ErrObject, which is a Class of VBA:

VBE7.DLL                                               Class ErrObject
VBA                                                  +-----------------+
|__  ..                                              |   Number        |
|___ Class ErrObject                                 |   Description   |
|___ Module Information                              |   Raise()       |
|__  ..   |___ ..                                    |   Clear()       |
          |___ Function Err() As ErrObject           |   ...           |
          |__  ..                                    +-----------------+

Err is a short-cut for Err(): Err.Raise(N) = Err().Raise(N)

Run-time errors or Err.Raise() fills out values in the ErrObject instance and VBA starts looking for an error handler along the call stack.

If Err is not cleared, only Number is updated when a subsequent Err.Raise() is called. This can happen in error handlers or after On Error Resume Next. Internal Run-time errors update all values in the ErrObject.


The big Err.Raise() test

This is an investigation to call Err.Raise(Number) in a VBA Module and observing the result in the ErrObject. Raise causes Run-time error that is trapped in the same procedure with On Error GoTo. The test code:

Sub errtrap()
  On Error GoTo label

      Err.Raise N
      ...
      Exit Sub

label:
      check Err.Number...
      check Err.Description...
      ...
      Resume Next
End Sub

Err.Raise(Number) expects a 32-bit Long argument for Number. Err.Number is also 32-bit Long value.

This is a flowchart what may happen internally:

Err.Raise(N)                                                             Err.Number
                                                                         Err.Description

+----------+      +----------+                    ?   +----------+
| 00000000 | ---> | S00A0005 |                  --->  | 0xxxxxxx |
+----------+      +----------+                 |      +----------+
+----------+      +----------+                 |      +----------+
| 0xxxxxxx | ---> | S00A0005 |                  --->  | S00A0000 |
+----------+      +----------+                 |      +----------+
+----------+      +----------+                 |         SUCCESS
| 0000xxxx | ---> | S00Axxxx |                 |
+----------+      +----------+                 |      +----------+      +----------+
                        |                       --->  | S00Axxxx | ---> | 0000xxxx |
                        |                      |      +----------+      +----------+
+----------+            |      +----------+    |           ^             Standard BASIC error or
| Sxxxxxxx | ----------- ----> |  HRESULT | ---            |             "Application-defined or object-defined error"
+----------+                   +----------+    |           |some
                                    ^          |      +----------+      +----------+
                                    |           --->  | Sxxxxxxx | ---> | Sxxxxxxx |
                                    |                 +----------+      +----------+
                                 Run-time                                "Automation error" + optional Description
                          Other Automation Objects

Err.Raise() in VBA code is raising an error: all Number values are converted to S=1 failure HRESULT codes. The run-time works with HRESULT internally and can also receive HRESULT success/failure codes from other Automation Objects. The HRESULT dispather then delivers codes to ErrObject with possible translations. S=0 success codes do not raise an error, execution continues with the next statement.

All these result were made using Err.Raise() only and in VBA64. Certain results are probably specific to an actual Win- and Office version.

Raising S=0

Valid only in the range of 00000001-0000FFFF, similar to CVErr(). All other values raise 5, "Invalid procedure call or argument":

Raise N      ----------->   Err.Number

00000000                    5, Invalid procedure call or argument
00000001 - 0000FFFF         Err.Number = N
00010000 - 07FFFFFF         5, Invalid procedure call or argument (sometimes 5, "Class not registered"?)

In the 0001-FFFF range many of them are Standard BASIC errors, like 3, "Return without GoSub".

Unused codes keep N and put "Application-defined or object-defined error" in Description.

I have not tested all above 65535..

Some of the Standard errors:

00000003	Return without GoSub
00000005	Invalid procedure call or argument
00000006	Overflow
00000007	Out of memory
00000009	Subscript out of range
0000000A	This array is fixed or temporarily locked
0000000B	Division by zero
0000000D	Type mismatch
0000000E	Out of string space
00000010	Expression too complex
00000011	Can't perform requested operation
00000012	User interrupt occurred
00000014	Resume without error
0000001C	Out of stack space
....
....
000002E8	Search text not found
000002EA	Replacements too long

Raising S=1

Generally, all negative S=1 failure HRESULT in VBA is "Automation error" with an optional error in Description. Most of HRESULT-s after Err.Raise() comes back untranslated in Err.Number. Facility code matters etc.

Raise N         ---->  Err.Number

Raise 8xxxxxxx  ---->  8xxxxxxx "Automation error"

Several HRESULT-s are translated to Standard errors and multiple HRESULT-s raised by Automation Objects can be translated to the same Legacy Error code. F. ex.:

Raise 80020001  ---->  000001B6 Object doesn't support this property or method
Raise 80020003  ---->  000001B6 Object doesn't support this property or method

This also means that getting an "Object doesn't support this property or method" in VBA we have no idea about the original Automation error.

Raising Facility 0Ah S=1 will be translated to Legacy VBA errors (therefore I think VBA works internally with HRESULT). F. ex.:

Raise 800A0000  ---->  SUCCESS, NOTHING HAPPENS, executes next statement
Raise 800A0001  ---->  1, "Application-defined or object-defined error"
Raise 800A0002  ---->  2, "Application-defined or object-defined error"
Raise 800A0003  ---->  3, "Return without GoSub"
...
...
Raise 800AFFFF  ---->  65535, "Application-defined or object-defined error"

An interesting test: Raise Sxxx0003 for all 2048 Facility where result is not merely "Automation error". A method to discover sub-systems and Facility codes:

80000003  Automation error One or more arguments are invalid
80010003  Automation error The caller is dispatching an intertask SendMessage call and cannot call out via PostMessage.
000001B6  Object doesn't support this property or method
0000004C  Path not found
80040003  Automation error This implementation doesn't take advises
80070003  Automation error The system cannot find the path specified.
80080003  Automation error RPC communication failed with OLE service
80090003  Automation error Bad Key.
00000003  Return without GoSub
800B0003  Automation error The form specified for the subject is not one supported or known by the specified trust provider.
800C0003  Automation error No Internet session has been established.
800F0003  Automation error The syntax of the INF is invalid.
80100003  Automation error The supplied handle was invalid.
80190003  Automation error Unexpected redirection status code (3xx).
801F0003  Automation error Asynchronous requests are not valid for this operation.
80270003  Automation error The entity ID conflicts with an already registered id.
80280003  Automation error TPM 1.2: One or more parameter is bad.
802A0003  Automation error This method cannot be called during this type of callback.
80310003  Automation error The BIOS did not correctly communicate with the master boot record (MBR). Contact the computer manufacturer for BIOS upgrade instructions.
80320003  Automation error The filter does not exist.
80390003  Automation error Some BCD entries were not synchronized correctly with the firmware.
803B0003  Automation error The network's underlying layer was not found.
803D0003  Automation error The operation is not allowed due to the current state of the object.
80400003  Automation error One or more fields in the input packet are invalid.
80550003  Automation error The EAS policy being evaluated cannot be enforced by the system.
80630003  Automation error The required service cannot be started.
80650003  Automation error The attribute cannot be written.
80660003  Automation error HD Audio widget does not support the connection list parameter.
80670003  Automation error The StateRepository configuration is not valid.
80830003  Automation error The specified storage tier could not be found on the volume. Confirm that the storage tier name is valid.
80860003  Automation error The application requesting authentication tokens is either disabled or incorrectly configured.
80B00003  Automation error Could not connect to dbgsrv server from ARM architecture device.
80E70003  Automation error The specified resiliency type is not valid.
83750003  Automation error Missing required element.
83760003  Automation error Protocol extensions are not supported.
87AF0003  Automation error Access permission denied

No comments:

Post a Comment