Home

Error and Exception Handling

 

Introduction to Errors

 

Overview 

Apparently no matter how careful and meticulous you are, there will be problems with your code or your application. Some problems will come from you. Some problems will be caused by users. And some problems will be caused by neither you nor your users. This means that there are things you can fix. There are things you can avoid as much as possible. And there are things beyond your control. Still, as much as you can, try anticipating any type of problem you imagine may occur when a user is using your application, and take action as much as possible to avoid bad situations.

 

Error Categories

As mentioned above, there are three main types of problems that you will deal with, directly or indirectly:

  1. Syntax: A syntax error comes from your mistyping a word or forming a bad expression in your code. It could be that you misspelled a keyword such as ByVel instead of ByVal. It could also be a bad expression such as 524+ + 62.55. It could be a "grammar" error such as providing the name of a variable before its data type when declaring a variable (quite common for those who regularly transition from different languages (C/C++, Pascal, C#, Java))

    When you use Microsoft Visual Studio to write your code, it would point out the errors while you are writing your code, giving up ample time to fix them. When you compile your application, the compiler can let you know about other syntax errors. For this reason, syntax errors are almost the easiest to fix. Most of the time, the compiler would point out where the problem is so you can fix it. 
  2. Run-Time: After all syntax errors have been fixed, the program may be ready for the user. There are different types of problems that a user may face when interacting with your program. For example, imagine that, in your code, you indicate that a picture would be loaded and displayed to the user but you forget to ship the picture or the directory of the picture indicated in your code becomes different when a user opens your application. In this case, when you compiled and executed the application in your machine, everything was fine. This is a type of run-time error.
    Run-time errors are mostly easy to fix because you will know what problem is occurring and why.
  3. Logic: These are errors that don't fit in any of the above categories. They could be caused by the user misusing your application, a problem with the computer on which the application is running while the same application is working fine in another computer. Because logic errors can be vague, they can also be difficult (even, to the extreme, impossible) to fix.

One of the best qualities of an effective programmer is to anticipate as many problems as possible and to deal with them in the early stages. Some problems can be easy to fix. With some others, you will simply need to build more experience to know how to fix them. Unfortunately, it will not be unusual to have users asking you to fix your application when a problem may not come from it.

 

Classic Error Handling

 

Introduction 

From their early stages, Visual Basic has always made it a priority to deal with errors. Most or early errors occur in your code. The Visual Studio IDE can help you detect syntax errors and fix them. In fact, a feature almost unique to the Visual Basic IDE, which is not available in Visual C++ and some versions of Visual C#, is that its Code Editor detects problems immediately as soon as they appear in your code. In fact, in previous versions of Visual Basic and in VBA (Microsoft Access), a message box would display, prompting you to fix the problem. This has always made Visual Basic one of the friendliest programming environments around. When you think everything is fine, compile your code. If there is a syntax error that that the IDE didn't signal or that you ignored when writing your code, the compiler will let you know. If there is no syntax error, the compilation will be over and the executable will be ready. You can then execute the application to see the result. If the user is not asked tom provide value(s), you are less likely to get a run-time error.

A run-time error is one that occurs when using your application. Consider the following application:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim Number As Double
        Dim Twice As Double

        Number = Me.TextBox1.Text
        Twice = Number * 2

        Me.TextBox2.Text = Twice
End Sub

Here is an example of executing it:

The first aspect your should take into consider is to imagine what could cause a problem. If you think there is such a possibility, start by creating a label that could be used to transfer code if a problem occurs. Here is an example:

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim Number As Double
        Dim Twice As Double

        Number = Me.TextBox1.Text
        Twice = Number * 2

        Me.TextBox2.Text = Twice

ThereWasAProblem:
        MsgBox("There was a problem when executing your instructions")
    End Sub

If you create such a label, you should tell the compiler when to jump to that label. Otherwise, as in this case, the label section would always execute. Here is an example of running the above version:

In this case, we want the label section to execute only when we want it to. To prevent the compiler from reaching this section if not directed so, you can add an Exit Sub line above the label section:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim Number As Double
        Dim Twice As Double

        Number = Me.TextBox1.Text
        Twice = Number * 2

        Me.TextBox2.Text = Twice

        Exit Sub

ThereWasAProblem:
        MsgBox("There was a problem when executing your instructions")
    End Sub

This time if you execute the program with an appropriate value, the label section would not be reached.

In Case Of Error, Jump To Label

The above program will compile fine. When executing it, imagine that the user types an inappropriate value such as 24$.58 instead of 244.58. In this case, the value is not a number, the program would "crash" and let you know that there was a problem:

With some experience, you would know what the problem was, otherwise, you would face a vague explanation. The short story is that the compiler couldn't continue because, in this case, it could not multiply 24$.58 by 2.

If a problem occurs when a person is using your program, the compiler may display a nasty and insignificant message to the user who would not know what to do with it. Therefore, you can start by creating an appropriate label as introduced above. An error normally occurs in a procedure. Therefore, to make your code easier to read, you should create a label that shows that it is made for an error instead of being a regular label. The label should also reflect the name of the procedure. Here is an example:

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim Number As Double
        Dim Twice As Double

        Number = Me.TextBox1.Text
        Twice = Number * 2

        Me.TextBox2.Text = Twice

        Exit Sub

Button1_Click_Error:
        MsgBox("The operation could not be executed", MsgBoxStyle.OKOnly, "Operation Error")
    End Sub

When you think there will be a problem in your code, somewhere in the lines under the name of the procedure but before the line that could cause the problem, type On Error GoTo followed by the name of the label that would deal with the error. Here is an example:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        On Error GoTo Button1_Click_Error
        Dim Number As Double
        Dim Twice As Double

        Number = Me.TextBox1.Text
        Twice = Number * 2

        Me.TextBox2.Text = Twice

        Exit Sub

Button1_Click_Error:
        MsgBox("The operation could not be executed", MsgBoxStyle.OKOnly, "Operation Error")
    End Sub

Here is an example of running the program:

When the On Error GoTo statement is used, this indicates to the compiler that if any type of error occurs while the code of this procedure is executed, transfer the compilation to the label. In this case, as soon as something bad happens, the compiler marks the area where the problem occurred, skips the normal code and jumps to the label indicated by the On Error GoTo line. After the section of that label is executed, the compiler returns where the error occurred. If there is nothing to solve the problem, the compiler continues down but without executing the lines of code involved. In this case, it would encounter the Exit Sub line and get out of the procedure.

In Case Of Error, Jump To Line #

Although the label is more explicit, it only indicates to the compiler what line to jump to in case of a problem. The alternative is to specify a line number instead of a label.

Resume 

If a problem occurs in your code and you provide a label to display a friendly message as done above, the compiler would display the message and exit from the procedure. If this happens, as mentioned above, when the compiler returns where the problem occurred, you can provide an alternate. For example, in our program, if the user provides an inappropriate value that causes the error, you can provide an alternate value and ask the compiler to continue as if nothing happened. In this case, you want to compiler to "resume" its activity.

To indicate that the program should continue, you can use the Resume keyword. Here is an example:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        On Error GoTo Button1_Click_Error
        Dim Number As Double
        Dim Twice As Double

        Number = Me.TextBox1.Text

        Resume

        Twice = Number * 2

        Me.TextBox2.Text = Twice

        Exit Sub

Button1_Click_Error:
        MsgBox("The operation could not be executed", MsgBoxStyle.OKOnly, "Operation Error")
    End Sub

When an error occurs, if you want the program to continue with with an alternate value than the one that caused the problem, in the label section, type Resume Next. Here is an example:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        On Error GoTo Button1_Click_Error
        Dim Number As Double
        Dim Twice As Double

        Number = Me.TextBox1.Text

        Twice = Number * 2

        Me.TextBox2.Text = Twice

        Exit Sub

Button1_Click_Error:
        MsgBox("The operation could not be executed", MsgBoxStyle.OKOnly, "Operation Error")
        Resume Next
    End Sub

In this case, since any numeric variable is initialized with 0, when the compiler returns to the line of code that caused the problem, it would use 0 as a substitute to the inappropriate value. Based on this, you can provide a new value to use in case of error. Here is an example:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        On Error GoTo Button1_Click_Error
        Dim Number As Double
        Dim Twice As Double

        Number = Me.TextBox1.Text

        Twice = Number * 2

        Me.TextBox2.Text = Twice

        Exit Sub

Button1_Click_Error:
        MsgBox("The operation could not be executed" & vbCrLf & _
               "10 will be used instead", _
                MsgBoxStyle.OKOnly, _
                "Operation Error")
        Number = 10
        Resume Next

    End Sub

Here is one example of running the program:

Here is another example of running the same program:

 

The Err Object

To support error handling, Visual Basic provides a global variable named Err. This allows you to identify the error and its description. Because an error depends on what caused it and why, the values of the Err variable also depend and are not always the same.

 

Exception Handling

 

Introduction

As opposed to the traditional techniques used to deal with errors, Visual Basic now supports a technique referred to as exception handling. This technique was mostly used by other languages such as C/C++, Object Pascal, C#, etc. This technique is also referred to as structured exception handling (SEH). The On Error GoTo system of dealing with errors is referred to as unstructured exception handling (we will abbreviate is unSEH). There were many concerns with unSEH used in previous versions of Visual Basic:

  • In previous versions, you had to remember to include On Error GoTo sometimes in a random area inside the procedure. Besides On Error GoTo, you had to remember to create a label section. The name of the label had to be faithfully included in the On Error GoTo line. This technique was not really the most precise system
  • When using the On Error GoTo technique, you had to make sure you get out of the procedure at the right time, which was done using an Exit Sub line. If you created this Exit Sub line in the wrong area in your procedure, either the whole code would not be considered or an desired section of the procedure would still execute, possibly producing an unpredictable result. In the same way, a bizarre way of creating a Resume or a Resume Next line would prevent the compiler from reaching or considering some sections of a procedure
  • As mentioned previously, the On Error GoTo system provides a global variable named Err. As flexible as good intentioned as it may appear, to effectively use Err, you had to proceed by trial and error because Err identifies errors by a number but its documentation didn't possible provide a list of error numbers. This was because Err not only depended on the application (Visual Basic, VBA, etc) but also it depended on the circumstance in which it was invoked. The only possible solution was to cause an error in your code in order to cause Err to show the numeric error that occurred. Then you had to use that error number and create a custom error message

Because of these uncertainties, you should abandon the On Error GoTo traditional error handling and use SEH in all of your new code. Because SEH and unSEH techniques are inherently different, you cannot use both in the same procedure.

Try to Catch the Error

As mentioned already, errors are likely going to occur in your program. The more you anticipate them and take action, the better your application can be. We have already seen that syntax errors are usually human mistakes such as misspelling, bad formulation of expressions, etc. The compiler will usually help you fix the problem by pointing it out.

SEH is based on two main keywords: Try and Catch. An exception handling section starts with the Try keyword and stops with the End Try statement. Between Try and End Try, there must by at least one Catch section. Therefore, exception handling uses the following formula:

Try
    ' Code to Execute In Case Everything is Alright
Catch
    ' If Something Bad happened, deal with it here
End Try

Exception handling always starts with the Try keyword. Under the Try line, Write the normal code that the compiler must execute. Here is an example:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim Number As Double
        Dim Twice As Double

        Try
            Number = Me.TextBox1.Text

            Twice = Number * 2

            Me.TextBox2.Text = Twice
        End Try

    End Sub

As the compiler is treating code in the Try section, if it encounters a problem, it "gets out" of the Try section and starts looking for a Catch section. Therefore, you MUST always have a Catch section. If you don't, as seen on the above code, the program will not compile. A Catch section must be written before the End Try line:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim Number As Double
        Dim Twice As Double

        Try
            Number = Me.TextBox1.Text

            Twice = Number * 2

            Me.TextBox2.Text = Twice

        Catch

        End Try

    End Sub

When the Catch keyword is simply written as above, it would be asked to treat any error that occurs. For example, if you execute the above code with a number such as 24$.58 instead of 244.58, nothing would appear to happen. This would indicate that the error was found and vaguely dealt with. One problem in this case is that the compiler would not bother to let the user know why there is no result displayed. Because there can be various types of errors in a program, you also should make your program more intuitive and friendlier so that, when an error occurs, the user would know the type of problem. This is also useful if somebody calls you and says that your program is not functioning right. If there is a way the user can tell you what exact type of error is displaying, may be you would find the solution faster.

 

Visual Basic and Exception Handling

 

The Exception Class

In traditionally-oriented error dealing languages such as C/C++ or Object Pascal, you could create any exception of your choice, including numeric or strings. To customize exception handling, you could also create your own class. Most libraries such as Borland's VCL and Microsoft's MFC also shipped with their own classes to handle exceptions. Event the Win32 library provides its type of mechanism to face errors. To support exception handling, the .NET Framework provides the Exception class. Once the compiler encounters an error, the Exception class allows you to identify the type of error and take appropriate action.

Normally, Exception mostly serves as the general class of exceptions. Anticipating various types of problems that can occur in a program, Microsoft derived various classes from Exception to make this issue friendlier. As a result, almost any type of exception you may encounter already has a class created to deal with it. Therefore, when your program faces an exception, you can easily identify the type of error. There are so many exception classes that we cannot study or review them all. The solution we will use is to introduce or review a class when we meet its type of error.

The Exception's Message

In exception handling, errors are dealt with in the Catch section. To do this, on the right side of Catch, declare a variable of the type of exception you want to deal with. By default, an exception is first of type Exception. Based on this, a typical formula to implement exception handling is:

Try

Catch ex As Exception

End Try

When an exception occurs in the Try section, code compilation is transferred to the Catch section. If you declare the exception as an Exception type, this class will identify the error. One of the properties of the Exception class is called Message. This property contains a string that describes the type of error that occurred. You can then use this message to display an error message if you want. Here is an example:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim Number As Double
        Dim Twice As Double

        Try
            Number = Me.TextBox1.Text

            Twice = Number * 2

            Me.TextBox2.Text = Twice
        Catch ex As Exception
            MsgBox(ex.Message)
        End Try

    End Sub

Here is an example of running the program:

 

 

Custom Error Messages

The above test shows us that the Exception class knows with certainty what problem occurred and why the operation could not be carried. Sometimes, the message provided by the Exception class may not appear explicit enough. In fact, you may not want to show it to the user since, as in this case, the user may not understand what the word "cast" in this context means and why it is being used. As an alternative, you can create your own message and display it to the user. Here is an example:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim Number As Double
        Dim Twice As Double

        Try
            Number = Me.TextBox1.Text

            Twice = Number * 2

            Me.TextBox2.Text = Twice
        Catch ex As Exception
            MsgBox("The operation could not be carried because " & vbCrLf & _
                   "the number you typed is invalid", _
                    MsgBoxStyle.OKOnly, _
                   "Invalid Operation")
        End Try

    End Sub

Here is an example of running the program:

Custom Message Without Using an Exception Argument

You can also combine the Exception.Message message and your own message:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim Number As Double
        Dim Twice As Double

        Try
            Number = Me.TextBox1.Text

            Twice = Number * 2

            Me.TextBox2.Text = Twice
        Catch ex As Exception
            MsgBox(ex.Message & vbCrLf & _
                   "The operation could not be performed since " & vbCrLf & _
                   "the number you provided is not valid", _
                    MsgBoxStyle.OKOnly, _
                   "Invalid Operation")
        End Try

    End Sub

Here is an example of running the program:

Custom Message Combining an Exception.Message message and a Custom Message

 

 

Exception Derived Classes

To deal with the various types of errors that can occur in a large procedure, the .NET Framework provides various classes derived from Exception. Each of these classes tend to deal with a particular error that could occur when using a certain control. Because there are so many of them, we will mention them when necessary.

 

Catching Various Types of Errors

In the examples above, when we anticipated some type of problem, we instructed the compiler to use our default Catch section. We left it up to the compiler to find out when there was a problem and we provided a Catch section to deal with it. We didn't event tell the compiler what kind of problem could occur. Fortunately, in this small program, the compiler could cope. A procedure with numerous or complex operations and requests can also produce different types of errors. With such a type of program, you should be able to face such different problems and deal with them individually, each by its own kind. To do this, you can create different Catch sections, each made for a particular error.

 

In Case of Error, Throw This

When a problem in a particular section of a procedure, you can indicate this to the compiler and "throw" an error. This is done with the Throw keyword, which is usually included in the Try section. The formula used is:

Try
    ' Code to Execute In Case Everything is Alright
    Throw
Catch
    ' If Something Bad happened, deal with it here
End Try

 

 

Home Copyright © 2004-2010 FunctionX, Inc.