Strange exception behaviour

J

Jos Beelen

Examine the following code fragment used from within the
main form of a windows forms application when clicking a
button:

private void button1_Click(object s, System.EventArgs e)
{
try
{
Form2 f2 = new Form2();
f2.ShowDialog();
}
catch (Exception ex)
{
MessageBox.Show ("Error catched");
}
}

Form2 also contains a button and when the button is
clicked, a divide by zero exception is created by the
following code:

private void button2_Click(object s, System.EventArgs e)
{
int i,j;
i = 0;
j = 1/i; // Divide by zero
}


Because the exception is not catched in Form2, I expect
this exception is catched by the code fragment in the main
form by displaying the message "Error catched", but the
behaviour is very strange.

1. When running the application from within VS2003 using
F5 (=debug), the error is catched, so my messagebox is
displayed. This is the same for both running in release
mode and debug mode. This is the expected behaviour !!!!

2. When running the application from wihtin VS2003 using
ctrl-F5 (=no debug), the standard "unhandled exception"
window is displayed. This is the same for both running in
release mode and debug mode. This behaviour is also the
same when running the application outside the studio (=
the behaviour when the application is deployed).

Question:
Why is the exception in -2- not catched by the implemented
catch. I expected the same behaviour as in -1-

I know I can use Application.ThreadException to catch the
unhandled exception, but this is not the requested
functionality. I want the calling method to handle the
exception.

Who can help me ....

Thanks in advance.
 
G

Guest

Hi Jos,

The difference in behaviour that you're seeing comes from the NativeWindow
class where it assigns a different Callback delegate based on whether or not
a debugger is attached. The DebuggableCallback delegate has no try/catch
block so the exception "bubbles up" to your handler, whereas the Callback
delegate has a try/catch block and in the catch passes the exception directly
to the OnThreadException handler.

If you want to prevent this from occurring in an application, you need to
add a handler to the Application.ThreadException event (and you should also
add a handler to AppDomain.UnhandledException).

Hope this helps.

Regards,
Matt Garven
 
J

Jos Beelen

Matt, thank you for your quick response.

I do understand the difference now, but when no debugger
is attached, I expect a "normal" behaviour.

According to the documentation (.NET Framework developers
guide, Exceptions Overview c#), the runtime should search
the stack for a caller who handles the exception. When no
match is found, the exception is treated as unhandled.

So when an exceptions occurs somewhere, it bubbles up
until a catch is found which is able to handle the
exception. In my example the first catch found should be
in the button1_Click method. So I expect my messagebox is
displayed in this case.

Instead of displaying my messagebox, the run-time handles
it as an unhandled exception. But it is handled, it is
within a try - catch block !!!

Is this "as designed", a bug or do I miss something ???


Jos
 
B

Bruce Wood

I think that Matt is describing an effect that I have also seen when
invoking just-in-time debugging: an exception occurs in an event
handler, but the JIT debugger can't tell me where: all it can tell me
is that it happened somewhere inside a .ShowDialog() invocation. So,
I'm left sitting with the debugger pointing to the .ShowDialog() call,
and showing an exception that obviously happened in some event handler
deep inside the form I called.

As Matt said, this has to do with how .NET is handling calls to the
native windowing API. Somehow it plays some trickery with the stack at
run time so that your event handler kinda-isn't-on-the-stack when the
exception occurs, or is in a different thread or something. I'm a bit
foggy on it myself.
 
G

Guest

It is as designed, but it's nothing particularly magical - it's just a bit
obscure.

Your try/catch sits lower than the try/catch in the Callback method of
NativeWindow, so it is the Callback method which handles the exception first.
It passes the exception directly to the OnThreadException handler and then
you see the "unhandled exception" dialog.

However, when your debugger is attached (regardless of release mode or debug
mode), NativeWindow uses the DebuggableCallback method instead of the
Callback method. This does not have the try/catch block so the exception is
free to bubble up the stack and therefore gets caught by your try/catch block.

Why? You'll notice that when the debugger is attached the form closes after
the exception occurs (ie it dies horribly). However, when the debugger isn't
attached, the form stays on the screen (ie doesn't die). Perhaps this was
intended as a way to add extra stability to WinForms apps so they don't fall
over every time an exception occurs.

Hope this helps.

Regards,
Matt Garven
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top