Wednesday, 6 July 2011

Runtime Error Handling

Errors that occur in your program are of three types. They are syntax errors, runtime errors and logical errors. Syntax errors are errors that occur because of improperly written statements. Main causes for syntax errors are incorrectly typed words, unmatched if statements etc. Among all, syntax errors are the easiest to detect and rectify. Logical errors are errors in the logic of the program. That means the entire program runs, but it doesn’t produce the results that are required. Logical errors are very difficult to detect and remove. Sometimes days may be passed but the errors may not be detected. So logical errors could cause nightmares. The task of finding out the errors becomes difficult proportionate to the size of the program.

Runtime errors are the errors that occur during the execution of the program and cause program to be terminated abruptly. A few examples of runtime errors are Division by Zero, File not found and Disk not ready. A good program should not be terminated abruptly. So we have to take control when a runtime error occurs and handle the errors (recover from the error).

How To Handle Runtime Errors
To handle runtime errors we have to use On Error statement. On Error statement sends control to the given label whenever a runtime error occurs in any of the statements given after On Error and before the end of the block (procedure or function).

The following are the various formats available for On Error statement.

On Error GoTo line
On Error Resume Next
On Error GoTo 0

We will discuss about last two syntaxes later. First let us concentrate on first syntax. Line is either the line number or a label that is given before the line. Whenever an error occurs in the code that is after On Error, control goes to the given label.

Let us assume we want to open a file. We take filename from user using an InputBox. If file is not opened Visual Basic, by default displays a runtime error and terminates the program. To prevent it now we want to handle runtime error that might occur during Open statement as follows:

Private Sub Command1_Click()

On Error GoTo errlabel
fn = InputBox("Enter filename")
Open fn For Input As #1
' process the file

Close #1
Exit Sub

MsgBox "File not found. Please try again"
End Sub
Listing 13.1: Handling error that might occur because of Open statement.

In the above code, if Open statement failed and resulted in a runtime error then that error is trapped by On Error statement and control is passed to errlabel label. Then given message is displayed and control comes out of procedure. If error is not trapped then an error message is displayed by Visual Basic and program is terminated.

Exit Sub statement is used to come out of procedure without entering into error handler. If Exit Sub is not given, though file is successfully processed, control goes to msgbox statement and error message is displayed. To prevent control from moving to error handler, Exit Sub statement is used.

Err Object
Err object contains information about run-time error. The information is accessed using the properties of Err object. Err object also has two methods. The following table provides information regarding each property and method.

Type Name Description
Property Number Contains the error code of the error that occurred most recently.
Description Contains error message.
Source Contains the name of the object or application that caused the error.
LastDLLError Contains the most recent system error that occurred when you call a DLL.
Method Clear Clears all property setting of Err object
Raise Raises an error. See section “User defined errors”.
Table 13.1: Properties and methods of Err object.

Err object could be used to get the exact reason for error and the source of error etc. For an example of Err object please see “Resume statement” later.

User Defined Errors
Whenever there is an error, Visual Basic raises runtime error. It is also possible to raise your own errors using Raise method of Err event.

The syntax of Raise method is:

Raise number, source, description, helpfile, helpcontext

Here is the meaning of each parameter.

Number Identifies the nature of the error. Visual Basic errors (both Visual Basic-defined and user-defined errors) are in the range 0–65535. The range 0–512 is reserved for system errors; the range 513–65535 is available for user-defined errors. When setting the Number property to your own error code in a class module, you add your error code number to the vbObjectError constant. For example, to generate the error number 513, assign vbObjectError + 513 to the Number property.
Source Name of the object or application that generated the error. When setting this property for an object, use the format projectname.classname. If source is not specified, the programmatic ID of the current Visual Basic project is used.
Description Describing the error. If unspecified, the value in Number is examined. If it can be mapped to a Visual Basic run-time error code, the string that would be returned by the Error function is used as Description. If there is no Visual Basic error corresponding to Number, the "Application-defined or object-defined error" message is used.
HelpFile The fully qualified path to the Help file in which help on this error can be found. If unspecified, Visual Basic uses the fully qualified drive, path, and file name of the Visual Basic Help file.
HelpContext The context ID identifying a topic within helpfile that provides help for the error. If omitted, the Visual Basic Help file context ID for the error corresponding to the Number property is used, if it exists.

