I showed you earlier in the chapter how unhandled errors can lead to data corruption, crashed applications, and spiraling out-of-control congressional spending. All good programmers understand how important error-handling code is, and make the extra effort of including either structured or unstructured error-handling code. Yet there are times when I, even I, as a programmer, think, "Oh, this procedure isn't doing anything that could generate errors. I'll just leave out the error-handling code and save some typing time." And then it strikes, seemingly without warning: an unhandled error. Crash! Burn! Another chunk of user data confined to the bit bucket of life.
Normally, all unhandled errors "bubble up" the call stack, looking for a procedure that includes error-handling code. For instance, consider this code.
Private Sub Level1() On Error GoTo ErrorHandler Level2() Return ErrorHandler: MsgBox("Error Handled.") Resume Next End Sub Private Sub Level2() Level3() End Sub Private Sub Level3() ' ----- The Err.Raise method forces an ' unstructured-style error. Err.Raise(1) End Sub
When the error occurs in Level3, the application looks for an active error handler in that procedure, but finds nothing. So it immediately exits Level3 and returns to Level2, where it looks again for an active error handler. Such a search will, sadly, be fruitless. Heartbroken, the code leaves Level2 and moves back to Level1, continuing its search for a reasonable error handler. This time it finds one. Processing immediately jumps down to the ErrorHandler block and executes the code in that section.
If Level1 didn't have an error handler, and no code farther up the stack included an error handler, the user would see the Error Message Window of Misery (refer to Figure 9-2), followed by the Dead Program of Disappointment.
Fortunately, Visual Basic does support a "catch all" error handler that traps such unmanaged exceptions and lets you do something about them. This feature works only if you have the Enable application framework field selected on the Application tab of the project properties. To access the code template for the global error handler, click the View Application Events button on that same project properties tab. Select "(MyApplication Events)" from the Class Name drop-down list above the source code window, and then select "UnhandledException" from the Method Name list. The following procedure appears in the code window.
Private Sub MyApplication_UnhandledException( _ ByVal sender As Object, _ ByVal e As Microsoft.VisualBasic. _ ApplicationServices.UnhandledExceptionEventArgs) _ Handles Me.UnhandledException End Sub
Add your special global error-handling code to this routine. The e event argument includes an Exception member that provides access to the details of the error via a System.Exception object. The e.ExitApplication member is a Boolean property that you can modify either to continue or to exit the application. By default, it's set to True, so modify it if you want to keep the program running.
Even when the program does stay running, you will lose the active event path that triggered the error. If the error stemmed from a click on some button by the user, that entire Click event, and all of its called methods, will be abandoned immediately, and the program will wait for new input from the user.