Logging unhandled exceptions in a Windows Application to file

Mikexx

Member
Joined
Sep 15, 2021
Messages
6
Programming Experience
1-3
Please be gentle to a C# newbie in Visual Studio.
I have been handed a Windows Forms application using .Net 4.6 and has 3 namespaces, two of which are dll Class Libraries.
I have looked at NLog and gone some way down the path with tutorials and examples. However it seems easy to output handled exceptions to a log file but struggling to output unhandled exceptions.
I've only touched Log4Net but this looks the same. All the example tutorials have a single namespace and no examples of where unhandled exceptions are recorded.

Is there a way I can output unhandled exceptions to a log file, not just in the executable but also from code in the dlls?
 
Solution
You can create a global exception handler by handling the Application.ThreadException and AppDomain.UnhandledException events, both of which are static, and you can then log your unforeseen exceptions there.
You can create a global exception handler by handling the Application.ThreadException and AppDomain.UnhandledException events, both of which are static, and you can then log your unforeseen exceptions there.
 
Solution
As a quick aside, I highly recommend moving past .NET 4.6. If possible go to 4.8. If not, at least use 4.6.2. There are some important security updates starting at 4.6.2, one of which is to use TLS 1.2 instead of the deprecated and insecure TLS 1.0, 1.1, and SSL 2.0.
 
As a quick aside, I highly recommend moving past .NET 4.6. If possible go to 4.8. If not, at least use 4.6.2. There are some important security updates starting at 4.6.2, one of which is to use TLS 1.2 instead of the deprecated and insecure TLS 1.0, 1.1, and SSL 2.0.
I have a feeling that 4.6.2 is the oldest .NET Framework still officially supported, so moving to that at least would definitely be a good idea. I doubt that any code changes would be required to go all the way to 4.8, which will provide the longest support window possible without going to .NET Core. I guess that it's just a matter of whether all the clients can install .NET Framework 4.8 or already have it installed.
 
I tell a lie. 4.5.2, 4.6 and 4.6.1 are supported until April next year. It's certainly still a good idea to move to the most recent point release you can, if not all the way to 4.8.
 
Many thanks for the replies.

I have moved to .Net 4.8 as suggested with no drama.

I added the following to Main()
C#:
            AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(UnhandledException);
            Application.ThreadException += new ThreadExceptionEventHandler(ThreadException);

And below Main() added
C#:
        static void UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            Exception ex = (Exception)e.ExceptionObject;
            // your code
        }

        static void ThreadException(object sender, ThreadExceptionEventArgs e)
        {
            Exception ex = e.Exception;
            // your code
        }

However this does catch unhandled exceptions in a dll. In the Output screen while debugging this I get:
Image added to an ImageList must either derive from Image or be an Icon.
but the above Methods aren't called. I had tried this route before but while it catches exceptions in the main e3xecutable it doesn't catch exceptions in the dlls.
 
Last edited by a moderator:
By any chance is that exception being thrown in the Form.Load event? If so, exceptions thrown in that WinForms event are never captured on a 64-bit system.
 
Many thanks for the reply. It is a 64 bit system and Visual Studio Output windows says:
Exception thrown: 'System.InvalidOperationException' in System.Windows.Forms.dll

If I compile to x86 CPU there's no change. Is this a system limitation?

I suppose all I want is the ability to pipe the contents of the Output window I see when debugging the application, into a file.
 
Let's step back...

Is the exception thrown a fatal exception? If not, that means it's an exception that is being handled by the library code. Although it is a bad practice in general to use exceptions for flow control, it's quite possible that some code that you are calling is using exceptions for flow control -- they throw an exception to indicate an error, but an error that can be handled.
 
Also you didn't answer whether the exception was being thrown during the Form.Load event. On 64-bit systems, the exception during that event is eaten to protect the system.

 
No, the form is loaded but the list of thumbnails is being populated. The exception occurs when a ImageList has a null image added.

The exception is unintentional, however it's a good example for where future logging would come in very useful for bug in the field.
 
Also you didn't answer whether the exception was being thrown during the Form.Load event. On 64-bit systems, the exception during that event is eaten to protect the system.

That issue has since been addressed. I'm not sure exactly when but it has been the case for some time now that exceptions in the Load event handler are treated the same way as any other exceptions. I just tested in VS 2019 16.11.2 in a project targeting x64 with this code:
VB.NET:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    Dim x = 1
    Dim y = 0
    Dim z = x \ y
End Sub
That's VB (I just had a VB project handy) but I'm sure that C# would be the same, because VB also suffered from the same issue in the past.
 
If the Output window is just mentioning a first chance exception then that means an exception was thrown, but if it's not affecting your app then it is probably being caught. Modify your exception settings in the debugger to break when that exception is thrown rather than when it goes uncaught and you may be able to get more information.
 
If I create an unhandled divide by zero exception in either the Application or the dlls then this is caught by CurrentDomain_UnhandledException() This will also terminate the Application.

If I create the following:
System.InvalidOperationException
HResult=0x80131509
Message=Image added to an ImageList must either derive from Image or be an Icon.
Source=System.Windows.Forms
StackTrace:
at System.Windows.Forms.ImageList.Original..ctor(Object image, OriginalOptions options, Color customTransparentColor)

This exception was originally thrown at this call stack:
System.Windows.Forms.ImageList.Original.Original(object, System.Windows.Forms.ImageList.OriginalOptions, System.Drawing.Color)

Then this is not caught by CurrentDomain_UnhandledException() but the application will continue.
 
Back
Top Bottom