Error Handling & Debugging
A program with anything more than a trivial amount of code will almost inevitably contain errors (or "bugs") during its development. The types of errors commonly encountered can be categorised as follows:
- Syntax errors - these occur when a command is mis-typed or an expected argument is omitted. Visual Basic detects such errors as they occur, and will not allow the program to be run until they are corrected.
- Run-time errors - these are usually errors beyond the control of the programmer, such as the input of invalid data by the user or a missing data file. Error-trapping routines can be implemented to deal with such occurrences.
- Logic errors - this type of error is the most difficult to find, as it will not be automatically detected by visual basic. The program will often run, but may produce unexpected results. The Visual Basic debugger can be used to track down errors in the program's logic.
The incidence of errors can be reduced if care is taken with the design of the program. Time spent at the design stage may save considerably more time tracking down program errors later. Use of appropriate comments throughout the code will help you to remember what each section of code is doing, should you need to revisit the code to track down an error. The use of a consistent and meaningful naming convention for variables, controls and procedures will also aid clarity during the fault-finding process.
Although the following sections describe a number of very useful debugging tools and techniques, always look for the obvious answer before setting up some elaborate debugging procedure. If you do not know exactly where the problem is, one approach is to set a breakpoint (see below) somewhere in the middle of your program. If the program breaks before the error manifests itself, you can be fairly certain its in the second half of the program code. Otherwise, its in the first half. You can continue to narrow down the search in this way until the error is found.
Trapping and Handling Run-Time Errors
Run-time errors can be trapped, in the sense that your Visual Basic application will register the fact that an error has occurred, enabling you to take corrective action That is, Visual Basic recognizes an error has occurred and enables your program to trap it and take corrective action. If the error not handled by an appropriate error-handling procedure, your program may fall over rather unceremoniously. Error trapping is turned on using the On Error statement, as shown below:
On Error GoTo errlabel
This is about the only legitimate use of a GoTo statement. When a run-time error occurs, control is transferred to the line in the program labelled errlabel. The following code fragment illustrates the use of this mechanism:
Sub SubExample()
[Declare variables etc]
On Error GoTo HandleErrors
[Some procedure code goes here]
Exit Sub
HandleErrors:
[Error handling code goes here]
End Sub
The On Error statement follows the declaration of variables and other preliminaries within the procedure to enable error trapping. The code that implements the procedure's functionality follows the On Error statement. The error handling code itself goes at the end of the procedure, after the HandleErrors label, and is only executed if an error is encountered within the preceding code. If no errors occur, the Exit Sub statement is used to terminate execution of the procedure before the error handling code is executed. Error trapping can also be turned off within the procedure of required, using the line:
On Error GoTo 0
Visual Basic's Err object returns the number associated with the current error condition in its Number property (Err.Number). The Error() function takes this error number as its argument, and returns a string containing a description of the error. Some common error codes are listed below.
| Visual Basic Error Codes | |
| Code | Description |
| 6 | Overflow |
| 9 | Subscript out of range |
| 11 | Division by zero |
| 13 | Type mismatch |
| 16 | Expression too complex |
| 20 | Resume without error |
| 52 | Bad file name or number |
| 53 | File not found |
| 55 | File already open |
| 61 | Disk full |
| 70 | Permission denied |
| 92 | For loop not initialized |
Once an error has been trapped and dealt with, control can be returned to the application using the Resume statement. There are three options:
- Resume on its own returns control to the program at the line where the error occurred. Be aware, however, that If the error has not been corrected, it will probably re-occur, causing an infinite loop between the error handling code and the code that produced the error.
- Resume Next returns control to the program at the line immediately following that in which the error occurred.
- Resume label returns control to the program at the line identified by label.
The code listing below is generic error handling procedure that tells the user an error has occurred, provides a description of the error, and gives the user the option of Aborting the program, Retrying the operation that caused the problem, or Ignoring the error. The code can be adapted for use in your own error handling procedures.
HandleErrors:
Select Case MsgBox(Error(Err.Number), vbCritical +
vbAbortRetryIgnore, "Error Number" + Str(Err.Number))
Case vbAbort
Resume ExitLine
Case vbRetry
Resume
Case vbIgnore
Resume Next
End Select
ExitLine:
Exit Sub
The routine is only executed if an error occurs. A message box is displayed indicating the Visual Basic error number and error description. The message box provides Abort, Retry, and Ignore buttons, and returns a response that indicates which button was selected by the user. To use the above code in an existing procedure, place it at the end of the procedure, insert the statement Exit Sub line immediately before the HandleErrors label, and insert the statement On Error GoTo HandleErrors at the beginning of the procedure (as in the SubExample() code above).
You can test this error handling routine using the Raise method associated with the Visual Basic Err object, which simulates the occurrence of a run-time error. To cause an error having the number n, use:
Err.Raise n
To clear an error condition, use the Clear method:
Err.Clear
Example 1
Open a new Visual Basic project, save it to a new folder, and create a form similar to the one illustrated below.
| Control | Name | Caption | Additional Properties |
| Form | Form1 | Error Generator | BorderStyle 1-Fixed Single |
| Button | cmdGenError | Generate Error | |
| TextBox | txtError | ||
Enter the following code in the form's code window:
Private Sub cmdGenError_Click()
On Error GoTo HandleErrors
Err.Raise Val(txtError.Text)
Err.Clear
Exit Sub
HandleErrors:
Select Case MsgBox(Error(Err.Number), vbCritical + vbAbortRetryIgnore, "Error Number" + Str(Err.Number))
Case vbAbort
Resume ExitLine
Case vbRetry
Resume
Case vbIgnore
Resume Next
End Select
ExitLine:
Exit Sub
End Sub
This code generates an error message using the number entered in the text box which the user can respond to by aborting the procedure, retrying the operation or ignoring the error.
Debugging
Errors in a program's logic often do not prevent it from running, but may cause unexpected results. Visual Basic provides debugging tools to help the programmer track down such errors. The programmer's interface to the debugging tools is via three debug windows:
- the Immediate Window
- the Locals Window
- the Watch Window
These windows can be accessed from the View menu or using the Debug Toolbar (accessed using the Toolbars option in the View menu). Debugging is carried out when the application is in break mode. Break mode is entered by setting breakpoints, pressing Ctrl+Break, or when the program encounters an untrapped error or a Stop statement. In this mode, the debug windows and other tools can be used to:
- determine the value of variables
- set breakpoints
- set watch variables and expressions
- manually control the application
- determine which procedures have been called
- change the values of variables and properties
The debugging tools available in Visual Basic include breakpoints, watch points, calls, step into, step over, and step out.
Example 2
This example is simply a form with a single command button that will be used to demonstrate the use of the debugging tools. The code attached to the button's Click event is a simple loop that repeatedly calls a function.
Enter the following code in the form's code window:
Private Sub cmdClickMe_Click()
Dim X As Integer, Y As Integer
X = 0
Do
Y = Fcn(X)
X = X + 1
Loop While X <= 20
End Sub
Function Fcn(X As Integer) As Integer
Fcn = CInt(0.1 * X ^ 2)
End Function
This program passes X, which has an initial value of 0, to the function Fcn, which then computes a value for Y. Each iteration of the loop increases X by 1 until the value of X exceeds 20. Although the program does not actually do a lot, it is useful for demonstrating the debugging facilities in Visual Basic.
Using Debug.Print
The simplest debugging method is to use a Debug.Print statement to print the value of a procedure's variables to the immediate window while an application is running. To demonstrate the use of this technique, amend the code for the cmdClickMe_Click() procedure as shown below, and run the application.
Private Sub cmdClickMe_Click()
Dim X As Integer, Y As Integer
X = 0
Do
Y = Fcn(X)
Debug.Print X; Y
X = X + 1
Loop While X <= 20
End Sub
An examination of the immediate window will reveal that value of X and Y has been printed for each iteration of the loop. This information can be used to ensure that the values of these variables are correct. Once you have seen the Debug.Print statement in action, remove it from the code.
Using a Breakpoint
The above example allowed the procedure to run to completion before displaying the value of variables in the immediate window. Sometimes it is useful to be able to stop a procedure during execution, examine the value of the procedure variables, and then resume execution. This can be done with breakpoints. A breakpoint is a line in the code that causes a break in program execution.
To set a breakpoint, position the cursor in the line of code where you want the program to break, and either press the F9 key, or click the Breakpoint button on the Debug toolbar or select Toggle Breakpoint from the Debug menu. The selected line will be highlighted. When the program runs, execution will halt on lines with breakpoints to allow you to check the value of variables and expressions in the immediate window. Program execution can be resumed by pressing the F5 key, or clicking on the Run button on the toolbar. All breakpoints can be cleared by selecting Clear All Breakpoints from the Debug menu. Individual breakpoints can be toggled using Toggle Breakpoint.
To demonstrate the use of breakpoints, set a breakpoint on the X = X + 1 line in the program, and run it. When the program stops, display the immediate window and type the following line of code:
Print X;Y
The values of these variables will appear in the debug window. Now restart the application, and print the new variable values.
The locals window shows the value of the variables used by the current procedure. As execution moves from one procedure to another, the contents of the locals window will change accordingly. Repeat the breakpoint example, and this time note that the values of X and Y also appear in the locals window.
Using Watch Expressions
The Add Watch option in the Debug menu lets you set up watch expressions for your program. The watch expressions can be the values of variables, or logical expressions. The values of watch expressions are displayed in the watch window. Watch expressions can be edited using the Edit Watch option in the Debug menu.
To demonstrate the use of a watch expression, set a breakpoint on the X = X + 1 line in the program, set a watch expression for the variable X, and run the program. You will see that X appears in the watch window, and will have a new value each time the program is restarted.
Now, clear the breakpoint, add a watch on the expression X = Y, and set the Watch Type to Break When Value Is True. Now run the application, and note that it goes into break mode and displays the watch window whenever X = Y.
Using Call Stack
Selecting the Call Stack button from the toolbar (or from the View menu) will display all currently active procedures. Call stack can be useful when dealing with situations involving nested procedures, and can give you an indication of where you are in the program.
Do demonstrate the use of Call Stack, set a breakpoint on the Fcn = Cint() line and run the application, which will break at this line. Press the Call Stack button. It will tell you that you are currently in the Fcn procedure, which was called from the cmdClickMe_Click() procedure.
Using Step Into
When the program is at a breakpoint you can continue program execution one line at a time by pressing F8 or by selecting Step Into from the Debug menu. This will allow you to watch how variables change (in the locals window), or how the form changes as you step through the program. You can also execute several lines at a time by clicking on a line below the current line and pressing Ctrl+F8, or by selecting Run To Cursor from the Debug menu.
To demonstrate this technique, set a breakpoint on the Do line in the program code and run the application. When the program breaks, use the F8 key to single step through the program. You can also try using the Run To Cursor option described above.
Using Step Over and Step Out
When stepping through a program, you probably won't want to step through procedures that you already know function properly. The Step Over facility executes all the steps in a procedure together, rather than one step at a time. To step over a procedure in this manner, select Step Over from the Debug menu, or press Shift+F8.
To demonstrate the use of Step Over, single step through the program once and note what happens. Then single step through the program again until you are on the line that calls the Fcn function, and press Shift+F8. Note that the program did not single step through the function as it did the first time round.
If you are currently stepping through a procedure and wish to execute the remainder of the procedure immediately, select Step Out from the Debug menu, or press Ctrl+Shift+F8.