To generate an error with error number 500, enter:

‘ clear all the properties before you raise error to clear values for ' all the properties
‘Raise error
Err.raise vbobjecterror + 500,, “Insufficient Balance”

Resume statement
Resume statement is used in error handler to resume execution after handling error. The following are the options available with Resume statement.

Resume Next
Resume line

Resume statement alone resumes execution with the statement that caused the error. For example open statement failed because of missing floppy in floppy drive. Then you can prompt user to insert floppy and reexecute the statement so that this time, the file is successfully opened.

Resume Next statement resumes execution with the next statement of the statement that caused error. For example, when a particular read statement could not read the data from a file, If you want to ignore that statement and proceed with remaining statements, use Resume Next.

Resume Label statement allows you to resume execution from the given label. This label could be anywhere in the same procedure.

Here is the previous example after adding resume statement.

Private Sub Command1_Click()
On Error GoTo errlabel
fn = InputBox("Enter filename")
Open fn For Input As #1
' process the file

Close #1
Exit Sub
Select Case Err.Number
Case 71 ' disk not ready
resp = MsgBox("Disk is not ready. Do you want to retry?", vbYesNo)
If resp = vbYes Then
Resume ' execute OPEN statement
End If
Case 53 ' file not found
resp = MsgBox("File not found. Do you want to reenter filename?", vbYesNo)
If resp = vbYes Then
Resume retry
End If
Case Else
Msgbox err.description
End Select
End Sub
Listing 13.2: Error handling with resume statement.

In the above example, we have used Err object to find out the exact problem and we have taken appropriate action. We have checked for two specific events - Disk not ready and File not found. If Disk is not ready then we have prompted user to specify whether he would like to retry. If user wants to retry then he would make disk ready and click on Yes button. Then program resumes execution with Open statement as we have used Resume statement, which resumes execution with the statement that caused the error.

If error is ‘File not found” then we are giving user a chance to reenter the file name. We have used Resume statement with a label to resume execution from retry label. Retry label is given before InputBox statement, as a result user is prompted to enter filename again.

On Error Resume
This is one of the formats available for On Error statement. This statement ignores errors and resumes execution as if no error has occurred. In this, programmer is responsible for finding out whether a statement is successful. The following is an example where we check whether Open statement is successful.

Private Sub Command1_Click ()
On Error Resume Next
Open fn For Input As #1
If Err.Number <> 0 Then
' display error message
MsgBox Err.Description
Exit Sub
End If
End Sub
Listing 13.3: Code to ignore error and continue.
On Error GoTo 0
Error trapping is automatically disabled when the procedure finishes execution. However, you can also turn off error trapping using On Error GoTo 0 statement. Once Visual Basic executes this statement, error trapping is disabled and default error handling will be enabled.

Error Propagation
When an error occurs, if error trapping is enabled in the procedure, error is handled in the procedure. But if error trapping is NOT enabled in the procedure then error will be propagated to calling procedure. And the propagation will go on until it finds an error handler in one of the calling procedure. If no error handler is found in any of the calling procedure, then a runtime error will occur.
PROC1 calls PROC2 and in turn PROC2 calls PROC3. If an error occurs in PROC3, as there is no error handler in PROC3, error is propagated to calling procedure - PROC2. As PROC2 also doesn't have error handler the error is further propagated and passed to its calling procedure - PROC1. And then, error handler in PROC1 is activated.

That means, the procedure in which error handler is found is not necessarily in the same procedure in which error occurred. This might result in unintended results. So be aware of it.