QuickStart: The Global Error Trap

Enabling and disabling your global error handler

To enable vbWatchdog, you simply call ErrEx.Enable(), passing the name of your global error handler subroutine as a string parameter:

Public Sub EnableWatchdog()
    
    ErrEx.Enable "GlobalErrorTrap"
     
End Sub

Public Sub GlobalErrorTrap()

    ' ... this subroutine is now automatically called whenever 
    ' an exception occurs in your code

End Sub

The most common use for the global error trap is to identify the location of the error (e.g. module/procedure name), logging the details and displaying an error dialog if necessary.

The GlobalErrorTrap subroutine must be defined in a standard VBA code module (except for classic VB6 users, who must read this instead).

Now let's see how we access some of the features available in vbWatchdog by discussing the basics of the ErrEx object.

Identifying the location of error

Inside of your global error trap, you can determine the location of the error that occurred by reading the following ErrEx object properties:

.SourceProcedureReturns the name of the procedure that caused the error
.SourceModuleReturns the name of the module where the procedure resides
.SourceProjectReturns the name of the VB project where the procedure resides
.SourceLineNumberReturns the debug line number of the error. See QuickStart: Automatic line numbering.
.SourceLineCodeReturns the actual line of code that caused the error, in a string.  Note that this property will return an empty string if the source code is not accessible, so use SourceLineNumber instead in those situations (e.g. for an Access MDE/ACCDE file).
.SourceProjectFilenameReturns the VB project filename associated with the error.
.SourceProjectConditionalCompilationArgsReturns the compiler conditional arguments associated with the VB project.
.SourceProjectIsCompiled [VBA only]Returns a boolean value indicating the compilation state of the project associated with the error.
.SourceProjectIsSaved [VBA only]Returns a boolean value indicating whether all of the VBA modules in the VBA project are saved (not being edited).
.SourceVBEProject [VBA only]Returns the VBE object (from the Extensibility Library) associated with the error.

The ErrEx.State property

The ErrEx.State property is arguably the most important property, and is used inside of your global error trap.  It defines what will happen next after your error handler has finished executing.

Initially, when your error handler is called, the ErrEx.State property indicates what state the local error handling was in before the error occurred.  If you wish to change how an error is to be handled from within your global error handler, then you can do so by changing the ErrEx.State value.

ErrEx.State can be one of five values when your global error handler is called:

OnErrorGoto0indicates no specific error handling has been set (or 'On Error Goto 0')
OnErrorResumeNextindicates ‘On Error Resume Next’ was set
OnErrorGotoLabelindicates ‘On Error Goto X’ was set
OnErrorPropagateindicates ‘On Error Goto X’ was set in a previous procedure in the stack (which will subsequently catch this error)
CalledByLocalHandlerSpecial case, see A typical implementation of a global error handler

vbWatchdog gives you the power to change the ErrEx.State value to any of the following values, which gives you the possibility of truly 'handling' an error at a global level, if you wish or need to do so.  Once your global error trap routine has returned, vbWatchdog checks the ErrEx.State value that you have set, and takes the appropriate action:

OnErrorGoto0The vbWatchdog error dialog will be invoked.  However, it is advised to use the explicit ErrEx.ShowErrorDialog method instead.
OnErrorResumeNextExecution will resume at the next line of code below the line of error.
OnErrorRetryExecution will resume at the line of error, causing the line of error to be re-executed.  This is the equivalent of using 'Resume' in a local error handler in order to try the repeat the offending line to try again.  This is useful for connection time-out issues etc.  Warning: Use this state with caution to prevent a loop forming for permanent errors.
OnErrorGotoLabelExecution will resume at the label that was declared in the local procedure.
OnErrorPropagateExecution will resume at the label that was declared in a local procedure further up the call stack - see Error Propagation.  This state can only be set if there is a previous call in the callstack that has active local error handling (i.e. OnErrorPropagate would be the ErrEx.State value on entry to your global handler).
OnErrorDebugThe VBE debugger will break at the line of code that caused the error.  This state is only valid when source code is available. This has the same effect as the ‘Debug’ button on the standard VBE error dialog. This state is not available for compiled Access MDE/ACCDE applications - use the ErrEx.IsDebugable property to determine if the debug option is available at runtime.
OnErrorEndThe code will end abruptly. Any code that was due to execute immediately after the line that caused the error will not execute. This acts the same as the ‘End’ button on the standard error dialog. For Access MDE/ACCDE applications, this doesn't reset global variables (same behaviour as old VBE).
OnErrorUnwind [v3+]The callstack will be unwound in a controlled manner. Global variables will not lose their values, and any ErrEx.Finally blocks that are defined in the callstack will be executed. The error itself is not propagated, which can be particularly useful for preventing the Access Runtime from shutting down on unhandled VBA errors.
OnErrorUnwindNoFinally [v3+]As per OnErrorUnwind, but any ErrEx.Finally blocks will not be executed.
OnErrorExitProcedureThis is the equivalent of using 'Exit Sub' or 'Exit Function' in a local error handler.  This can be useful if you consistently use a Boolean return value to indicate success/failure in every function inside your project, as you can then use this state to pass the default return value back to the caller on error.
CalledByLocalHandlerSpecial case, see A typical implementation of a global error handler

Showing the vbWatchdog error dialog

One of the great features of the vbWatchdog is the customizable error dialog.  This can be invoked by calling the ErrEx.ShowErrorDialog method from within your global error handler.  ErrEx.ShowErrorDialog also conveniently returns a value that can be assigned directly to the ErrEx.State property (OnErrorEnd, OnErrorResumeNext, etc)

