7

This is related to a previous question.

What I'm trying to understand now is how come UI thread exceptions can be prevented from terminating the application while non-UI exceptions can't be.

For reference, see this example.

Most importantly, what I would like to be able to do in that case is "silently" terminate the process--without displaying the Windows dialog box that asks whether I'd like to send an error report or not.

This is my AppDomain UnhandledExceptionHandler:

private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{            
    try
    {
        // Maybe do some logging here if allowed
    }
    catch
    {
    }

    // then just terminate the application
    Application.Exit();            
}

UPDATE
In light of comments in this answer, I'd like to clarify that most importantly I'd like to find out more about the mechanism that enables the UI thread to have an early opportunity to catch unhandled exceptions via the Application.ThreadException mechanism. And whether such behavior could be implemented on a non-UI thread.

Community
  • 1
  • 1
Mike Dinescu
  • 48,812
  • 10
  • 104
  • 136

3 Answers3

8

After doing some more searches on Google I found this very interesting explanation that was given to the same problem as described by Jeff Atwood on his blog.

Hi all, Sorry for the confusion. This behavior is actually the design, though the design can be a little convoluted at times.

The first thing to understand is that the UnhandledException event is not an unhandled exception "handler". Registering for the event, contrary to what the documentation says :-(, does not cause unhandled exceptions to be handled. (Since then they wouldn't be unhandled, but I'll stop with the circular reasoning already...) The UnhandledException event simply notifies you that an exception has gone unhandled, in case you want to try to save state before your thread or application dies. FWIW, I have filed a bug to get the docs fixed.

Just to complicate things, in v1.0 and 1.1, an unhandled exception did not always mean that your application would die. If the unhandled exception occurred on anything other than the main thread or a thread that began its life in unmanaged code, the CLR ate the exception and allowed your app to keep going. This was generally evil, because what would often happen was, for example, that ThreadPool threads would silently die off, one by one, until your application wasn't actually doing any work. Figuring out the cause of this kind of failure was nearly impossible. This may be why Jeff thought it worked before...he just always saw crashes on non-main threads.

In v2.0, an unhandled exception on any thread will take down the application. We've found that it's tremendously easier to debug crashes than it is to debug hangs or the silent-stoppage-of-work problem described above.

BTW, on my 1.1 machine the example from MSDN does have the expected output; it's just that the second line doesn't show up until after you've attached a debugger (or not). In v2 we've flipped things around so that the UnhandledException event fires before the debugger attaches, which seems to be what most people expect.

Jonathan Keljo CLR Exceptions PM Jonathan Keljo on February 18, 2005 10:02 PM

However, I'm still interested in how the UI thread accomplishes the trick of allow you to have a catch-all handler for all UI thread exceptions.

Even more, I'm very interested in a way to disable the .NET JIT Debugging Dialog for my application only (without disabling it for the whole machine as seen here)

Cœur
  • 32,421
  • 21
  • 173
  • 232
Mike Dinescu
  • 48,812
  • 10
  • 104
  • 136
3

It's not that any AppDomain exception terminates the application, it's that unhandled exceptions (of any sort) will tear down the AppDomain and terminate the application.

The issue here is that you can handle UI thread exceptions explicitly, at a fairly high level. However, when you have an unhandled exception in a background thread, there is no means of handling it easily at the same level, so it tends to propagate up and pull down the application. Application.ThreadException allows you to at least know that this is what caused the error, and log it if necessarily.

Unhandled exceptions in the UI thread will cause the same thing to happen.

Reed Copsey
  • 522,342
  • 70
  • 1,092
  • 1,340
  • @Reed: "Unhandled exceptions in the UI thread will cause the same thing to happen." - this is not true. Please create a test application and try it for yourself. – Mike Dinescu Aug 19 '09 at 17:15
  • 1
    Technically, I should have said "Unhandled exceptions on the main thread". Windows Forms adds its own exception handling behavior on the UI thread (since it's entirely running on the UI thread) that changes the main thread's behavior. Make a console application, and try this, and you'll see it doesn't matter what thread things occur on - they'll all tear down the application. – Reed Copsey Aug 19 '09 at 17:20
  • Then I should restate my question: How does the UI thread accomplish it's general exception handling behavior? Is that something I could replicate as behavior for a non-UI thread? – Mike Dinescu Aug 19 '09 at 17:24
  • @Miky D: You will need to catch exceptions on every Thread. Keep in mind any threads that might get created behind the scenes without manually starting a Thread yourself. – Max Schmeling Aug 19 '09 at 17:25
  • 1
    Well, @Max and @Reed, clearly not all UI functions contain exception handlers in themselves and yet the exceptions are caught by the catch-all Applicaiton.ThreadException handler. What's the "catch" (pun intended)?? – Mike Dinescu Aug 19 '09 at 17:29
2

Does this help at all?

Improved Unhandled Exception behavior in .NET 2.0

Also, this code seems to "die quietly". Are you looking for something else?

using System;

namespace UnhandledException
{
    class Program
    {
        static void Main(string[] args)
        {
            AppDomain.CurrentDomain.UnhandledException += CurrentDomainUnhandledException;

            throw new NotImplementedException();
        }

        static void CurrentDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            Exception exception = (Exception)e.ExceptionObject;
            System.Console.WriteLine("exception=[" + exception.ToString() + "]");

            Environment.Exit(-1);
        }   
    }
}
Cœur
  • 32,421
  • 21
  • 173
  • 232
Michael Maddox
  • 11,633
  • 5
  • 35
  • 39
  • Yes it does.. I had just finished reading the post and comments when you posted that. +1 however.. – Mike Dinescu Aug 19 '09 at 17:53
  • Yes, Environemnt.Exit seems to do the trick! I'll leave the questions open for a little while longer to see if anybody can give an insight into how the UI thread accomplishes the catch-all exception. Otherwise you'll have my vote for the accepted answer! – Mike Dinescu Aug 19 '09 at 18:07
  • Application.ThreadException is just another variant of an "unhandled exception handler". There are many variants (Console App vs. WinForms vs. WebForms vs. WCF, etc.). I'm not sure I understand your question. In general, I implement every one that is applicable. – Michael Maddox Aug 19 '09 at 18:18
  • Something to keep in mind: Enviroment.Exit terminates the whole process so if you application lives in an AppDomain side by side with other AppDomains all of them will go down together.. – Mike Dinescu Aug 19 '09 at 18:30