Alex Rivera | Logout

Exception handling with multiple forms

Asked 2009-11-21T16:07:41.567
10

I'm seeing different behavior with exceptions being caught or not being caught when I am debugging vs. when I am running a compiled .exe. I have two forms (Form1 and Form2). Form1 has a button on it which instantiates and calls ShowDialog on Form2. Form2 has a button on it which intentionally produces a divide by zero error. When I'm debugging, the catch block in Form1 is hit. When I run the compiled .exe, it is NOT hit, and instead I get a message box that states, "Unhandled exception has occurred in your application. If you click continue, the application will ignore this error and attempt to continue. If you click Quit, the application will close immediately...Attempted to divide by zero". My question is why do you get different behavior when debugging vs. when running the .exe? If that is the expected behavior, then would it be considered necessary to put try/catch blocks in every single event handler? That seems kind of crazy over kill, doesn't it?

Here's the code for Form1.

public partial class Form1 : Form
{
    public Form1()
    {
            InitializeComponent();

    }

    private void button1_Click(object sender, EventArgs e)
    {
        try
        {
            Form2 f2 = new Form2();
            f2.ShowDialog();
        }
        catch(Exception eX)
        {
            MessageBox.Show( eX.ToString()); //This line hit when debugging only
        }
    }
}

Here's Form2's code:

public partial class Form2 : Form
{
    public Form2()
    {
            InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
            int x = 0;
            int y = 7 / x;

    }
}
Edit
Report

1 Answer

12

Yes, this is by design and is closely associated with the way Windows Forms works. In a Winforms app, code runs in response to messages posted to the active window by Windows. Every native Windows app contains a message loop to detect these messages. The Winforms plumbing ensures one of your event handlers runs in response; button1_Click in your example code.

Most Winforms controls implement their own event handlers. A PictureBox for example has a Paint event handler that ensures its Image is drawn to the screen. This is all done automatically, you don't have to write any code yourself to make this work.

There is however a problem when this code throws an exception, there is no way for you to catch such an exception since none of your own code was involved. In other words, there is no place for you to inject your own try block. The very last bit of your own program's code that was involved is the code that got the message loop started. The Application.Run() method call, normally in Program.cs. Or the Form.ShowDialog() call if you display a dialog. Either of those methods start a message loop. Putting a try block around the Application.Run() call isn't useful, the app will terminate after catching an exception.

To combat this problem, the Winforms message loop code contains a try block around the code that dispatches an event. Its catch clause displays the dialog you mentioned, it is implemented by the ThreadExceptionDialog class.

Getting to the point of your question: this catch clause really gets in the way of troubleshooting problems with your code when you debug. The debugger will only stop on an exception when there is no catch block that handles the exception. But when your code throws an exception, you'll want to know about it when you debug. The previously mentioned code in the message loop is aware whether or not a debugger is attached. If it is, it dispatches events without the try/catch block. Now, when y

answered 2009-11-21T17:39:46.000

Your Answer