Section 9.2. Runtime Error Handling

   

9.2 Runtime Error Handling

As we have mentioned, VB currently supports both unstructured and structured error handling. Let us first look at unstructured error handling.

9.2.1 Unstructured Error Handling

Error-handling techniques that revolve around the various On Error ... statements are referred to as unstructured error-handling techniques. These techniques generally use the Err object and the Visual Basic call stack.

9.2.1.1 The Err object

Visual Basic's built-in error object, called Err , is one of the main tools for unstructured error handling. This object has several properties and methods , as shown in Tables Table 9-1 and Table 9-2, respectively.

Table 9-1. Properties of the Err object

Property

Description

Description

A short string describing the error.

HelpContext

The context ID for a help topic associated with the error.

HelpFile

The fully qualified filename of the associated help file, if any.

LastDLLError

The return code from a call made to a function in an external DLL. Note, however, that this property may change value at any time, so it is wise to store the current value in a variable immediately upon return from the DLL call. Note also that even if the DLL call resulted in an error, this is not considered an error by VB. (VB has no way of knowing the meaning of return values from external functions, after all.)

Number

This is the error number of the error.

Source

A string that specifies the object that generated the error. When the error is generated within your application, the Source property is the project's name, which is more or less useless. (It would have been nice to get the name of the offending procedure.) However, when the error is generated by an external COM component, the Source property returns the programmatic ID of that component, which has the form application.objectname , as in Excel.Application , for example.

Table 9-2. Methods of the Err object

Method

Description

Clear

Clears the values of all properties of the Err object. Its syntax is:

 Err().Clear(  ) 

Note that the Clear method is called implicitly when any of the following statements is executed: a Resume statement of any type; an Exit Sub , Exit Function , or Exit Property statement; or any On Error statement.

Raise

Causes Visual Basic to generate a runtime error and sets the properties of the Err object to the values given by the parameters of the Raise method. Its syntax is:

 Err.Raise(Number, Source, Description, _           HelpFile, HelpContext) 

where all but the first named argument is optional. Each parameter corresponds to the property of the same name.

9.2.1.2 Dealing with runtime errors

Visual Basic detects a runtime error as soon as it occurs, sets the properties of the Err object, and directs the flow of execution to a location that the programmer has specified by the most recent On Error ... line. This location can be one of the following:

  • The line of code immediately following the line that caused the error.

  • Another location within the offending procedure.

  • The procedure that called the offending procedure, if there is one. If not, VB issues an error message itself and terminates the application.

Let us take a closer look at each of these possibilities.

9.2.1.2.1 In-line error handling

Code execution will be "redirected" to the line following the offending line of code (that is, execution will continue immediately following the offending line) if the most recent preceding On Error statement is:

 On Error Resume Next 

This is referred to as in-line error handling . Here is an example that involves renaming a file. Note the typical use of a Select Case statement to handle the error based on the value of Err.Number. Incidentally, one way to obtain error numbers is to deliberately invoke a particular error and break execution (with a breakpoint) to examine Err.Number:

 Dim sOldName, sNewName As String On Error Resume Next ' Ask for an existing file name sOldName = InputBox("Enter the file name to rename") ' Ask for new name sNewName = InputBox("Enter the new file name") ' Rename file Rename("c:\" & sOldName, "c:\" & sNewName) ' Deal with error If Err(  ).Number = 53 Then     ' File not found error     MsgBox("File " & sOldName & " not found")     Exit Sub Else     ' All other errors     MsgBox(Err().Number & ": " & Err(  ).Description)     Exit Sub End If 
9.2.1.2.2 Centralized error handling

While in-line error handling does have its uses, there is much to be said for centralizing error handling within a procedure. (This often improves readability and makes code maintenance easier.) We can direct code execution to a central error handler using the code:

 On Error Goto   label   

This is outlined in the following code shell:

 Sub Example(  ) On Error Goto ErrHandler '' If run-time error occurs here '' Visual Basic directs execution to ErrHandler Exit Sub ErrHandler: '' Code can be placed here to handle errors '' or pass them up the calls list. '' We have knowledge of Err().Number, Err(  ).Description, '' and Err(  ).Source. End Sub 

Once the On Error Goto label line is executed, we say that the error handler beginning at the label ErrHandler is active .

Once code execution is directed to the error handler, there are several possibilities for dealing with the error. The most common possibility is simply to handle the error in the active error handler, perhaps by displaying an error message asking the user to take corrective action.

