Tips: Converting existing code

Overview

Here we will describe a method of implementing the Global Error Handler in a way that blends itself closely with existing code. As such, you will find examples side by side of the 'before' and 'after' stages.

Example Global Error Handling routine

Here is the global error handling routine to use to start with for these examples:

Public Sub OnError()

    Select Case ErrEx.State
    
        Case OnErrorGoto0
            ' ---------------------------------------------------------------
            ' Unhandled errors
            ' ---------------------------------------------------------------
            LogErrorToTable
    
            ErrEx.State = ErrEx.ShowErrorDialog
            
        Case OnErrorGotoLabel
            ' ---------------------------------------------------------------
            ' Ignore locally handled errors
            ' ---------------------------------------------------------------

        Case OnErrorPropagate
            ' ---------------------------------------------------------------
            ' Ignore locally handled errors
            ' (handled by a previous routine in the call stack)
            ' ---------------------------------------------------------------
            
        Case OnErrorResumeNext
            ' ---------------------------------------------------------------
            ' Ignore errors when On Error Resume Next is set
            ' ---------------------------------------------------------------
            
        Case CalledByLocalHandler
            ' ---------------------------------------------------------------
            ' ErrEx.CallGlobalErrorHandler was called
            '
            ' This is a special case for when local error handling was in use
            ' but the local error handler has not dealt with the error and
            ' so has passed it on to the global error handler
            ' ---------------------------------------------------------------
            LogErrorToTable
                
            ErrEx.State = ErrEx.ShowErrorDialog
        
            ' ---------------------------------------------------------------
            ' NOTE:
            '
            ' Since this global error handler routine is for 'release', not
            ' 'development', we don't really want to end abruptly here.
            '
            ' So instead, we set ErrEx.Status = CalledByLocalHandler
            ' which ensures we resume after the CallGlobalErrorHandler
            ' line - where cleanup code can then be done
            ' ---------------------------------------------------------------
            ErrEx.State = CalledByLocalHandler
            
    End Select

End Sub
This routine is very typical and makes the system work similarly to the existing way VBE handles errors, albeit with many more features…

Example 1: No local error handling required

When you think about it logically, the majority of VB subroutines do not need to handle specific errors but instead just need to show a warning / error dialog when an error occurs (and perhaps log errors to a file or table).

This is the best scenario for us because we can now cut down the VB code considerably:

Before (without global error handling)

After (using global error handler)

Private Sub btnMyButton_Click()

    On Error Goto LocalErrorHandler

    DoCmd.OpenForm "ABC"

    Exit Sub

LocalErrorHandler:
    MsgBox "Error occurred in btnMyButton_Click: " & _
		Err.Description & " (" & CStr(Err.Number) & ")"
    LogErrorToTable Err.Number, Err.Description

End Sub
RightArrow
Private Sub btnMyButton_Click()

    DoCmd.OpenForm "ABC"

End Sub

As this example shows, we no longer need to provide any local error handling when you're not needing to catch specific errors.   The reason for this is that even though no local error handler has been set, our global error handling routine still gets called but with an ErrEx.State of OnErrorGoto0 which indicates no error handling has been set.

Furthermore, there's no need to pass over the name of the procedure since this information is all available from within your global error handling routine.

Benefits

  • Smaller code
  • Easier to read
  • Easier to maintain
  • All the added features of the Global Error Handler - such as reading the CallStack, automatic line numbering and live variable inspection in the procedure of error

Example 2: Catching expected errors in a local error handler

There will be times when you need to catch an expected error in your local procedure yet still show a warning / error dialog for other, unhandled errors.

With our Global Error Handler, this is very similar to how you would do this normally:

Before (without global error handling)

After (using global error handler)

Public Function IsMDE() As Boolean

On Error GoTo LocalErrorHandler

    Dim db As DAO.Database
    Set db = CurrentDb()
    
    If db.Properties("MDE") = "T" Then
    
        IsMDE = True
    
    End If

    Set db = Nothing
    
    Exit Function
    
LocalErrorHandler:
    If Err.Number = 3270 Then
        'Property Not Found
        Exit Function
    End If

    'An unexpected error has occurred
    MsgBox "Error occurred in IsMDE: " & _
		Err.Description & " (" & CStr(Err.Number) & ")"
    LogErrorToTable Err.Number, Err.Description
    
