Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Maximum Err.Raise number?

Why is it when I use Err.Raise 65536 the Err.Number will actually have the value of 5 and not 65536?

According to Raise definition: Sub Raise(Number As Long, [Source], [Description], [HelpFile], [HelpContext]). The passing parameter is Long and Err.Number is also Long.

So why can't I use values greater then 65535?

Private Sub Command1_Click()
Dim a As Long
    On Error GoTo ErrCatch
    For a = 0 To 99999
        Err.Raise a
        DoEvents
    Next a
    Exit Sub
ErrCatch:
    ' this is where Err.Number is evaluated
    Resume Next
End Sub`
like image 750
George Avatar asked Sep 21 '12 17:09

George


2 Answers

From the MSDN documentation:

Number

Required. Long integer that identifies the nature of the error. Visual Basic errors are in the range 0–65535; the range 0–512 is reserved for system errors; the range 513–65535 is available for user-defined errors. When setting the Number property to your own error code in a class module, you add your error code number to the vbObjectError constant. For example, to generate the error number 513, assign vbObjectError + 513 to the Number property.

So even though you can submit a value larger than 65535, anything larger than 65535 will become Error 5.

like image 190
LittleBobbyTables - Au Revoir Avatar answered Nov 14 '22 12:11

LittleBobbyTables - Au Revoir


There is a further level beyond "Microsoft said so". The error number that you raise is a 32-bit integer because this is part of the COM specification for passing errors between components. All public methods of a component are actually functions returning the HRESULT as the return value; if you have a VB function, it secretly maps the return value of the function to an [out] parameter. The HRESULT value is a bitfield comprised of a whole heap of values; but to keep things simple, you can divide it into two 16-bit portions. The lower 16 bits contain the actual error number, which happen to be between 0 and 65535 - the unsigned 16 bit range. There are many standards for the upper 16 bits. The most important is 0x0000____. All constants using this start with "S_" (stands for success). The most common used 32bit value is S_OK (0x00000000). If this value is returned, then the function has succeeded. Most of your VB method calls will return this value. Any value whose top bit is set, however, indicates that there has been an error. In hex, these are values looking like 0x8___ . There are many classes of error. The one which VB returns by default is 0x800A. However, the COM specification only gives you one class you can officially use, 0x8004 - which is represented in VB as the constant vbObjectError.

In fact, VB recommends you use the vbObjectError constant when raising errors on public methods in ActiveX DLLs or EXEs. Whether you do or not makes no difference. It just means that the error that is received by the calling code is very large and negative, so you will have to AND your error number with &H0000FFFF to get your 16 bit integer back. Interestingly, it also recommends that you don't do this with ActiveX control methods, probably because the upper 16 bits associated with ActiveX control methods is 0x800A000. Even more interestingly, VB itself ANDs all error numbers with 0x800A0000 when you raise them by default. Likewise it detects whether an error number is like 0x800A____ - and if so, removes the upper 16 bits for you, anyway, so you just deal with the error number itself. At my workplace, we have many VB components. Our standard is to not OR the error code with vbObjectError. This saves us the bother of subsequently having to mask it out in the calling code.

For instance, if you have COMPONENT1.CLASS1 and COMPONENT2.CLASS2. CLASS1.Method1 calls CLASS2.Method1. If I raise an error in CLASS2, then I must handle it in CLASS1.Method1. Following Microsoft's dictates, I would write it like this:

COMPONENT1.CLASS1

Function Method1()
    On Error GoTo ErrorHandler
    ...
ErrorHandler:
    If (Err.Number And vbObjectError) = vbObjectError Then
        Select Case Err.Number And (Not vbObjectError)
        Case Component2.EErrComponent2.ecBlahBlahError
            ... handle ...
        End Select
    End If
End Function

COMPONENT2.CLASS2

Enum EErrComponent2
    ecBlahBlahError = 513 ' Minimum error code
End Enum

Function Method1()
...
    Err.Raise EErrComponent1 Or vbObjectError
...
End Function

Repeat this for multiple components, this boilerplate gets a little tiresome, and doesn't seem to actually give us anything in return.

We would probably do this:

COMPONENT1.CLASS1

Function Method1()
    On Error GoTo ErrorHandler
    ...
ErrorHandler:
    Select Case Err.Number
    Case Component2.EErrComponent2.ecBlahBlahError
        ... handle ...
    End Select
End Function

COMPONENT2.CLASS2 Enum EErrComponent2 ecBlahBlahError End Enum

Function Method1()
...
    Err.Raise EErrComponent1
...
End Function

I wonder if anyone has ever had problems when not using vbObjectError. We certainly haven't.

like image 23
Mark Bertenshaw Avatar answered Nov 14 '22 12:11

Mark Bertenshaw