Another common (and useful) approach is passing information about an error to the calling procedure with parameters or with the return value of the offending function. For instance, if a function is designed to rename a file, the function might return an integer error code indicating the success or failure of the operation. This is quite common among the Win32 API functions. In particular, the error code might be 0 for success, -1 if the file does not exist, -2 if the new filename is invalid, and so on.

A third possibility is to pass the error to the calling procedure by invoking the Err.Raise method within the active error handler, as in:

 Err.Raise(Err.Number, Err.Source, Err.Description, _           Err.HelpFile, Err.HelpContext) 

This triggers the calling procedure's error handler (or more precisely, the next enabled error handler in the calls list). This process is called regenerating or reraising the error.

Note that it is possible to deactivate an active error handler using the line:

 On Error Goto 0 

If there is no active error handler, then VB reacts to errors just as though no error handler existed in the procedure. We describe this situation in the next section.

9.2.1.2.3 No enabled error-handler

If there is no enabled error handler in the offending procedure, either because there is no On Error statement in the procedure or because error handling has been disabled with an On Error Goto statement, then Visual Basic automatically sends the error to the calling procedure's error handler. If the calling procedure has no error handler, the error continues up the calls list until it reaches an enabled error handler. If none is found, then Visual Basic handles the error by displaying an error message and terminating the application.

9.2.2 Structured Exception Handling

Structured exception handling uses a Try ... Catch ... Finally structure to handle errors. As we will see, VB.NET's structured exception handling is a much more object-oriented approach, involving objects of the Exception class and its derived classes.

9.2.2.1 Try...Catch...Finally

The syntax of the Try ... Catch ... Finally construct is given here:

 Try   tryStatements   [Catch1 [   exception   [As   type   ]] [When   expression   ]     catchStatements1 [Exit Try] Catch2 [   exception   [As   type   ]] [When   expression   ]   catchStatements2   [Exit Try] . . . Catchn [   exception   [As   type   ]] [When   expression   ]   catchStatementsn   ] [Exit Try] [Finally   finallyStatements   ] End Try 

The tryStatements (which are required) constitute the Try block and are the statements that are monitored for errors by VB. Within the Try block, we say that error handling is active .

The Catch blocks (of which there can be more than one) contain code that is executed in response to VB "catching" a particular type of error within the Try block. Thus, the Catch blocks consist of the error handlers for the Try block.

The phrases exception [As type ] and [When expression ] are referred to as filters in the VB.NET documentation. In the former case, exception is either a variable of type Exception, which is the base class that "catches" all exceptions, or a variable of one of Exception's derived classes.

(We provide a list of these classes a bit later.) For instance, the variable declared as:

 Catch e As Exception 

will catch (that is, handle) any exception. The variable declared as:

 Catch e As ArgumentNullException 

catches (handles) any exception of class ArgumentNullException. In short, type is the name of one of the exception classes.

The When filter is typically used with user-defined errors. For instance, the code in the following Try block raises an error if the user does not enter a number. The Catch block catches this error:

 Try     Dim sInput As String     sInput = Inputbox("Enter a number.")     If Not IsNumeric(sInput) Then         Err.Raise(1)     End If Catch When Err.Number = 1     Msgbox("Error1") End Try 

Note that code such as:

 Dim x As Integer Try     x = 5 Catch When x = 5     MsgBox(x) End Try 

does not work (that is, the Catch statements are never executed) because no error was generated.

The Exit Try statement is used to break out of any portion of a Try ... Catch ... Finally block. The optional finallyStatements code block is executed regardless of whether an error occurs (or is caught), unless an Exit Try statement is executed. This final code can be used for cleanup in the event of an error. (By placing an Exit Try at the end of the Try block, the finallyStatements are not executed if no error occurs.)

As with unstructured error handling, VB may pass an error up the call stack when using structured error handling. This happens in the following situations:

  • If an error occurs within a Try block that is not handled by an existing Catch block

  • If an error occurs outside any Try block (provided, of course, that no On Error -style error handlers are active).

9.2.2.2 Exception classes

The System namespace contains the Exception class, which is the base class for a substantial collection of derived exception classes, listed as follows . Note that the indentation indicates class inheritance. For example, EntryPointNotFoundException (the fifth from the last entry in the list) inherits from TypeLoadException.

  Exception     ApplicationException     SystemException AccessException     FieldAccessException     MethodAccessException     MissingMemberException MissingFieldException MissingMethodException AppDomainUnloadedException AppDomainUnloadInProgressException ArgumentException    ArgumentNullException    ArgumentOutOfRangeException    DuplicateWaitObjectException ArithmeticException     DivideByZeroException     NotFiniteNumberException     OverflowException ArrayTypeMismatchException BadImageFormatException CannotUnloadAppDomainException ContextMarshalException CoreException     ExecutionEngineException     IndexOutOfRangeException     StackOverflowException ExecutionEngineException FormatException InvalidCastException InvalidOperationException MulticastNotSupportedException NotImplementedException NotSupportedException     PlatformNotSupportedException NullReferenceException OutOfMemoryException RankException ServicedComponentException TypeInitializationException TypeLoadException     EntryPointNotFoundException TypeUnloadedException UnauthorizedAccessException                                 WeakReferenceException URIFormatException  

