Browse DevX
Sign up for e-mail newsletters from DevX


Building an Application Error Handler

Since Visual Basic does not handle errors automatically, a developer has to build error handling code in the application. The objective of this Solution is to describe the key points of a basic error handling framework, using common practice experience.




Building the Right Environment to Support AI, Machine Learning and Deep Learning

untime errors can occur as a result of attempts to complete an invalid operation while the program is running. There are two causes of runtime errors: either one of the program's statements can not be properly resolved or something unexpected happened. The main goal of an error handler is to fix as many errors as possible, or at least prevent the application from crashing when the errors do occur, and provide developers with detailed information for further bug fighting.

Typically an application consists of many forms, classes and standard modules which contain quite a few Sub/Function procedures. Most of those procedures have to be provided with error handlers. It doesn't take much to notice that we have to handle the same situation with certain or unexpected errors over and over. In this case, code reusability is a big advantage. In order to be able to reuse code, use centralized error handling routines in combination with procedure level error handling code. The procedure level error handler catches the error as it occurs and records information about where in the procedure it occurred. The central error handler manages how the error is displayed to the user and logs the errors for further analysis.

Procedure Level Code
The ON ERROR statement is used to enable the error handler in every procedure. There are three different kinds of statements: ON ERROR GOTO, ON ERROR RESUME NEXT, and ON ERROR GOTO 0. We have to use one of these in order to tell the program what to do in case an error occurs.

Error handling code for a specific Error number either fixes the problem or displays a message to the user explaining what happened and what action can be taken, if any, to continue running the application. After the error has been corrected or the user has been notified, either the RESUME, RESUME NEXT, or RESUME LineLabel statements tells the program how to continue the execution.

In the case where an unexpected error has occurred, the developer needs to locate the error source. It may not be easy to do when the procedure body contains many lines of code that could have generated the error. You can use a variable called EntryPoint to split the code into several blocks where the value of EntryPoint is changed from block to block. Keeping track of EntryPoint's value helps to narrow the search bounds.

Recording the call stack is another useful tool for determining the cause for an error. The call stack contains all the procedures called up to the point of the error, so that we know how we got to the error. In order to accomplish this, we call a procedure known as the CallStackPush(strProcedure as String) at the beginning of every procedure. This call adds the name of the procedure to the call stack and at the end of procedure we call the Sub CallStackPop removing that name from the call stack. Once we have included the error handling code, the typical procedure looks like this:

ProcedureName (..) 'variables declaration section ON ERROR GOTO ErrHdl StrProcedure = "ModuleName.ProcedureName" EntryPoint = 0 CallStackPush (strProcedure) .. EntryPoint = 1 'EntryPoint is global .. ' procedure body .. EntryPoint = 2 .. CallStackPop Exit Sub ErrHdl: Select Case Err.Number Case ErrorNum1 ' error handling code for ErrorNum1 Case ErrorNum2 ' error handling code for ErrorNum2 .. Case Else ' error handling routine for unexpected errors End Select End Sub

Centralized Routines
The last purpose of the error handling routine is to log errors to a database or log file. Note that when using log files, it is a good practice to have a separate folder for the log files. For easy archiving, we include the date in the error log files' name, and we create a separate log file for each date. To avoid errors in the error handling routine itself, the existence of the folder and log file has to be examined before opening the log file for appending the error information.

The ON ERROR statement enables the routine to show an "unexpected error" message and to stop execution. Since Visual Basic automatically calls the Clear method of the Err object when it executes an ON ERROR statement, it is necessary to store Err.Number and Err.Description by passing the properties' values to the corresponding variables before the ON ERROR statement is executed. Then, all the error information and the call stack should be dumped to the log file.

