Using On Error Statements

You can handle Visual Basic run-time errors by adding On Error statements and error-handling code to your procedures. For example, the event procedures created by Microsoft Access wizards include On Error statements and error-handling code. The following Click event procedure created by a control wizard shows how many of the procedures created by wizards handle errors.

Private Sub Button1_Click()
	
	Dim strDocName As String

	On Error GoTo Err_Button1_Click

	strDocName = "ProductsPopUp"
	DoCmd.OpenForm strDocName

Exit_Button1_Click:
	Exit Sub

Err_Button1_Click:
	MsgBox Err.Description
	Resume Exit_Button1_Click
End Sub

In this code, the On Error statement turns on error handling. If an error occurs, Visual Basic branches (passes program control) to the Err_Button1_Click line label, which marks the beginning of the error-handling code. It then runs the MsgBox statement, displaying the error’s message string. Visual Basic then runs the Resume statement to exit the error-handling code, branching to the Exit_Button1_Click line label. Finally, Visual Basic runs the Exit Sub statement to exit the Button1_Click procedure.

See Also   For information on line labels, search the Help index for “GoTo statement.”

If no error occurs, Visual Basic runs each line of code until it reaches the Exit Sub statement and then exits the procedure. It doesn’t run the Err_Button1_Click error-handling code that follows.

If your application doesn’t handle Visual Basic run-time errors, users may be surprised if a run-time error suddenly halts the application. It’s especially important to handle Visual Basic errors if you’re creating a run-time version of your application. A run-time application shuts down if an untrapped error occurs.

See Also   For information on creating a run-time version of your application, see Chapter 15, “Delivering Your Application.”

For example, the following procedure doesn’t contain error-handling code. It returns True (– 1) if the specified file exists and False (0) if it doesn’t exist.

Function FileExists (ByVal strFileName As String) As Boolean
	FileExists = (Dir(strFileName) <> "")
End Function

The Dir function returns the first file matching the specified file name, and returns a zero-length string ("") if no matching file is found. The code appears to cover either of the possible outcomes of the Dir call. However, if the drive letter specified in the argument isn’t a valid drive, the run-time error message “Device unavailable” is displayed. If the specified drive is a floppy disk drive, this function works correctly only if a disk is in the drive and the drive door is closed. If not, the run-time error “Disk not ready” occurs. In both cases, Microsoft Access displays the error message and halts execution of the code.

To avoid this situation, you can use an On Error statement to respond to Visual Basic errors and take corrective action. For example, device problems such as an invalid drive or an empty floppy disk drive can be handled by the following code:

Function FileExists (ByVal strFileName As String) As Boolean
	Dim strMsg As String

	On Error GoTo CheckError							' Turn on error handling.
	FileExists = (Dir(strFileName) <> "")	' Use Dir function to see 
															' if file exists.

	Exit Function										' Avoid running error-handling
															' code if no error occurs.

CheckError:												' Run following code 
															' if error occurs.
	' Declare constants to represent Visual Basic error codes.
	Const conErrDiskNotReady = 71, conErrDeviceUnavailable = 68
	' vbExclamation, vbOK, vbCancel, vbCritical, and vbOKCancel are
	' intrinsic constants that don't need to be declared.

	If (Err.Number = conErrDiskNotReady) Then
		' Display message box with an exclamation point icon and with 
		' OK and Cancel buttons.
		strMsg = "Put a floppy disk in the drive and close the drive door."
		If MsgBox(strMsg, vbExclamation + vbOKCancel) = vbOK Then
			Resume
		Else
			Resume Next
		End If
	ElseIf Err.Number = conErrDeviceUnavailable Then
		strMsg = "This drive or path does not exist: " & strfilename
		MsgBox strMsg, vbExclamation
		Resume Next
	Else
		strMsg = "Error number " & Str(Err.Number) & " occurred: " & _
			Err.Description
		' Display message box with stop sign icon and OK button.
		MsgBox strMsg, vbCritical
		Stop
	End If
	Resume
End Function

This code uses properties of the Err object to return the error code number and the message string associated with the run-time error that occurred.

When Visual Basic generates the error “Disk not ready,” the FileExists function displays a message telling the user to click one of two buttons, OK or Cancel. If the user clicks OK, the Resume statement returns program control to the statement at which the error occurred and attempts to run that statement again. This statement succeeds if the user has corrected the problem; otherwise, the program returns to the error-handling code.

See Also   For more information on the methods and properties of the Err object, search the Help index for “Err object.”

If the user clicks Cancel, the Resume Next statement returns program control to the statement following the one at which the error occurred, in this case, the Exit Function statement.

