Click here to Skip to main content
Click here to Skip to main content

Safe Form - Simplified Unhandled Exception Handling in Visual Basic .NET

, 26 Jan 2005
Rate this:
Please Sign up or sign in to vote.
An elegant way of handling those unforeseeable exceptions.

Introduction

This article hopes to simplify two key hurdles that took me a while to get past. First, unhandled exceptions. While I'm sure that none of you ever have any of these, I seem to get them at the most inopportune times. The unfriendly Continue or Quit dialog just does wonders for your reputation and almost inevitably means a crash will be imminent while you're presenting your application, or, even worse, after releasing it. The second piece that I'd like to show you is how to simplify creating templates to work from. Inheritance could be one of the best things to ever happen to Visual Basic, so, by all means, take advantage of it.

Background

I have to mention that what led me to putting this together was a very nice component by Stratalogic Software, called SLS Exception Reporter. It's a nice way of managing any exception and works great in conjunction with this template.

Part I: Unhandled Exceptions

Even though we always hope to have everything encapsulated within nice structured Try-Catch-Finally blocks, occasionally, an error happens for no foreseeable reason. When working with Windows Forms, this raises a System.Threading.ThreadException event. There's very little that you have to actually do to handle this event.

First, create a method called OnThreadException:

Private Sub </FONT>OnThreadException(ByVal sender As Object, _
                       ByVal e As ThreadExceptionEventArgs)
  ' This is where you handle the exception
  ' For Instance:
  MessageBox.Show(e.Exception.Message)
End Sub

This next part is to wire up the OnThreadException handler to the Application.ThreadException event. This should be done in the constructor of the form, before the InitializeComponent method.

Public Sub New()
MyBase.New()

  'Hook the ThreadException event to the OnThreadException method.
  AddHandler Application.ThreadException, AddressOf OnThreadException

  'This call is required by the Windows Form Designer.
  InitializeComponent()

  'Add any initialization after the InitializeComponent() call

End Sub

Now, you can choose to handle the exception in any way that you wish and be sure that the user doesn't end up with the Continue or Quit dialog. If you happen to use the Stratalogic component, you may do something like:

Private oExceptionReporter As SLSExceptionReporter

Private Sub OnThreadException(ByVal sender As Object, _
                     ByVal e As ThreadExceptionEventArgs)
  oExceptionReporter = New SLSExceptionReporter.ExceptionReporter
  oExceptionReporter.ContactEmail = "myemail@mydomain.com"
  oExceptionReporter.DisplayException(e.Exception)
End Sub

Part II: Safe Form Template