Public Sub WriteError(ProcName As String, EPoint As Long) Dim sErrorNumber As String Dim sErrorDescription As String Dim sErrFile As String Dim i As Integer Dim sMsg$, starSeparator As String ' save current values of error object properties sErrorDescription = CStr(Err.Description) sErrorNumber = CStr(Err.Number) On Error GoTo ErrHdl ' seize running procedure name in stack CallStackPush ("ErrLog.WriteError") Set fs = New Scripting.FileSystemObject ' make sure the folder for error loggin exists If Not fs.FolderExists(App.Path & ErrFolder) Then fs.CreateFolder (App.Path & ErrFolder) End If ' include the current date into the errorlog file name sErrFile = ErrFolder & ErrFile & Format(Now, "yyyymmdd") & ".txt" ' make sure the errorlog file exists and open/create the file If fs.FileExists(App.Path & sErrFile) Then Set ts = fs.OpenTextFile(App.Path & sErrFile, ForAppending) Else Set ts = fs.CreateTextFile(App.Path & sErrFile) End If WriteErrorInfo ProcName, sErrorNumber, sErrorDescription ' release procedure name from stack CallStackPop MsgBox "Program Has Stopped. Unexpected Error.", vbCritical End ErrHdl: For i = 0 To CallStackSize - 1 sMsg = sMsg & CallStack(i) & vbCrLf Next i MsgBox "Unexpected Error. Source: ErrLog.WriteError" & vbCrLf & sMsg, vbCritical End Sub ' write the error info and the call stack to the error log file Private Sub WriteErrorInfo (ProcName as String, sErrorNumber as String, sErrorDescription as String) Dim i As Integer Dim starSeparator As String For i = 1 To StrLen + 5 starSeparator = starSeparator & "*" Next i ' write error message into the text file ts.WriteLine (starSeparator) ' error source procedure name ts.WriteLine ("* Source: " & ProcName) ' define procedure section containing the error ts.WriteLine ("* EntryPoint: " & EntryPoint) ts.WriteLine ("* Error Number: " & sErrorNumber) ts.WriteLine ("* Description:") ' save sErrorDescription string in predefined format ts.Write (ParseErrDescription(sErrorDescription, StrLen)) ' call cascade description ts.WriteLine ("* Error Call History: ") For i = 0 To CallStackSize - 1 ts.WriteLine ("* - " & CallStack(i)) Next i ' put the time stamp ts.WriteLine ("* Date/Time: " & Now) ts.Close End Sub

There are two ways of creating the call stack maintenance procedures: using a dynamic array or using a collection object. Which one to use is an optimization issue and is not considered in this Solution. In either case, centralized procedures are used to track the call stack, and are therefore declared as a module level global variable.

' add next element into stack using dynamic array Public Sub CallStackPush(sProcedure As String) If CallStackSize = 0 Then ReDim CallStack(0) ReDim Preserve CallStack(CallStackSize) CallStack(CallStackSize) = sProcedure CallStackSize = CallStackSize + 1 End Sub ' add next element into stack using collection object Public Sub CallStackPush(sProcedure As String) If oCallStack Is Nothing Then Set oCallStack = New Collection End If oCallStack.Add sProcedure, "key" & oCallStack.Count End Sub ' remove last element out of stack using dynamic array Public Sub CallStackPop() CallStackSize = CallStackSize - 1 If CallStackSize = 0 Then ReDim CallStack(0) Else ReDim Preserve CallStack(CallStackSize - 1) End If End Sub

' remove last element out of stack using collection object Public Sub CallStackPop() oCallStack.Remove oCallStack.Count - 1 If oCallStack.Count = 0 Then Set oCallStack = Nothing End If End Sub

This 10-Minute Solution has introduced a general approach for error handling with centralized routines. These routines contain many of the elements that developers need to use in order to create error handling code for a typical application. While ideal code does not need the error handling at all—in real life even the best developers let errors slip into their programs. Therefore, it is important that a developer pay special attention to the issue of error handling.

Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.



Thanks for your registration, follow us on our social networks to keep up-to-date