Unhandled exceptions


face=Tahoma>There are two kinds of
threads executing inside managed code:  the ones we start in managed code
and the ones that wander into the CLR. 
The ones that started in managed code include all calls to
Thread.Start(), the managed threadpool threads, and the Finalizer
thread(s).
style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman'">


face=Tahoma>  style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman'">


face=Tahoma>For all the threads we
start in managed code, the CLR has its own exception backstop and nothing will
leak out to the OS unhandled exception filter.  We can call the
AppDomain.UnhandledException event from this backstop.
style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman'">


face=Tahoma>  style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman'">


style="mso-bidi-font-family: Tahoma">For the ones
that wander into managed code, we are registered on the OS unhandled exception
filter so we can call the AppDomain.UnhandledException from there.  Of
course, different unmanaged components are registered in a rather random order
on the OS unhandled exception filter.  Some of them chain nicely. 
Others (like the VC6 filter) might decide to rip the process without chaining
under certain circumstances.


style="mso-bidi-font-family: Tahoma"> size=2> 


style="mso-bidi-font-family: Tahoma">So you are
only completely assured of getting
the AppDomain’s UnhandledException event on the managed
threads.


style="mso-bidi-font-family: Tahoma"> size=2> 


style="mso-bidi-font-family: Tahoma">Another
subtlety is that you must register for this event in the Default AppDomain. style="mso-spacerun: yes">  That’s because – by the time the
exception is unhandled – the thread has unwound out to the default AppDomain.
 That’s where all threads start
executing and that’s where they eventually unwind to. style="mso-spacerun: yes">  This is an unfortunate restriction for
some scenarios, but it’s not clear whether it will ever be
relaxed.


style="mso-bidi-font-family: Tahoma"> size=2> 


style="mso-bidi-font-family: Tahoma">Finally, the
CLR has some default policy for which unhandled exceptions should terminate the
process and which ones should be swallowed. style="mso-spacerun: yes"> Generally, unhandled exceptions on
threadpool threads, the Finalizer thread(s) and similar “reusable” threads are
swallowed.  We simply terminate the
current unit of work and proceed to the next one. style="mso-spacerun: yes">  Unhandled exceptions on the main thread
of a managed executable will terminate the
process.


style="mso-bidi-font-family: Tahoma"> size=2> 


style="mso-bidi-font-family: Tahoma">Nobody
particularly likes the defaults that were chosen. style="mso-spacerun: yes">  But everyone seems to have conflicting
opinions on what would have made better defaults. style="mso-spacerun: yes"> And, at this point, nothing is likely to
change.  The UnhandledException
event is there so that you can install your own policy. style="mso-spacerun: yes">  You can terminate the process, log the
failure, trap to the debugger, swallow the exception or any other
behavior.


style="mso-bidi-font-family: Tahoma"> size=2> 

Comments (11)

  1. aileen says:

    keep showing up on my pc when turn on

  2. aileen says:

    keep showing up on my pc when turn on

  3. .. the entry seem to imply that UnhandledException handle can be used to choose whether or not the errot is swollawed. This does not seem to be the case to me. The best you can hope to do is test if the application will termiate then restart if it is going to. Also the application always pops up an standard error box to inform the user an error has occured, there seem to be no way to suppress this.

    Or am I missing something?

  4. Chris Brumme says:

    It turns out that I’m the only person on our team who remembers the design I described in the above post. In other words, I must have imagined parts of it.

    You are correct that in V1 & V1.1, there is no way to swallow an exception via the UnhandledException event, if that exception is going to terminate the process. In that sense, the event is strictly a notification.

    You can still do the reverse. If an exception would be swallowed, you can use the UnhandledException event to terminate the process via System.Environment.Exit or some other technique.

    In a future version, we will give the host better control over how unhandled exceptions should be treated. But that’s no excuse for my mistakes in the above post.

  5. Thanks for getting back so quickly … actaully I’ve been playing with it a bit more and have a few further comments.

    I defintly want to use AppDomain.UnhandleException from a standard winforms app to implement some last chance error recovery. Trouble is the event seem a little flakey, I get different behavior depending on whether I’m debugging thorough visual studio or not.

    If it is in debug mode then unhandled exception will be caught by the event and the application will decided that the error is faltal and termiate the event.

    If the app is not in run from inside the debugger (but still a debug build) then a standard .NET error box will be shown asking if you want to continue or quit. If you continue then the app will recover reasonably well, if you quit it closes down, but either way the AppDomain.UnhandledException will not fire.

    Ideally what I’d like to do is suppress the standard error page, show my own custom error page and offer the user the chance to restart the app if it is going to terminate. But I’d settle from any hints or tips that offer me a little consistancy. Since I know whether the app is going to terminate or not it would be reasonable easy to kick of a new process using System.Diagnostics.Process, but only if the event actually fires!

    Thanks

  6. Actual there seems to be on way to turn off the "An unhandled exception …" digaol box in a winforms app. In this makes the AppDomain.UnhandledException event pretty useless in winforms app as it never get’s fired when the code is running outside the debugger.

    Went to huge efforts trying to find out how to turn off the dialog, then found out there’s very easy whay round it. Just use the System.Windows.Form.Application.ThreadException event instread.