Now, let's inherit all of our forms from this one, right? Now I'm a bit lazy.. err.. efficient I mean, so I want to do this the easiest possible way. I won't go into the finer points of creating templates; instead, I'll give you one to start from. I did this using Visual Studio .NET 2003. I'm not sure what the differences would be for other versions, but if you're using 2003, browse to C:\Program Files\Microsoft Visual Studio .NET 2003\Vb7.

  1. Open VBProjectItems and create a file called SafeForm.vsz to configure your form wizard:
    VSWIZARD 6.0
    Wizard=VsWizard.VsWizardEngine.7.1
    Param="WIZARD_NAME = SafeForm"
    Param="WIZARD_UI = FALSE"
    Param="PROJECT_TYPE = VBPROJ"
  2. Next, you'll need a .vsdir file in each of the areas that you would like to have the wizard accessible from.

    In the Local Project Items and UI folders, create a file called SafeForm.vsdir. In this file, type:

    ..\SafeForm.vsz|SafeForm|#3050|10|#3051|
             {164B10B9-B200-11D0-8C61-00A0C91E29D5}|4527| |Form.vb
  3. Now, go back up to C:\Program Files\Microsoft Visual Studio .NET 2003\Vb7\VBWizards.
  4. Create a folder called SafeForm and two folders inside that called Scripts and Templates.
  5. There should be a folder called 1033 under each of these two directories.
  6. Under Templates\1033, create a file called Form.vb and paste the following code:
    #Region " Imported NameSpaces "
    Imports System
    Imports System.Threading
    #End Region
    
    ''' -----------------------------------------------------------
    ''' Project : ExceptionHandling
    ''' Class : SafeForm
    ''' 
    ''' -----------------------------------------------------------
    ''' <summary>
    ''' The SafeForm class will encapsulate methods
    ''' to handle unhandled exceptions from forms that
    ''' inherit from this class.
    ''' </summary>
    ''' <remarks>
    ''' </remarks>
    ''' <history>
    ''' [John Saunders] 1/21/2005 Created
    ''' </history>
    ''' -----------------------------------------------------------
    
    Public Class [!output SAFE_ITEM_NAME]
    Inherits System.Windows.Forms.Form
    
    #Region " Windows Form Designer generated code "
    
    Public Sub New()
      MyBase.New()
    
      'Hook the ThreadException event to the OnThreadException method
      AddHandler Application.ThreadException, AddressOf OnThreadException
    
      'This call is required by the Windows Form Designer.
      InitializeComponent()
    
      'Add any initialization after the InitializeComponent() call
    
    End Sub
    
    'Form overrides dispose to clean up the component list.
    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
      If disposing Then
        If Not (components Is Nothing) Then
          components.Dispose()
        End If
      End If
      MyBase.Dispose(disposing)
    End Sub
    
    'Required by the Windows Form Designer
    Private components As System.ComponentModel.IContainer
    
    'NOTE: The following procedure is required by the Windows Form Designer
    'It can be modified using the Windows Form Designer. 
    'Do not modify it using the code editor.
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
      components = New System.ComponentModel.Container()
      Me.Text = "[!output SAFE_ITEM_NAME]"
    End Sub
    
    #End Region
    
    #Region " Internal Methods "
    
    Private Sub OnThreadException(ByVal sender As Object, _
                       ByVal e As ThreadExceptionEventArgs)
    'Handle any unforeseeable exceptions here.
      MessageBox.Show(e.Exception.Message)
    End Sub
    
    #End Region
    
    End Class
  7. You will need a file called default.js in the Scripts\1033 folder:
    //
    // Copyright (c) Microsoft Corporation 2001-2002. All rights reserved.
    //
    
    function OnFinish(selProj, selObj)
    {
      var oldSuppressUIValue = true;
      try
      {
        oldSuppressUIValue = dte.SuppressUI;
        var bSilent = wizard.FindSymbol("SILENT_WIZARD");
        dte.SuppressUI = bSilent;
    
        var strItemName = wizard.FindSymbol("ITEM_NAME");
        var strTemplatePath = wizard.FindSymbol("TEMPLATES_PATH");
        var strTemplateFile = strTemplatePath + "\\Form.vb";
    
        var VSProject = selProj.Object;
        var refs = VSProject.References;
        var ref;
        ref = refs.Add("System");
        ref = refs.Add("System.Data");
        ref = refs.Add("System.Drawing");
        ref = refs.Add("System.Windows.Forms");
    
        var item = AddFileToVSProject(strItemName, selProj, 
                              selObj, strTemplateFile, true);
        if( item )
        {
          item.Properties("SubType").Value = "Form";
          var editor = item.Open(vsViewKindPrimary);
          editor.Visible = true;
        }
    
        return 0;
      }
      catch(e)
      {
        switch(e.number)
        {
          case -2147221492 /* OLE_E_PROMPTSAVECANCELLED */ :
            return -2147221492;
    
          case -2147024816 /* FILE_ALREADY_EXISTS */ :
          case -2147213313 /* VS_E_WIZARDBACKBUTTONPRESS */ :
            return -2147213313;
    
          default:
            ReportError(e.description);
            return -2147213313;
        }
      }
      finally
      {
        dte.SuppressUI = oldSuppressUIValue;
      }
    }
  8. Now, start Visual Studio and create a Visual Basic .NET Windows Application.
  9. Right-click Add New Item... and you should see a new choice called "Safe Form".
  10. After adding the Safe Form to your project, make sure that all other forms inherit from SafeForm and not System.Windows.Forms.Form.

Now, all unhandled exceptions are managed each time you create a new Windows Forms project, since you will have the SafeForm template there to inherit from. You can also include any other code in your template to make starting a new project easier.

Enjoy.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

JSaunders
Web Developer
United States United States
No Biography provided

Comments and Discussions

 
GeneralBrilliant Idea! PinmemberDigiOz Multimedia5-May-08 12:12 
GeneralSLS Exception Reporter no longer available PinmemberMisterT992-Jun-07 6:19 
AnswerRe: SLS Exception Reporter no longer available PinmemberPandaWood29-Jul-08 19:00 
Generaldebugging pocket PinmemberRenatoSuga4-Dec-06 4:24 
AnswerRe: debugging pocket PinmemberJSaunders4-Dec-06 5:54 
GeneralYou god like individual Pinmemberwheelibin12-Sep-06 7:48 
GeneralEven simpler PinmemberPinx8-Feb-05 13:59 
GeneralDebug PinmemberSerge Baltic25-Jan-05 4:55 
GeneralRe: Debug PinmemberJSaunders25-Jan-05 5:12 
GeneralRe: Debug PinmemberSerge Baltic26-Jan-05 6:19 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.141223.1 | Last Updated 26 Jan 2005
Article Copyright 2005 by JSaunders
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid