Results 1 to 10 of 10

Thread: Unhandled exceptions

  1. #1

    Thread Starter
    Lively Member
    Join Date
    Jan 2010
    Posts
    117

    Unhandled exceptions

    As far as I know, there are 3 events that are fired when unhandled exceptions happen within Windows Forms application: Windows.Forms.Application.ThreadException, AppDomain.CurrentDomain.UnhandledException and MyApplication.UnhandledException.

    1. Do I need to handle (subscribe to) all these three events?
    2. What is the difference between the last two events?
    3. Where exactly should I put SetUnhandledExceptionMode statement? If it is placed in Sub MyApplication_Startup() or Sub New(), exception is thrown.

  2. #2
    You don't want to know.
    Join Date
    Aug 2010
    Posts
    4,578

    Re: Unhandled exceptions

    1. No, you only need to handle one of these events.

    2. This has a longer answer.

    AppDomain.UnhandledException is the most general-purpose version of this event. It's in a very core library of .NET, so it can't make assumptions that it's running in a particular kind of application. That's why all it really does is tell you what exception was thrown and whether it's going to kill the application.

    Application.ThreadException is specific to Windows Forms. It has an extra-special behavior: in certain cases, handling this event means the application will NOT terminate after the unhandled exception, and if that happens the AppDomain.UnhandledException event is NOT raised. So what we deduce from this is Windows Forms is a layer on top of the AppDomain, and this event lets some unhandled exceptions "be handled" by that layer.

    MyApplication.UnhandledException actually maps to Microsoft.VisualBasic.WindowsFormsApplicationBase.UnhandledException. As you can imagine, it's specific to "VB .NET Windows Forms applications" and requires the VB Application Framework to have been enabled (it is enabled by default.) This one lets you choose if the application is going to exit or not.

    So I think the difference between the last two is how easy they make it to decide what to do in response to the exception. Application.ThreadException uses the Application Configuration File to determine its behavior. MyApplication.UnhandledException uses a boolean on the EventArgs parameter.

    There is some wording that indicates Application.ThreadException is specific to "threads created and owned by Windows Forms". I don't know, specifically, what that means, but I have a feeling in most applications it means "If you made a Windows Forms application you can use this."

    3. I wouldn't use that method at all. But based on the documentation it will be very hard to set it within a VB application:
    Call SetUnhandledExceptionMode before you instantiate the main form of your application using the Run method.
    That means you need to call it as part of the application's Sub Main(), but to be able to do that you generally have to disable the VB application framework, which means the Windows Forms-specific events are harder to use.

    Advice:
    It doesn't matter which of the three events you handle, but MyApplication.UnhandledException will be the easiest from a VB app. I would NOT use any of the behaviors that let the application continue running when an exception is unhandled. That can cause your application to get into very weird states. The best thing to do in response to unhandled exceptions is to try to log that exception (sometimes logging can throw another!), then quit as gracefully as possible.
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

  3. #3

    Thread Starter
    Lively Member
    Join Date
    Jan 2010
    Posts
    117

    Re: Unhandled exceptions

    Thank you for such an extensive answer.
    1. I must say there is quite a lot of contradiction on this matter. For example, here it is suggested to use the first two events, here - all three events and this book suggests that the first event is enough for WinForm applications.
    2. I am still not sure I understand the real difference among those two. What type of events could be captured by one event that cannot be captured by another and vice versa? If they both capture exactly the same events, then what's the point of having them two.
    3. I was not going to use that at first, but then I found it being used in this official example. If I copy-paste that code, it simply throws an exception. So, I thought maybe I am missing something.

    Your advice would be the safest way of dealing with unhandled exceptions. However, .IsTerminating property will almost always be True and there will be no way to recover when exception occurs, even when something light-weighted and insignificant happens within the UI thread.

  4. #4
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,296

    Re: Unhandled exceptions

    Quote Originally Posted by riov View Post
    1. I must say there is quite a lot of contradiction on this matter. For example, here it is suggested to use the first two events, here - all three events and this book suggests that the first event is enough for WinForm applications.
    In C#, the third one doesn't exist and you have to handle both of the first two. The third one is something was specifically added to VB to make your life easier. VB automatically handles the first two and raises the third, so you only need to handle the third. When I say "automatically", I mean that code is generated by VB and added to your application. You are shown that code so that you can't break it.

  5. #5
    You don't want to know.
    Join Date
    Aug 2010
    Posts
    4,578

    Re: Unhandled exceptions

    1.

    The MSDN documentation is there to tell you how to use something. It doesn't suggest anything, but explains how the events interact. It suggests some things that I don't think are necessarily true and don't care to test. It seems to suggest UnhandledException won't catch an exception that's specifically thrown on the WinForms UI thread. I don't think that makes any sense, and it might only be true if you use Application.SetUnhandledException().

    I can tell you I've never used ThreadException or Application.SetUnhandledExceptionMode(), but UnhandledException has always worked for me. So my opinion is this is for some advanced case that seems dangerous to me and 99% of applications are probably not in, where they want to let a UI thread exception go unhandled without killing the UI thread.

    The second article uses all three to demonstrate that they exist. It doesn't really make many suggestions, and I think it's very cluttered.

    The book is there to tell you what letter an exam wants you to circle to get a certification. But it's not wrong: AppDomain.UnhandledException is the most general-purpose exception handler and is adequate for all .NET application types.

    2.

    It seems like they exist so you can separate "things that exploded on background threads" from "things that exploded on the UI thread". I don't know why you'd ever care about the difference. I never have. But it's there, in case you find a reason. Personally, I don't like the idea of a handler that doesn't catch all of the unhandled exceptions.

    3.

    You have to use a Sub Main() to properly use that method. In VB, that is very difficult because the VB designers decided to hide Sub Main from us. You have to disable many of VB's features and manually create the file, then configure your file to use it, then hand-write the code to bootstrap Windows Forms after it. C# doesn't hide the Main() entry point from you, so it's much easier to do this in C#. That's probably why the example's in C# and not VB, they didn't want to write a page of text explaining how to use a Sub Main() and field thousands of support calls from confused developers.

    Your advice would be the safest way of dealing with unhandled exceptions. However, .IsTerminating property will almost always be True and there will be no way to recover when exception occurs, even when something light-weighted and insignificant happens within the UI thread.
    If it's light-weight and insignificant you should have caught it in your code and recovered that way. If an exception makes it to this handler, it's because you didn't catch it. You don't know where it was, or what the application state was. It's never actually safe to continue. If it was, you'd have caught the exception.

    Many people disagree. They aren't right.
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

  6. #6
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,296

    Re: Unhandled exceptions

    Quote Originally Posted by Sitten Spynne View Post
    If it's light-weight and insignificant you should have caught it in your code and recovered that way. If an exception makes it to this handler, it's because you didn't catch it. You don't know where it was, or what the application state was. It's never actually safe to continue. If it was, you'd have caught the exception.

    Many people disagree. They aren't right.
    I concur. I've had this discussion at work in relation to an application where the users wanted a way to continue in the case of an unhandled exception. This came about because we let a bug through that basically prevented anyone using the application until we fixed it and redeployed. Ignoring the exception that was thrown was actually safe in that case but there was no way to know that until we examined it. If it hadn't been safe and they had continued, they may have corrupted their data. At their demand, we ended up handling the MyApplication.UnhandledException and providing an option there to close, restart or continue with a very clear statement that continuing could result in data loss or corruption and that they did so at their own risk. Of course, we all know that every user will just choose that option as a matter of course but we made it clear to them that it was on them if anything happened as a result. We also had the application send us an email with the details of the exception so they would never be able to claim that they didn't ignore the warning provided.

    In VB, the easiest option is to handle the application's UnhandledException event. Open the Application page of the project properties, click the View Application Events button, use the drop-downs at the top of the code window to create the event handler (just as for a form) and you're done. Here's the sort of code you can use to do what I described above:
    vb.net Code:
    1. Imports Microsoft.VisualBasic.ApplicationServices
    2.  
    3. Namespace My
    4.     ' The following events are available for MyApplication:
    5.     ' Startup: Raised when the application starts, before the startup form is created.
    6.     ' Shutdown: Raised after all application forms are closed.  This event is not raised if the application terminates abnormally.
    7.     ' UnhandledException: Raised if the application encounters an unhandled exception.
    8.     ' StartupNextInstance: Raised when launching a single-instance application and the application is already active.
    9.     ' NetworkAvailabilityChanged: Raised when the network connection is connected or disconnected.
    10.     Partial Friend Class MyApplication
    11.  
    12.         Private Sub MyApplication_UnhandledException(sender As Object, e As UnhandledExceptionEventArgs) Handles Me.UnhandledException
    13.             Dim message = $"An unexpected error has occurred.
    14.  
    15. Click 'Abort' to close the application.
    16. Click 'Retry' to restart the application.
    17. Click 'Ignore' to continue using the application without restarting.
    18.  
    19. Note that the state of the application cannot be known when an unexpected error occurs.  Ignoring the error could result in data loss or curruption and is not recommended.  Continue at your own risk."
    20.  
    21.             Select Case MessageBox.Show(message, "Unexpected Error", MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Error, MessageBoxDefaultButton.Button2)
    22.                 Case DialogResult.Abort
    23.                     e.ExitApplication = False
    24.                 Case DialogResult.Retry
    25.                     e.ExitApplication = False
    26.                     Windows.Forms.Application.Restart()
    27.                 Case DialogResult.Ignore
    28.                     e.ExitApplication = True
    29.             End Select
    30.         End Sub
    31.  
    32.     End Class
    33.  
    34. End Namespace

  7. #7

    Thread Starter
    Lively Member
    Join Date
    Jan 2010
    Posts
    117

    Re: Unhandled exceptions

    I believe using MyApplication.UnhandledException as the single global unhandled exception handler would yield unexpected results.
    For example, this exception will not be caught when placed in WinForms Load Sub:
    Code:
    Dim t As New Thread(Sub()
    		Dim i = 1
    		i /= 0
    	End Sub)
    t.Start()
    and when you place this code in a MyApplication_Startup Sub, the option given to the user to continue using the application will not work (that is a fatal exception, where you cannot recover, but you are not aware of it; setting e.ExitApplication to False will have no effect):
    Code:
    Dim i = 1
    i /= 0
    I believe I will stick with AppDomain.UnhandledException and play safe and not over-complicate my code by using different exception handlers simultaneously.

  8. #8
    You don't want to know.
    Join Date
    Aug 2010
    Posts
    4,578

    Re: Unhandled exceptions

    Quote Originally Posted by riov View Post
    I believe using MyApplication.UnhandledException as the single global unhandled exception handler would yield unexpected results.
    For example, this exception will not be caught when placed in WinForms Load Sub:
    Code:
    Dim t As New Thread(Sub()
    		Dim i = 1
    		i /= 0
    	End Sub)
    t.Start()
    and when you place this code in a MyApplication_Startup Sub, the option given to the user to continue using the application will not work (that is a fatal exception, where you cannot recover, but you are not aware of it; setting e.ExitApplication to False will have no effect):
    Code:
    Dim i = 1
    i /= 0
    I believe I will stick with AppDomain.UnhandledException and play safe and not over-complicate my code by using different exception handlers simultaneously.
    You're dealing with a DIFFERENT unhandled exception there. What you say is only true on a 64-bit machine. Microsoft decided developers' lives were too easy, and decided at some point the rule should be: "If an exception happens in the Load event of a Form and the user is using a 64-bit OS, we will silently ignore the exception so they can spend dozens of hours trying to figure out why it works on one machine and not on the other. This way we can sell more support calls."

    To sidestep it, never use Load again, use Shown, which doesn't have any hidden pitfalls.

    Also note there are several exceptions .NET won't let you handle, such as OutOfMemoryException. The short story there is "odds are slim you can do anything reasonable, even logging might not work".
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

  9. #9
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,296

    Re: Unhandled exceptions

    Quote Originally Posted by Sitten Spynne View Post
    You're dealing with a DIFFERENT unhandled exception there. What you say is only true on a 64-bit machine. Microsoft decided developers' lives were too easy, and decided at some point the rule should be: "If an exception happens in the Load event of a Form and the user is using a 64-bit OS, we will silently ignore the exception so they can spend dozens of hours trying to figure out why it works on one machine and not on the other. This way we can sell more support calls."
    Of course that's not actually true. What actually happened is that the Windows team and the .NET team had different ideas about how the situation should be handled and noone above them both made them work it out so the issue remained unresolved for a long, long time. I've not actually read anything about this but it seems to me that the issue has actually been fixed recently. I'm on the latest 64-bit version of Windows 10 and exceptions in the Load event handler don't seem to be swallowed any more. I don't know when the behaviour changed but it's a very good thing if it has. It was a stupid thing to allow to remain for so long.

  10. #10
    You don't want to know.
    Join Date
    Aug 2010
    Posts
    4,578

    Re: Unhandled exceptions

    I see it as "I can't tell you what the Load event does on a machine without testing it", which may as well be "undefined behavior".

    I like to write code that does the same thing on all machines, so until the "earliest platform that behaves in a well-defined manner" is the "only windows that .NET supports" I'm going to stick with using the Shown event, which has never behaved differently on any configuration.
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width