--> (Word) | --> (PDF) | --> (Epub) | --> (Text) |
--> (XML) | --> (OpenOffice) | --> (XPS) | --> (MHT) |
Despite your best efforts to cover all possible contingencies, run-time errors will occur in your applications. You can and should do all you can to prevent them, but when they happen you have to handle them.
Introduction
The various functions, statements, properties and methods available in Visual Basic and the components used in Visual Basic expect to deal with certain types of data and behavior in your applications. For example, the CDate() function can convert a value to a Date [gs variable]. The function is remarkably flexible in the type of information it can accept, but it expects to receive data that it can use to derive a date. If you provide input that it can't convert, it raises error number 13 - "Type mismatch" - essentially saying "I can't handle this input data".
In an application, this type of error may be a program logic error (you simply passed the wrong data) or it may be a data entry error on the part of the user (you asked for a date and the user typed a name). In the first case, you need to debug the program to fix the mistake. However, there is no way for you to anticipate the behavior of the end users of the application. If the user enters data you can't handle, you need to deal with the situation.
Dealing with errors at run-time is a two step process:
In addition to dealing with run-time errors, you may at times want to generate them. This is often done in class modules built as components of ActiveX server DLLs or EXEs. It is considered good programming practice to separate the [gs user] interface from the program [gs logic] as much as possible, so if a [gs server] component cannot deal with an error, it should raise the error in its client application rather than simply display an error message for the user.
In VB5, there is an option that allows you to specify that an application has been designed for unattended execution (this is typically used for remote server applications). If you plan to allow the application to run unattended or on a remote computer, you can't simply display an error message because there will be nobody there to see it or dismiss the message box.
Trapping Errors at Run-Time
Before you can do anything to deal with a run-time error, you need to capture the error. You use the On Error statement to enable an error trap. On Error will redirect the execution in the event of a run-time error. There are several forms of the On Error statement:
It's not necessary to code an error handling routine in every procedure you write in Visual Basic. If an error is raised in a procedure, VB will work its way back up through the call tree looking for an error handler.
Public Sub SubA()
On Error Goto ProcError
' other code
MsgBox FuncA()
ProcExit:
Exit Sub
ProcError:
MsgBox Err.Description
Resume ProcExit
End Sub
Private Function FuncA() As Date
FuncA = CDate("hi there")
End Function
In this example, procedure SubA enables an error handler using the statement On Error Goto ProcError. When function FuncA is called in the MsgBox statement, the On Error Goto ProcError handler is still enabled.
The CDate function in FuncA will generate error 13 (type mismatch) because CDate can't make a date from the input data. VB first looks in FuncA for an error handler. None was enabled, so the error is propogated back up the call tree to SubA. Since there is an error handler in SubA, program execution is redirected to the ProcError label in SubA. The MsgBox statement displays a description of the error and the Resume statement directs VB to continue execution at the ProcExit label.
There are some situations where VB cannot pass an error back up the call tree. This applies to Sub Main, most event procedures, and the Class_Terminate event procedure. Sub Main (if defined in the project property sheet) is the first code executed, so there is no procedure higher in the tree at application startup time. Most event procedures are also fired by Visual Basic when no other code is running so these are also at the top of the tree. Finally, the Class_Terminate event of class modules cannot raise an error because this event can also occur when no other code is executing in the application.
If an error is generated in one of these types of procedures and no error handler is enabled in the procedure, VB invokes its own default error handler, displays a message, and terminates the application. Because of this behavior, it is vital that you always code an error handler in Sub Main, all event procedures, and the Class_Terminate event for class modules.
Unlike the Class_Terminate event, the Class_Initialize event of a class module can raise an error or allow it to go untrapped. However, it is considered good programming practice to have classes trap their own errors, deal with them if possible, and if necessary raise errors explicitly, providing a number and description defined within the class.
You can code your classes to map any error the class encounters to class-defined error numbers, but given the large number of potential errors that could occur in an application, that may not always be practical. An alternative is to have the class assign specific numbers and descriptions to errors that are specific to problems with the code or data in the class (such as a value that violates a rule for the data) but pass out standard VB errors (such as error 13 - type mismatch) as is. This allows applications using the class to explicitly handle the errors exclusive to the class with customized code, but handle standard VB errors with more generic code.
Regardless of the approach you take, you must always ensure that private data within the class is valid and that code within the class cleans up any local or module level object variables it creates. This may require you to setup an error handler that traps errors, cleans up local object variables, and then raises the same error again.
Building Error Handlers
Trapping an error using the On Error statement is only the first step in dealing with run-time errors in your code. You must also deal with the error in some way, even if the error handling code is as simple as ignoring the error (a perfectly valid approach in some situations) or displaying a message for the user.
The first step in handling an error is determining the nature of the error. This is accomplished by examining the properties of Visual Basic's Err object. The Err object includes the following properties:
It is important that you rely only on the error number to determine the nature of the error. While the Description and other properties may contain useful information, only the Number property is a reliable indicator of the exact error that occurred.
A common approach in coding an [gs error] handler is to build a Select Case block based on the Number property of the Err object:
Public Sub SubA()
On Error Goto ProcError
' code that raises an error
ProcExit:
Exit Sub
ProcError:
Select Case Err.Number
Case X
' handle X
Case Y
' handle Y
Case Z
' handle Z
Case Else
' default
MsgBox Err.Description
Resume ProcExit
End Select
End Sub
X, Y, and Z may be literal numbers (Case 13 ' type mismatch) or, if they are available, symbolic constants representing the numbers.
If you are building a class module that will raise class-defined errors, you should provide a public enumeration in the class that defines constants for any errors raised by the class. By providing constants, code that creates objects defined by the class can use the constants instead of the literal numbers and protect itself from changes in the actual numbers.
Once you have trapped and handled the error, you need to tell Visual Basic where to continue with program execution. There are several options available when an error handling block is entered using On Error Goto label:
In addition to these statements, you can also call the Clear method of the Err object to clear the current error. This is most often used with inline error handling, as shown below:
Public Sub CreateFile(sFilename As String)
On Error Resume Next
' the next line will raise an error if the file
' doesn't exist, but we don't care because the
' point is to kill it if it does anyway.
Kill sFilename
Err.Clear
' code to create a file
End Sub
This isn't a very robust example. There are many other things besides a file that doesn't exist that could cause the Kill statement to fail. The file may be read-only, there may be a network permissions error, or some other problem.
Handling Errors You Can't Handle
In most cases you can anticipate the most common errors and build code to deal with them. The error handling code might be as simple as a message to the user such as "This field requires a valid date." In some cases, however, you will encounter errors you didn't anticipate and you must find a way to deal with them.
There are two general approaches you can take to handling unanticipated errors:
You should try to avoid the latter situation at all times. Displaying a message and shutting down or - worse yet - just pulling the application out from under the user will not be well received. If you must terminate an application due to some disastrous situation, be sure to provide as much information to the user as you can so that the situation can be resolved. An even better option is to code your error handlers to call code that corrects severe problems.
For example, if you are designing a [gs database] application and encounter a corrupted [gs database] file, the error handling code could give the user the [gs option] of attempting to repair the damaged file. If a file cannot be found where it should be, write [gs code] to either look for it or give the user a file open dialog box so they can tell you where it went.
Raising Your Own Errors
There may be times when you need to generate errors in your code. This happens most often in class modules, but you can raise an error anywhere in a Visual Basic application. You raise an error by calling the Raise method of the Err object.
Not surprisingly, the parameters of the Raise method are the same as the properties of the Err object: Number, Description, Source, HelpContext, and HelpFile. The values you provide for these parameters are available to error handling code that deals with the error you generate.
When you raise an error, you should make the information you provide via the Err object as informative as possible so that error handling code that deals with the error has the best possible opportunity to handle it.
The following example is a hypothetical property procedure for a class module:
' in the declarations section
Private mDate As Date
Public Enum MyClassErrors
errInvalidDate
' other errors
End Enum
' a property procedure
Public Property Let Date(vntDate As Variant)
' a variant is used to allow the property
' procedure to attempt to convert the value
' provided to a date
If IsDate(vntDate) Then
mDate = CDate(vntDate)
Else
' invalid data
Err.Raise _
Number:=errInvalidDate, _
Description:=CStr(vntDate) & " is not a valid date.", _
Source:="Foo.MyClass"
' help context and file go here if a help file is available
End If
End Property
In this example, the property procedure tests for a valid date using the IsDate [gs function]. If the data provided is not a date, an error is raised using the constant from the error enumeration in the declarations section of the class module and a description that includes the bad data and the nature of the error.
Summary
Handling [gs run-time] errors is something all applications must do if they are to be robust and reliable.
The key points for error handling are...There are two steps to handling run-time errors:
The Err object was introduced in Visual Basic 4.0. For backward compatibility, VB continues to support the Err and Error statements and functions. Any new code should be using the Err object and legacy code should be converted to use the Err object.
SOURCE | LINK (vb6.us) | LANGUAGE | ENGLISH |