Public Sub GlobalErrorTrap()

    ErrEx.State = ErrEx.ShowErrorDialog()

End Sub

For more details on customizing the error dialog, see QuickStart: Customizing the Error Dialog.

A typical implementation of a global error handler

Typically, your global error handler will have a simple select-case statement that determines what the current state of the local error handling is, so that we can decide what to do next.

For example, when you set "On Error Goto XYZ" in your general code and an exception occurs, your global error handler will be invoked with an ErrEx.State value of OnErrorGotoLabel.  In this case, you probably just want to pass this error on to the defined local error handler, and to do this you simply ensure that the ErrEx.State value isn't altered inside of your global error handler, and vbWatchdog will then pass the error on to your local error handler.

Additionally, if you later decide from inside your local error handler that you actually want to pass the error back to the global error handler again (for example, to display the error dialog), then you can call ErrEx.CallGlobalErrorHandler, which re-calls your global error handler with a special ErrEx.State value of CalledByLocalHandler.  This gives you the opportunity to do some specific processing at the local level when an error occurs, whilst still being able to use the features of the global error handler.

Public Sub GlobalErrorTrap()

    Select Case ErrEx.State

	Case OnErrorGoto0, CalledByLocalHandler

            LogErrorToTable ' See Sample.MDB for LogErrorToTable (in module ModOnError), or LogErrorToFile 
            ErrEx.State = ErrEx.ShowErrorDialog

	Case OnErrorGotoLabel, OnErrorPropagate, OnErrorResumeNext

            ' Do nothing...  perhaps log the error if you wish.

    End Select

End Sub

Public Sub Example()

    On Error Goto MyLocalErrorHandler

    Debug.Print 1/0	' Raise an error
    Exit Sub

MyLocalErrorHandler:
    If Err.Number = 11 Then ' Division by zero error
        Resume Next
    Else
        ErrEx.CallGlobalErrorHandler    ' Call the global error handler
    End If

End Sub

In this example, the local error handler is handling local errors (division by zero in this example) and also passing any unhandled errors back on to the global error handler.  Tip: To obtain a thorough understanding of this approach, the best advice is to copy the above example code into a VBA application, set a break point on it and step through the code line by line.

For taking this a step further and ensuring that all open objects (e.g. recordsets) are closed when an error occurs, see Demo 2 of the Sample.mdb.

Tip: An alternative approach to handling errors locally is to use the Try-Catch feature of vbWatchdog.

Reading the callstack

vbWatchdog provides two ways to read the callstack.

The first is from within your global error handling subroutine, where you can read the ErrEx.CallStack object properties to iterate through the details of the callstack relating to the error being dealt with.

The second method is from anywhere in your application you can read the ErrEx.LiveCallstack object properties to iterate through the details of the current callstack.  The difference, for example, would be that using the ErrEx.LiveCallstack from inside global error handler would include the global error handler at the top of the callstack, whereas the ErrEx.Callstack object has the procedure of error at the top of the call stack.

For more details, please see Reading the callstack

Other features of ErrEx

.ShowHelpThis method simply opens the help file associated with the error (as given by ErrEx.HelpFile and ErrEx.HelpContext).
.UserDataRead/Write variant property. Use this Variant property as storage if you want to pass an argument to your global error handler from your local procedure code.

This property is automatically cleared after your global error handler next completes.
.IsDebugableThis boolean property should be used when creating your own error dialogs to enable/disable the 'debug' button

Use it to determine if you are able to break into the source code at runtime. For example, in MDE compiled Access applications, and VB6 compiled applications, this property will be False. Similarly if the error occurred in the immediate window then this property will be False but for most other times the property value will be True.
.VersionThis string property returns the vbWatchdog version information in the format "X.X.X".
.VBEVersionThis string property returns the DLL version information of the VB engine in the format "X.X.X.X"
.VariablesInspectorEnabledBoolean property - default value is True.

This property determines whether or not the VariablesInspector is active. Due to the nature of the VariablesInspector feature, it adds extra workload which gets performed when the VariablesInspector object is initially accessed when an error occurs. Typically the overheads incurred are so small that they are not worth worrying about - but in extreme cases (e.g. if you have thousands of variables in procedures) then you may wish to turn off the feature entirely here.
.TypeInfoInspectorEnabled [v3+]Boolean property - default value is True.

When True, the vbWatchdog VariablesInspector further inspects generic Object and Variant data types to determine the real underlying object type (which is then provided in variables dumps and the TypeDesc property of the variables inspector).  Also, this option allows vbWatchdog to determine array boundaries and outputs the extra information in the ValueDesc property… e.g. {ARRAY}(1 to 6) rather than just {ARRAY}.
.LoadedDLLs [v3+]String read-only property.

Provides a dump of the names, paths and version numbers of all DLLs currently loaded by the running application process
.ProjectFilterList Read/Write String property

vbWatchdog includes a filter that can be used to ignore errors from certain VBA projects.  Without a filter, the Wizards used by Microsoft Access also use VBA, and as such, errors (whether handled or not) would ordinarily pass through your global error handler.

The filter list is a string list of VBA project names, each separated by a semi-colon and the list is primarily used to prevent errors from the Access wizards from passing through to your global error handler.

Tips

  • When using a global error trap, use local error handling inside of it to catch errors that may occur during execution.  Errors that occur inside your global error trap do not get passed on to the global error trap (to prevent recursion issues).
  • Always use the ErrEx object inside of your global error handler routine instead of Err.  If an error occurs inside of your global error handler, then Err will be affected, wheras ErrEx always refers to the current error being handled.