As Microsoft states: "Most of the exception classes that inherit from Exception do not implement additional members or provide additional functionality." Thus, it is simply the class name that distinguishes one type of exception from another. The properties and methods applied to an exception object are inherited from the Exception base class.

When writing Catch blocks, we always face the question of whether to simply trap the generic exception class, as in:

 Sub test(  )     Try     ...     Catch e As Exception     ...     End Try End Sub 

or whether to trap specific exception classes. Of course, the time to trap specific exception classes is when we want to handle errors differently based on their class. For instance, this may take the form of issuing different custom error messages for different exception types.

Also, there are occasions when we may want to take advantage of members of a particular exception class that are not implemented in the Exception base class. For instance, the ArgumentException class has a ParamName property that returns the name of the parameter that causes the exception. Now, if we simply trap the generic Exception class, as in the following code:

 Sub test(  )     Try         Dim s, d As String         s = "c:\temp.txt"         ' Attempt to copy a file to a nonvalid target         FileCopy(s, d)     Catch e As Exception         MsgBox(e.Message)     End Try End Sub 

then we cannot take advantage of the ParamName property. On the other hand, if we specifically trap the ArgumentException class, as in the following code:

 Sub test1(  )     Try         Dim s, d As String         s = "c:\temp.txt"         ' Attempt to copy a file to a nonvalid target         FileCopy(s, d)     Catch e As ArgumentException         MsgBox(e.Message & " Parameter: " & e.ParamName)     End Try End Sub 

then we can retrieve the name of the offending parameter.

Now let us take a look at some of the members of the Exception class:

Message property

A string containing an error message.

Source property

A string that describes the application or object that threw the exception.

StackTrace property

A string that contains the stack trace immediately before the exception was thrown. We provide an example of this in a moment (although in this case its value is Nothing .

TargetSite property

A string that gives the method that threw the exception.

ToString method

A string that returns the fully qualified name of the exception, possibly the error message, the name of the inner exception, and the stack trace. Its syntax is simply:

 ToString(  ) 

The best way to get a feel for these members is with an example. Consider the following code, which consists of three subroutines. The first subroutine, Exception0 , contains a Try ... Catch ... statement. In the Try code block, the subroutine Exception0 calls the subroutine Exception1 , which simply calls Exception2 .

 Sub Exception0(  )     Dim s As String     Try         Exception1(  )     Catch e As Exception         s = "Message: " & e.Message         s = s & ControlChars.CrLf & "Source: " & e.Source         s = s & ControlChars.CrLf & "Stack: " & e.StackTrace         s = s & ControlChars.CrLf & "Target: " & e.TargetSite.Name         s = s & ControlChars.CrLf & "ToString: " & e.ToString         debug.writeline(s)     End Try      End Sub Sub Exception1(  )     Exception2(  ) End Sub Sub Exception2(  )     Throw New ArgumentNullException(  ) End Sub 

In Exception2 , there is a single line of code that executes the Throw statement, which throws an exception. This is similar to raising an error with the Err.Raise method. However, as you can see by the New keyword, the Throw statement actually creates an object of one of the exception types.

The output from the call to Exception0 is:

 Message: argument can't be null Source:  Stack: at WindowsApplication3.Form1.Exception2(  )            in C:\VBNET\Form1.vb:line 68        at WindowsApplication3.Form1.Exception1(  )            in C:\VBNET\Form1.vb:line 66        at WindowsApplication3.Form1.Exception0(  )            in C:\VBNET\Form1.vb:line 53 Target: Exception2 ToString: System.ArgumentNullException: argument can't be null    at WindowsApplication3.Form1.Exception2(  )            in C:\VBNET\Form1.vb:line 68    at WindowsApplication3.Form1.Exception1(  )            in C:\VBNET\Form1.vb:line 66     at WindowsApplication3.Form1.Exception0(  )            in  C:\VBNET\Form1.vb:line 53 
   


VB.Net Language in a Nutshell
VB.NET Language in a Nutshell
ISBN: B00006L54Q
EAN: N/A
Year: 2002
Pages: 503

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net