If the “Device unavailable” error occurs, Visual Basic displays a message describing the problem. The Resume Next statement then returns program control to the statement following the one at which the error occurred.

If an unanticipated error occurs, Visual Basic displays an alternative message and halts the code at the Stop statement.

See Also   For more information on using the Stop statement for error handling, see “Guidelines for Complex Error Handling” later in this chapter.

The error-handling code in the preceding example involves three steps:

  1. Turn on error handling, and set (enable) an error trap by telling the application where to branch (which error-handling routine to run) when an error occurs.

    The On Error statement in the FileExists function turns on error handling and directs the application to the CheckError line label.

  2. Write error-handling code that responds to all errors you can anticipate. If program control actually branches to the error-handling code at some point, the trap is then said to be active.

    The CheckError code handles the error by using an If...Then...Else statement that checks the value returned by the Number property of the Err object. The Number property of the Err object returns an error code number corresponding to the error message that Visual Basic generates. In the example, if the “Disk not ready” error is generated, a message prompts the user to close the drive door. A different message is displayed if the “Device unavailable” error occurs.

    Your code should also determine what action to take if an unanticipated error occurs. In the previous FileExists function, if any error other than “Disk not ready” or “Device unavailable” occurs, a general message is displayed and the program stops.

  3. Exit the error-handling code.

    In the case of the “Disk not ready” error, the Resume statement passes program control back to the statement at which the error occurred. Visual Basic then tries to run that statement again. If the situation hasn’t changed, then the same error occurs again, and execution branches back to the error-handling code.

    In the case of the “Device unavailable” error, the Resume Next statement passes program control to the statement following the one at which the error occurred.

The following sections describe in detail how to perform these steps. Refer to the FileExists function in this section as you read.

Setting the Error Trap

The first step in writing error-handling code is creating an On Error statement, which specifies the next line of code to run if an error occurs. Use the syntax On Error GoTo line, where line indicates the line label identifying the error-handling code. Running the On Error statement turns on error handling and enables an error trap. The error trap remains enabled while the procedure containing it is active; that is, until an Exit Sub, Exit Function, End Sub, or End Function statement is run for that procedure. You can disable error handling in the current procedure by using another form of the On Error statement, On Error GoTo 0.

See Also   For more information on disabling error handling, see “Turning Off Error Handling” later in this chapter.

Writing Error-Handling Code

Begin the error-handling code with the line label specified in the On Error statement. In the FileExists function, the line label is CheckError. The colon is part of the label, although it isn’t used in the On Error GoTo line statement.

You’ll usually include error-handling code at the end of a procedure, before the End Function or End Sub statement. Enter an Exit Function, Exit Sub, or Exit Property statement at the end of the main procedure code, but immediately preceding the error handler’s line label. This prevents Visual Basic from running the error-handling code at the conclusion of the main-procedure code if no error occurs.

The Number property of the Err object returns an error code number representing the most recent run-time error. By using the Number property of the Err object in combination with the Select Case or If...Then...Else statement, you can take specific action for any error that occurs.

Note   The string returned by the Description property of the Err object always explains the error associated with the current error code number. However, the exact wording of the message may vary among different versions of Microsoft Access. Therefore, use the Number property rather than the Description property to identify the specific error that occurred.

When designing your error-handling routine, include code that tells the user what the problem is and how to proceed. Also, if the application can’t continue after an error is encountered, it’s a good idea to close open objects, remote connections, and database files when you exit the application.

Exiting Error-Handling Code

The preceding FileExists function uses the Resume statement within the error-handling code to rerun the statement that caused the error, and uses the Resume Next statement to resume execution at the statement following the one at which the error occurred. Depending on the circumstances, there are other ways to exit error-handling code; regardless of which way you exit, you should always tell the error handler what to do when its execution is complete. To exit error-handling code, use any of the statements shown in the following table.

Statement Description
Resume Resumes program execution starting with the statement that caused the error.
Resume Next Resumes program execution at the statement immediately following the one that caused the error.
Resume line Resumes program execution at the label specified by line, where line is a line label that must be in the same procedure as the error handler.
Err.Raise Number:= number Triggers the most recent run-time error again. When this statement is run within error-handling code, Visual Basic searches backward through the calls list for other error-handling code. The calls list is the chain of procedures that lead to the current point of execution. For more information, see “Unanticipated Errors” later in this chapter.

The Resume and Resume Next Statements

You can use the Resume and Resume Next statements to perform similar functions. The Resume statement returns program control to the statement that caused the error. You use it to rerun the statement after correcting the error. The Resume Next statement returns program control to the statement immediately following the one that caused the error. The difference between Resume and Resume Next is shown in the following illustration.

