QuickStart: The Global Error Trap
On this page you'll find:
Enabling and disabling your global error handler
vbWatchdog can be enabled with or without defining a global error handler. To enable a global error handler, you call ErrEx.Enable, passing the name of your global error handler subroutine as a string parameter:
Public Sub EnableWatchdog()
Call 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 (module/procedure name etc), logging the details and displaying the main error dialog.
The GlobalErrorTrap subroutine should be defined in a standard VBA module and must be declared as Public scope.
Now let's see how we access some of these features by discussing the basics of the ErrEx class.
Identifying the location of error
Inside of your global error handling routine, you can determine the location of the error being handled by reading these ErrEx properties:
| .SourceProcedure | Returns the name of the procedure that caused the error |
| .SourceModule | Returns the name of the module where the procedure resides |
| .SourceProject | Returns the name of the VBA project where the procedure resides |
| .SourceLineNumber | Returns the debug line number of the error. See QuickStart: Automatic line numbering. |
| .SourceLineCode | Returns the debug line of the error. See QuickStart: Automatic line numbering. Note that this property will return an empty string if the source code is not accessible (e.g. for an Access MDE/ACCDE file). |
The ErrEx.State property
The ErrEx.State property is for use inside of your global error handler. 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:
| OnErrorGoto0 | indicates no specific error handling has been set (or 'On Error Goto 0') |
| OnErrorResumeNext | indicates ‘On Error Resume Next’ was set |
| OnErrorGotoLabel | indicates ‘On Error Goto X’ was set |
| OnErrorPropagate | indicates ‘On Error Goto X’ was set in a previous procedure in the stack (which will subsequently catch this error) |
| CalledByLocalHandler | Special case, see Handling Errors Locally |
You can then (optionally) change the ErrEx.State value to any of the following values. Once your global error handler has returned, vbWatchdog checks the ErrEx.State value that you have set, and takes appropriate action:
| OnErrorGoto0 | The vbWatchdog error dialog will be invoked. However, it is advised to use the explicit ErrEx.ShowErrorDialog method instead. |
| OnErrorResumeNext | The code will resume at the next source line below the line of error. |
| OnErrorRetry | This is the equivalent of using 'Resume' in a local error handler in order to try the repeat the offending line to try again. Useful for connection time-out issues etc. Warning: Use this state with caution to prevent a loop forming for permanent errors. |
| OnErrorGotoLabel | The code will resume at the label that was declared in the local procedure. |
| OnErrorPropagate | The code will resume at the label that was declared in a previous local procedure in the call stack - see Error Propagation. 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). |
| OnErrorDebug | The VBE will break at the line of source code that caused the error. Only valid when source code is available. This is the same as the ‘Debug’ button on the standard VBE error dialog. Not available for compiled Access MDE/ACCDE applications - use the IsDebugable property to determine if the debug option is available at runtime. |
| OnErrorEnd | The 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). |
| OnErrorExitProcedure | This is the equivalent of using 'Exit Sub' or 'Exit Function' in a local error handler. |
| CalledByLocalHandler | Special case, see Handling Errors Locally |
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
Call 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, you can call 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 call 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
| .ShowHelp | This method simply opens the help file associated with the error (as given by ErrEx.HelpFile and ErrEx.HelpContext). |
| .UserData | Read/Write variant property. Use this Variant storage property 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. |
| .IsDebugable | This boolean property should be used when creating your own error dialogs (e.g. by using an Access form).
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 occured in the immediate window then this property will be False but for most other times the property value will be True. |
| .Version | This string property returns the vbWatchdog version information in format "X.X.X". |
| .VBEVersion | This string property returns the DLL version information for VBE6.DLL (or VBE7.DLL) file in the format "X.X.X.X" |
.VariablesInspectorEnabled (VBA edition only) | Boolean 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. |
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 class 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.