An error handler is a routine for trapping and responding to errors in your application. You'll want to add error handlers to any procedure where you anticipate the possibility of an error (you should assume that any Basic statement can produce an error unless you explicitly know otherwise). The process of designing an error handler involves three steps:
The On Error statement enables the trap and directs the application to the label marking the beginning of the error-handling routine.
In the Errors.vpb sample application, the FileExists function contains an error-handling routine named CheckError
.
The CheckError
routine handles the error using an If...Then...Else statement that responds to the value in the Err object's Number property, which is a numeric code corresponding to a Visual Basic error. In the example, if "Disk not ready" is generated, a message prompts the user to close the drive door. A different message is displayed if the "Device unavailable" error occurs. If any other error is generated, the appropriate description is displayed and the program stops.
In the case of the "Disk not ready" error, the Resume statement makes the code branch back to the statement where the error occurred. Visual Basic then tries to re-execute that statement. If the situation has not changed, then another error occurs and execution branches back to the error-handling routine.
In the case of the "Device unavailable" error, the Resume Next statement makes the code branch to the statement following the one at which the error occurred.
Details on how to perform these steps are provided in the remainder of this topic. Refer to the FileExists function example as you read through these steps.
An error trap is enabled when Visual Basic executes the On Error statement, which specifies an error handler. The error trap remains enabled while the procedure containing it is active — that is, until an Exit Sub, Exit Function, Exit Property, End Sub, End Function, or End Property statement is executed for that procedure. While only one error trap can be enabled at any one time in any given procedure, you can create several alternative error traps and enable different ones at different times. You can also disable an error trap by using a special case of the On Error statement — On Error GoTo 0.
To set an error trap that jumps to an error-handling routine, use a On Error GoTo line statement, where line indicates the label identifying the error-handling code. In the FileExists function example, the label is CheckError
. (Although the colon is part of the label, it isn't used in the On Error GoTo line statement.)
For More Information For more information about disabling error handling, see the topic, "Turning Off Error Handling," later in this chapter.
The first step in writing an error-handling routine is adding a line label to mark the beginning of the error handling routine. The line label should have a descriptive name and must be followed by a colon. A common convention is to place the error-handling code at the end of the procedure with an Exit Sub, Exit Function, or Exit Property statement immediately before the line label. This allows the procedure to avoid executing the error-handling code if no error occurs.
The body of the error handling routine contains the code that actually handles the error, usually in the form of a Case or If…Then…Else statement. You need to determine which errors are likely to occur and provide a course of action for each, for example, prompting the user to insert a disk in the case of a "Disk not ready" error. An option should always be provided to handle any unanticipated errors by using the Else or Case Else clause — in the case of the FileExists function example, this option warns the user then ends the application.
The Number property of the Err object contains a numeric code representing the most recent run-time error. By using 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 contained in the Err object's Description property explains the error associated with the current error number. The exact wording of the description may vary among different versions of Microsoft Visual Basic. Therefore, use Err.Number
, rather than Err.Description
, to identify the specific error that occurred.
The FileExists function example uses the Resume statement within the error handler to re-execute the statement that originally caused the error, and uses the Resume Next statement to return execution to the statement following the one at which the error occurred. There are other ways to exit an error-handling routine. Depending on the circumstances, you can do this using any of the statements shown in the following table.
Statement | Description |
Resume [0] | Program execution resumes with the statement that caused the error or the most recently executed call out of the procedure containing the error-handling routine. Use it to repeat an operation after correcting the condition that caused the error. |
Resume Next | Resumes program execution at the statement immediately following the one that caused the error. If the error occurred outside the procedure that contains the error handler, execution resumes at the statement immediately following the call to the procedure wherein the error occurred, if the called procedure does not have an enabled error handler. |
Resume line | Resumes program execution at the label specified by line, where line is a line label (or nonzero line number) that must be in the same procedure as the error handler. |
Err.Raise Number:= number | Triggers a run-time error. When this statement is executed within the error-handling routine, Visual Basic searches the calls list for another error-handling routine. (The calls list is the chain of procedures invoked to arrive at the current point of execution. See the section, "Error-Handling Hierarchy," later in this chapter.) |
The difference between Resume and Resume Next is shown in Figure 13.1.
Figure 13.1 Program flow with Resume and Resume Next
Generally, you would use Resume whenever the error handler can correct the error, and Resume Next when the error handler cannot. You can write an error handler so that the existence of a run-time error is never revealed to the user or to display error messages and allow the user to enter corrections.
For example, the Function procedure in the following code example uses error handling to perform "safe" division on its arguments without revealing errors that might occur. The errors that can occur when performing division are:
Error | Cause |
"Division by zero" | Numerator is nonzero, but the denominator is zero. |
"Overflow" | Both numerator and denominator are zero (during floating-point division). |
"Illegal procedure call" | Either the numerator or the denominator is a nonnumeric value (or can't be considered a numeric value). |
In all three cases, the following Function procedure traps these errors and returns Null:
Function Divide (numer, denom) as Variant
Dim Msg as String
Const mnErrDivByZero = 11, mnErrOverFlow = 6
Const mnErrBadCall = 5
On Error GoTo MathHandler
Divide = numer / denom
Exit Function
MathHandler:
If Err.Number = MnErrDivByZero Or _
Err.Number = ErrOverFlow _
Or Err = ErrBadCall Then
Divide = Null ' If error was Division by
' zero, Overflow, or Illegal
' procedure call, return Null.
Else
' Display unanticipated error message.
Msg = "Unanticipated error " & Err.Number
Msg = Msg & ": " & Err.Description
MsgBox Msg, vbExclamation
End If ' In all cases, Resume Next
' continues execution at
Resume Next ' the Exit Function statement.
End Function
Resume Next can also be used where an error occurs within a loop, and you need to restart the operation. Or, you can use 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 FileExists example shown earlier, this function allows the user to enter a file specification that the function returns if the file exists.
Function VerifyFile As String
Const mnErrBadFileName = 52, _
mnErrDriveDoorOpen = 71
Const mnErrDeviceUnavailable = 68, _
mnErrInvalidFileName = 64
Dim strPrompt As String, strMsg As String, _
strFileSpec As String
strPrompt = "Enter file specification to check:"
StartHere:
strFileSpec = "*.*" ' Start with a default
' specification.
strMsg = strMsg & vbCRLF & strPrompt
' Let the user modify the default.
strFileSpec = InputBox(strMsg, "File Search", _
strFileSpec, 100, 100)
' Exit if user deletes default.
If strFileSpec = "" Then Exit Function
On Error GoTo Handler
VerifyFile = Dir(strFileSpec)
Exit Function
Handler:
Select Case Err.Number ' Analyze error code and
' load message.
Case ErrInvalidFileName, ErrBadFileName
strMsg = "Your file specification was "
strMsg = strMsg & "invalid; try another."
Case MnErrDriveDoorOpen
strMsg = "Close the disk drive door and "
strMsg = strMsg & "try again."
Case MnErrDeviceUnavailable
strMsg = "The drive you specified was not "
strMsg = strMsg & "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
Resume StartHere ' This jumps back to StartHere
' label so the user can try
' another file name.
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 is assigned to the strMsg
variable and execution jumps back to the label StartHere
. This gives the user another chance to enter a valid path and file specification.
If the error is unanticipated, the Case Else segment regenerates the error so that the next error handler in the calls list can trap the error. This is necessary because if the error wasn't regenerated, the code would continue to execute at the Resume StartHere
line. By regenerating the error you are in effect causing the error to occur again; the new error will be trapped at the next level in the call stack.
For More Information For more details, see "Error Handling Hierarchy" later in this chapter.
Note Although using Resume line is a legitimate way to write code, a proliferation of jumps to line labels can render code difficult to understand and debug.