End Function
RightArrow
Public Function IsMDE() As Boolean

On Error GoTo LocalErrorHandler

    Dim db As DAO.Database
    Set db = CurrentDb()
    
    If db.Properties("MDE") = "T" Then
    
        IsMDE = True
    
    End If

    Set db = Nothing
    
    Exit Function
    
LocalErrorHandler:
    If Err.Number = 3270 Then
        'Property Not Found
        Exit Function
    End If

    'An unexpected error has occurred
    ErrEx.CallGlobalErrorHandler

End Function

This example shows that here we would change only two lines of code to get the same functionality. When our global error handler gets called at the 'ErrEx.CallGlobalErrorHandler' line, the ErrEx.State will be CalledByLocalHandler - which you can see a case statement for in our global error handler at the top of this page.

Again, there's no need to pass over the name of the procedure since this information is all available from within your global error handling routine.

Benefits

  • Easier to read
  • Easier to maintain
  • All the added features of the Global Error Handler - such as reading the CallStack, automatic line numbering and live variable inspection in the procedure of error

Example 3: Catching expected errors and cleanup code

There are also times when you need to catch an expected error, show an error dialog for unhandled errors and also ensure that open objects (such as recordsets) are closed and de-referenced properly (even when unexpected errors occur).

With the Global Error Handler, this is again perfectly feasible and very similar to how you would do this normally:

Before (without global error handling)

After (using global error handler)

Public Function IsMDE() As Boolean

On Error GoTo LocalErrorHandler

    Dim db As DAO.Database
    Set db = CurrentDb()
    
    If db.Properties("MDE") = "T" Then
    
        IsMDE = True
    
    End If

Cleanup:
    Set db = Nothing
    Exit Function

LocalErrorHandler:
    If Err.Number = 3270 Then
        ' Property Not Found
        Resume Cleanup
    End If

    'An unexpected error has occurred
    MsgBox "Error occurred in IsMDE: " & _
		Err.Description & " (" & CStr(Err.Number) & ")"
    LogErrorToTable Err.Number, Err.Description

    Resume Cleanup
    
End Function
RightArrow
Public Function IsMDE() As Boolean

On Error GoTo LocalErrorHandler

    Dim db As DAO.Database
    Set db = CurrentDb()
    
    If db.Properties("MDE") = "T" Then
    
        IsMDE = True
    
    End If

Cleanup:
    Set db = Nothing
    Exit Function
    
LocalErrorHandler:
    If Err.Number = 3270 Then
        'Property Not Found
        Exit Function
    End If

    'An unexpected error has occurred
    ErrEx.CallGlobalErrorHandler
    Resume Cleanup

End Function

Again, not much difference here. In conclusion you can see just how little effort is needed to implement the global error handler into your applications.

Benefits

  • Easier to read
  • Easier to maintain
  • All the added features of the Global Error Handler - such as reading the CallStack, automatic line numbering and live variable inspection in the procedure of error

Example 4: Catching expected errors and cleanup code (try-catch alternative)

Using a slightly different approach, you can simplify handling local errors by using our Try-Catch approach:

Before (without global error handling)

After (using global error handler)

Public Function IsMDE() As Boolean

On Error GoTo LocalErrorHandler

    Dim db As DAO.Database
    Set db = CurrentDb()
    
    If db.Properties("MDE") = "T" Then
    
        IsMDE = True
    
    End If

Cleanup:
    Set db = Nothing
    Exit Function

LocalErrorHandler:
    If Err.Number = 3270 Then
        ' Property Not Found
        Resume Cleanup
    End If

    'An unexpected error has occurred
    MsgBox "Error occurred in IsMDE: " & _
		Err.Description & " (" & CStr(Err.Number) & ")"
    LogErrorToTable Err.Number, Err.Description

    Resume Cleanup
    
End Function
RightArrow
Public Function IsMDE() As Boolean

    Dim db As DAO.Database
    Set db = CurrentDb()
    
    If db.Properties("MDE") = "T" Then
    
        IsMDE = True
    
    End If

ErrEx.Catch 3270
    ' Property Not Found - program flow
    ' will continue to Finally...

ErrEx.Finally
    Set db = Nothing
    
End Function

For more information, please refer to the Try-Catch documentation.