How can I make something that catches all 'unhandled' exceptions in a WinForms application?

64,751

Solution 1

Take a look at the example from the ThreadException documentation:

public static void Main(string[] args)
{
   // Add the event handler for handling UI thread exceptions to the event.
    Application.ThreadException += new     
  ThreadExceptionEventHandler(ErrorHandlerForm.Form1_UIThreadException);

  // Set the unhandled exception mode to force all Windows Forms errors
  // to go through our handler.
  Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);

  // Add the event handler for handling non-UI thread exceptions to the event. 
  AppDomain.CurrentDomain.UnhandledException += new       
  UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
}

You might also want to not catch exceptions when debugging, as this makes it easier to debug. It is somewhat of a hack, but for that you can wrap the above code around with

 if (!AppDomain.CurrentDomain.FriendlyName.EndsWith("vshost.exe")) { ... }

To prevent catching the exceptions when debugging.

EDIT: An alternate way to check for your application running inside a debugger that feels cleaner than checking a filename.

(see comments by moltenform, Kiquenet and Doug)

if(!System.Diagnostics.Debugger.IsAttached) { ... }

This avoids the problem of using a different debugger than vshost.exe.

Solution 2

In NET 4, certain exceptions are no longer caught by default; these tend to be exceptions that indicate a (possibly fatal) corrupted state of the executable, such as an AccessViolationException.

Try using the [HandleProcessCorruptedStateExceptions] tag in front of your main method, e.g.

using System.Runtime.ExceptionServices.HandleProcessCorruptedStateExceptions

[HandleProcessCorruptedStateExceptions]
public static int Main()
{
    try
    {
        // Catch any exceptions leaking out of the program
        CallMainProgramLoop();
    }
    catch (Exception e) // We could be catching anything here
    {
        System.Console.WriteLine(e.Message);
        return 1;
    }
    return 0;
  } 

Solution 3

A nice example can be found at http://www.csharp-examples.net/catching-unhandled-exceptions/ Basically, change your main to:

static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
        Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
        AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

        Application.Run(new Form1());
    }

    static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
    {
        MessageBox.Show(e.Exception.Message, "Unhandled Thread Exception");
    }

    static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
    {
        MessageBox.Show((e.ExceptionObject as Exception).Message, "Unhandled UI Exception");
    }

Solution 4

You can use NBug library for that. With minimal setup like this:

NBug.Settings.Destination1 = "Type=Mail;[email protected];[email protected];SmtpServer=smtp.mycompany.com;";
AppDomain.CurrentDomain.UnhandledException += NBug.Handler.UnhandledException;
Application.ThreadException += NBug.Handler.ThreadException;

You can start collecting information on all unhandled bugs in your application, even when it's deployed to the clients. If you don't want to use a 3rd party library, you should attach to below events:

// These two should come before enabling visual styles or running the application
AppDomain.CurrentDomain.UnhandledException += ...
Application.ThreadException += ...
...
Application.Run(new Form1());
Share:
64,751
Isaac Bolinger
Author by

Isaac Bolinger

I've got more questions than answers.

Updated on August 14, 2021