Generally, you use the Resume statement whenever the user must make a correction. Use the Resume Next statement whenever a correction by the user isn’t required, and you want to continue program execution without attempting to rerun the statement that caused the error. You can also use the Resume Next statement if you anticipate an error in a loop, and you want to start the loop operation again if an error occurs. With the Resume Next statement, you can write error-handling code so that the existence of a run-time error isn’t revealed to the user.

For example, the following Divide function uses error handling to perform division on its numeric arguments without revealing errors that have occurred. There are several errors that can occur in division. If the numerator is not zero, but the denominator is zero, Visual Basic generates the “Division by zero” error; if both numerator and denominator are zero in floating-point division, it generates the “Overflow” error; or if either the numerator or the denominator is a nonnumeric value (or can’t be considered a numeric value), Visual Basic displays an appropriate error message. In all three cases, the Divide function traps these errors and returns the Null value.

Function Divide (Numerator, Denominator) As Variant
	
	Const conErrDivo = 11, conErrOverflow = 6, conErrIllFunc = 5

	On Error GoTo MathHandler 

	Divide = Numerator / Denominator
	Exit Function

MathHandler:
	' If error was Division by zero, Overflow, or 
	' Illegal function call, return Null.
	If Err.Number = conErrDivo Or Err.Number = conErrOverflow Or _
		Err.Number = conErrIllFunc Then
		Divide = Null		
	Else
		MsgBox "Unanticipated error " & Err.Number & ": " & _
			Error.Description, vbExclamation
	End If					
	' In all cases, Resume Next continues execution at the 
	' Exit Function statement.
	Resume Next				
End Function

The Resume line Statement

Alternatively, you can use the syntax Resume line, which returns control to a specified line label. The following example illustrates the use of the Resume line statement. A variation on the preceding FileExists function, the following VerifyFile function enables the user to enter a file specification that the function returns if the file exists.

Function VerifyFile () As Variant
	
	Const conErrBadFileName = 52, conErrDriveDoorOpen = 71
	Const conErrDeviceUnavailable = 68, conErrInvalidFileName = 64

	Dim strPrompt As String, strMsg As String, strFileSpec As String

	On Error GoTo Handler

	strPrompt = "Enter file specification to check:"

StartHere:
	strFileSpec = "*.*"							' Start with a default spec.
	strMsg = strMsg & vbCrLf & strPrompt
	' Let the user modify the default.
	strFileSpec = InputBox(strMsg, "File Search", strFileSpec, 100, 100)
	' Exit if the user enters nothing.	
	If strFileSpec = "" Then Exit Function	
	VerifyFile = Dir(strFileSpec)
	Exit Function

Handler:
	Select Case Err.Number						' Analyze error code, then load message.
		Case conErrInvalidFileName, conErrBadFileName
			strMsg = "Your file specification is invalid. Try another."
		Case conErrDriveDoorOpen
			strMsg = "Close the disk drive door and try again."
		Case conErrDeviceUnavailable
			strMsg = "The drive you specified was not found. Try again."
		Case Else
			Dim intErrNum As Integer			

			intErrNum = Err.Number
			Err.Clear									' Clear the Err object.
			Err.Raise Number:=intErrNum		' Regenerate the error.
	End Select
	' This jumps back to the StartHere label so the user can 
	' try another file name.
	Resume StartHere	
End Function				

If a file matching the specification is found, the function returns the file name. If no matching file is found, the function returns a zero-length string (""). If one of the anticipated errors occurs, a message appropriate to the error is assigned to Msg and execution branches to the StartHere line label. This gives the user another chance to enter a valid path and file specification.

Use the Resume line statement when you want to resume execution at a place other than the statement that caused the error, or the line immediately after the statement that caused the error. The Resume line statement can be especially useful if you want to exit the error-handling code and branch to a point just before an Exit statement in a Function or Sub procedure.

Note   Although branching to a line label can be useful in some circumstances, jumps to labels are often considered throwbacks to a less structured style of programming. Too many Resume line statements can make code difficult to understand and debug.

The Raise Method

The previous VerifyFile function also illustrates how to use the Raise method of the Err object to regenerate an unanticipated Visual Basic error within the error-handling routine itself. This causes Visual Basic to search backward through the calls list (if there is one) for error-handling code.

See Also   For more information on this process, see the following section, “Unanticipated Errors.”

If you haven’t included appropriate code to handle the error that has occurred, Visual Basic halts execution and displays an error message. The Raise method only returns descriptive strings for Visual Basic errors. If you use the Raise method to regenerate a Microsoft Access error, then you can use the AccessError method of the Application object to return a descriptive string for the error.

See Also   For more information on the AccessError method, search the Help index for “AccessError method.”