Comments

  • Isaac Bolinger
    Isaac Bolinger over 2 years

    Up until now, I just put a try/catch block around the Application.Run in the Program.cs entry point to the program. This catches all exceptions well enough in Debug mode, but when I run the program without the debug mode, exceptions don't get handled anymore. I get the unhandled exception box.

    I don't want this to happen. I want all exceptions to be caught when running in non-debug mode. The program has multiple threads and preferably all exceptions from them get caught by the same handler; I want to log exceptions in the DB. Does anyone have any advice in how to do this?

  • Teoman Soygul
    Teoman Soygul about 13 years
    You're welcome. Use the NBug project discussion forum if you have further questions (nbusy.com/forum/f11) or use the [nbug] tag here.
  • neo2862
    neo2862 about 13 years
    Of course, you can also subscribe a "regular" event handler to the UnhandledException event. See msdn.microsoft.com/en-us/library/…
  • gideon
    gideon about 13 years
    Guys on Win7 + VS10, if I subscribe to these events the subscription doesn't run, instead the regular Windows Vista/7 dialog shows up Check Online for a Solution Or Close the Program.. etc. But if I do NOT subscribe, I get the regular generic .NET Unhandled Exception Window. This happens on Both Release and Debug builds, also tried setting Application.SetUnhandledExceptionMode(UnhandledExceptionMode‌​.CatchException); Doesn't change anything.
  • Teoman Soygul
    Teoman Soygul about 13 years
    @giddy, after handling the exceptions you should exit the application with Environment.Exit(1); if you don't want the error window displayed.
  • gideon
    gideon about 13 years
    @Teo thanks for your reply. I want my own error form to show up and then I want the app to exit. But the event subscription never runs, it just shows the generic Win Vista/7 dialog when it encounters exceptions. But if I don't subscribe the generic .NET unhandled exception dialog appears!
  • Teoman Soygul
    Teoman Soygul about 13 years
    @giddy Try hooking up to all possible unhandled exception events: UnhandledException, ThreadException (WinForms), DispatcherUnhandledException (WPF), UnobservedTaskException (Threading.Tasks). It is possible that you've missed one of these unhandled exception sources.
  • gideon
    gideon about 13 years
    I'm on winforms, and subscribed to both Unhandled and Thread Exception.
  • Teoman Soygul
    Teoman Soygul about 13 years
    Try something like this one: Application.ThreadException += (sender, e) => { new MyErrorForm(); Environment.Exit(0); }; note that I changed Environment.Exit(1); to Environment.Exit(0); which should prevent Vista/7 dialog.
  • Isaac Bolinger
    Isaac Bolinger about 13 years
    I made a background worker, and in the dowork event handler I intentially caused a null reference exception. However it didn't get caught by the AppDomain.CurrentDomain.UnhandledException in spite of setting these: Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_Thr‌​eadException); Application.SetUnhandledExceptionMode(UnhandledExceptionMode‌​.CatchException); AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledExcept‌​ion);
  • Can Gencer
    Can Gencer about 13 years
    @IsaacB, background worker catches exceptions itself. You can check the exception in the RunWorkerCompleted even, looking at the RunCompletedEventArgs.Error property.
  • Can Gencer
    Can Gencer about 13 years
    You can test the exception handling for additional threads by putting this into the OnLoad of your main form. new Thread(() => { throw new Exception(); }).Start();
  • Nazar Grynko
    Nazar Grynko almost 11 years
    Unfortunately handling UnhandledException will not stop application from terminating :(
  • moltenform
    moltenform about 8 years
    Instead of the FriendlyName.EndsWith hack, try Debugger.IsAttached which is cleaner.
  • Kiquenet
    Kiquenet about 7 years
    Can I use AppDomain.CurrentDomain.UnhandledException and Application.ThreadException too with [HandleProcessCorruptedStateExceptions] tag ?
  • Kiquenet
    Kiquenet about 7 years
    GitHub is the new source repo. Send pull requests there: github.com/soygul/NBug
  • Kiquenet
    Kiquenet about 7 years
    I dont know the good patterns and practices. Be careful when using the AppDomain.UnhandledException event Revision note: I was pointed by Phillip Haack of this important omission. Other common source of mistakes is the Application.ThreadException event. There are lots of caveats when using them,
  • Kiquenet
    Kiquenet about 7 years
    IMHO, add notes in your answer, use Debugger.IsAttached for prevent catching the exceptions when debugging and handling UnhandledException will not stop application from terminating ( reference by @NazarGrynko)
  • Kiquenet
    Kiquenet about 7 years
    Can I combine AppDomain.CurrentDomain.UnhandledException and Application.ThreadException with [HandleProcessCorruptedStateExceptions] tag ? stackoverflow.com/a/5763158/206730 CLR Inside Out - Handling Corrupted State Exceptions certain exceptions are no longer caught by default; these tend to be exceptions that indicate a (possibly fatal) corrupted state of the executable, such as an AccessViolationException.
  • Doug
    Doug about 6 years
    In order to not catch exceptions while debugging, you can check System.Diagnostics.Debugger.IsAttached property value. It's more elegant than checking the running executable name.
  • person27
    person27 almost 4 years
    There's also usually the preprocessor variable DEBUG, for readers in the future.
  • Jesse Chisholm
    Jesse Chisholm over 2 years
    @person27 re: DEBUG using that conditional protects you from running this in a DEBUG compile. The recommended techniques let you catch the otherwise unhandled exceptions regardless of DEBUG or RELEASE compile, but protect from trying to double catch them in your code AND in the debugger code.