I am getting a NullReferenceException in release mode, but not in debug mode.
To try and find the error, I have added an UnhandledException handler, however the exception is not sent to the handler.
There is no gui code, it is console only.
The program exits with the message:
System.NullReferenceException: Object reference not set to an instance of an object.
To be clear, I don't get this in debug mode at all, I only get it when it is run in release mode from the console, so I can't debug it to find where the problem is.
why does setting the AppDomain.CurrentDomain.UnhandledException not work?
static void errhandler(object sender, UnhandledExceptionEventArgs args)
{
Exception e = (Exception)args.ExceptionObject;
Console.WriteLine(e.StackTrace + ' ' + e.ToString());
System.Environment.Exit(1);
}
[System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand, Flags = System.Security.Permissions.SecurityPermissionFlag.ControlAppDomain)]
static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException +=new UnhandledExceptionEventHandler(errhandler);
try
{
new test(args[0], args[1]);
}
catch (Exception e)
{
Console.WriteLine(e.StackTrace + ' ' + e.ToString());
}
}
For handling ALL exceptions we use this:
private static void SetupExceptionHandling()
{
// Add the event handler for handling UI thread exceptions to the event.
Application.ThreadException += ApplicationThreadException;
// 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 += AppDomainUnhandledException;
// This AppDomain-wide event provides a mechanism to prevent exception escalation policy (which, by default, terminates the process) from triggering.
// Each handler is passed a UnobservedTaskExceptionEventArgs instance, which may be used to examine the exception and to mark it as observed.
TaskScheduler.UnobservedTaskException += TaskSchedulerUnobservedTaskException;
// Add the event handler for handling UI thread exceptions to the event.
Dispatcher.CurrentDispatcher.UnhandledException += DispatcherUnhandledException;
}
I hope, it may help you.
Your code is correct. Proof:
static void errhandler(object sender, UnhandledExceptionEventArgs args)
{
Console.WriteLine("Errhandler called");
Exception e = (Exception)args.ExceptionObject;
Console.WriteLine(e.StackTrace + ' ' + e.ToString());
System.Environment.Exit(1);
}
public static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(errhandler);
string s = null;
s.ToString();
}
prints "Errhandler called".
Thus, your problem is somewhere else.
Why not put a try catch block in the code?
Like this:
[System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand, Flags = System.Security.Permissions.SecurityPermissionFlag.ControlAppDomain)]
static void Main(string[] args)
{
try
{
new test(args[0], args[1]);
}
catch(Exception e)
{
Console.WriteLine(e)
}
}
Or do you need to use a Eventhandler?
Related
I have coded this inside App startup
inside App.xaml.cs
public App()
{
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);
DispatcherUnhandledException += App_DispatcherUnhandledException;
Application.Current.DispatcherUnhandledException += new DispatcherUnhandledExceptionEventHandler(Application_DispatcherUnhandledException);
TaskScheduler.UnobservedTaskException += new EventHandler<UnobservedTaskExceptionEventArgs>(Application_DispatcherUnhandledException2);
this.Dispatcher.UnhandledException += Dispatcher_UnhandledException;
}
private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
writeMessage(e.Exception);
}
private void Dispatcher_UnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
writeMessage(e.Exception);
}
private static void writeMessage(Exception e)
{
string srMsg = e.InnerException?.Message;
if (srMsg != null)
{
srMsg += "\r\n\r\nStack\r\n" + e.InnerException?.StackTrace;
}
if (srMsg == null)
{
srMsg = e.Message + "\r\n\r\nStack\r\n" + e.StackTrace;
}
srMsg += "\r\n\r\n*********\r\n\r\n";
File.AppendAllText("global_errors.txt", srMsg);
}
private static void Application_DispatcherUnhandledException2(object o, UnobservedTaskExceptionEventArgs e)
{
writeMessage(e.Exception);
}
private static void Application_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
writeMessage(e.Exception);
}
private static void MyHandler(object sender, UnhandledExceptionEventArgs args)
{
Exception e = (Exception)args.ExceptionObject;
writeMessage(e);
}
However, this is still not capturing task factory errors
For example
Nothing proposed in this thread works WPF global exception handler
Getting the StackTrace can be done in several ways, it really depends on what fits your needs the best. Anyhow I would suggest you, to try the following.
Add a callback to the AppDomain.FirstChanceException event, at the start of your project e.g. before the errors occur which you want to catch/log. This could look something like the following:
public static Main()
{
AppDomain.CurrentDomain.FirstChanceException += CurrentDomain_FirstChanceException;
}
private static void CurrentDomain_FirstChanceException(object sender, FirstChanceExceptionEventArgs e)
{
}
After that, add the Environment.StackTrace in the CurrentDomain_FirstChanceException method. It will hold the current StackTrace as a string. From my testing it includes the FileName and FileLineNumber.
var currentStackTrace = Environment.StackTrace;
// Now it is on to you on what you want to do with the StackTrace. This could be some kind of logging.
Note that this will log ALL exceptions thrown by the AppDomain, no matter if they are handled by the code e.g. try/catch.
The exception is thrown only if you observe the Task by for example calling Wait() or .Result or accessing its Exception property.
Unobserved exceptions are not thrown unless you use the <ThrowUnobservedTaskExceptions> configuration element to revert back to the behavior that was the default in .NET Framework 4 and terminates the process:
<runtime>
<ThrowUnobservedTaskExceptions enabled="true"/>
</runtime>
If you really want to catch the exception, you should do it in the delegate that you pass to Task.Factory.StartNew. You may wrap this functionality in an extension method as suggested here.
This question already has answers here:
VS2010 does not show unhandled exception message in a WinForms Application on a 64-bit version of Windows
(5 answers)
Closed 5 years ago.
In an attempt to make this question a more Minimal, Complete, and Verifiable example, I am starting from scratch and trying to reproduce the problem in a minimal way. Please standby for new Question link
Problem Reproduced and Isolated Here
I've attempted to implement a global unhanded exception handler.
I have a WFA (Windows Form App).
In the Program class, I impliment the following code
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(Utility.UnhandledExceptionOccurred);
Application.ThreadException += new ThreadExceptionEventHandler(Utility.UnhandledExceptionOccurred);
if (!EventLog.SourceExists("TestEventSource"))
{
EventLog.CreateEventSource("TestEventSource", "TestEventLog");
MessageBox.Show("EventLog and Source Created. Restart Please");
return;
}
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
This is the Utility class with the Event Handlers
static class Utility
{
public static void UnhandledExceptionOccurred(object sender, UnhandledExceptionEventArgs e)
{
MessageBox.Show("This Program Has Crashed\r\nPlease report this to nearest IT specialist " +
"and restart the program");
Exception E = (Exception)e.ExceptionObject;
var errMsg = "UNHANDLED EXCEPTION \r\n";
errMsg += "OUTER: " + E.Message + "\r\n";
Exception Inner = E.InnerException;
int i = 1;
while (Inner != null)
{
errMsg += "INNER " + i.ToString() + ": " + Inner.Message + "\r\n";
Inner = Inner.InnerException;
i++;
}
errMsg += E.StackTrace;
EventLog.WriteEntry("TestEventSource", errMsg, EventLogEntryType.Error);
Application.Exit();
}
public static void UnhandledExceptionOccurred(object sender, ThreadExceptionEventArgs e)
{
MessageBox.Show("This Program Has Crashed\r\nPlease report this to nearest IT specialist " +
"and restart the program");
Exception E = e.Exception;
var errMsg = "UNHANDLED EXCEPTION \r\n";
errMsg += "OUTER: " + E.Message + "\r\n";
Exception Inner = E.InnerException;
int i = 1;
while (Inner != null)
{
errMsg += "INNER " + i.ToString() + ": " + Inner.Message + "\r\n";
Inner = Inner.InnerException;
i++;
}
errMsg += E.StackTrace;
EventLog.WriteEntry("TestEventSource", errMsg, EventLogEntryType.Error);
Application.Exit();
}
}
When I cause an exception in the main UI thread, This code works perfectly, catching the exception, writing to system event log, and exiting.
However, say I've got a new class in the same namespace.
class Foo
{
public Foo()
{
throw new Exception("A");
}
}
Then in Form1_onLoad I execute the following code
public void FormLoaded(object sender, EventArgs e)
{
var F = new Foo();
}
The exception is raised, but never caught.
So far as I can tell, there is no second thread running in the background which I have to implement new UnhandledException Handlers for. Is there?
What is going on here? if my classes are all in the same namespace, why won't these unhandled exceptions get caught by the handles in Application?
Some More Source
{
public EventLog Log = new EventLog();
Person P;
public Form1()
{
InitializeComponent();
Log.Source = "TestEventSource";
Log.WriteEntry("Form Initialized and Running");
throw new Exception("Exeption here is Caught");
}
public void FormLoaded(object sender, EventArgs e)
{
var F = new Foo(); //Exceptions here are not caught
}
}
NO, I am not raising the Exception in the constructor for Form1() at the same time that I create a new Foo() in FormLoaded. Just to clarify. It's Either one or the other. When I raise the Exception in Form1() constructor, it is caught. When I do not Raise said exception in Form1() Constructor, and Create a new Foo() in Form1Load, the Exception is NOT caught.
I copied most of your code, replaced your exception-handling-code with just a Debugger.Break() and skipped the EventLog stuff and run it. Creating Foo in OnLoad calls the handler with ThreadExceptionEventArgs, creating Foo in the forms constructor calls the one with UnhandledExceptionEventArgs.
I created a small test project and run your code, everything works as expected (VS2015 Community, AnyCpu/x64, .NET 4.0)
EDIT 1:
Now I think I get it... Your problem is, that if you run your exception code in Form.OnLoad that Visual Studio 'breaks' for you and shows you the unhandled-exception window... Thats fine. Press F5 to continue and your exception handler should be called...
As far as I remember you can change this behavior under Debug -> Windows -> Exception settings
EDIT 2:
Or could it be this? https://stackoverflow.com/a/1583427/8400446
This question already has answers here:
Globally catch exceptions in a WPF application?
(7 answers)
Closed 6 years ago.
Sometimes, under not reproducible circumstances, my WPF application crashes without any message. The application simply close instantly.
Where is the best place to implement the global Try/Catch block. At least I have to implement a messagebox with: "Sorry for the inconvenience ..."
You can trap unhandled exceptions at different levels:
AppDomain.CurrentDomain.UnhandledException From all threads in the AppDomain.
Dispatcher.UnhandledException From a single specific UI dispatcher thread.
Application.Current.DispatcherUnhandledException From the main UI dispatcher thread in your WPF application.
TaskScheduler.UnobservedTaskException from within each AppDomain that uses a task scheduler for asynchronous operations.
You should consider what level you need to trap unhandled exceptions at.
Deciding between #2 and #3 depends upon whether you're using more than one WPF thread. This is quite an exotic situation and if you're unsure whether you are or not, then it's most likely that you're not.
You can handle the AppDomain.UnhandledException event
EDIT: actually, this event is probably more adequate: Application.DispatcherUnhandledException
A quick example of code for Application.Dispatcher.UnhandledException:
public App() {
this.Dispatcher.UnhandledException += OnDispatcherUnhandledException;
}
void OnDispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) {
string errorMessage = string.Format("An unhandled exception occurred: {0}", e.Exception.Message);
MessageBox.Show(errorMessage, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
// OR whatever you want like logging etc. MessageBox it's just example
// for quick debugging etc.
e.Handled = true;
}
I added this code in App.xaml.cs
I use the following code in my WPF apps to show a "Sorry for the inconvenience" dialog box whenever an unhandled exception occurs. It shows the exception message, and asks user whether they want to close the app or ignore the exception and continue (the latter case is convenient when a non-fatal exceptions occur and user can still normally continue to use the app).
In App.xaml add the Startup event handler:
<Application .... Startup="Application_Startup">
In App.xaml.cs code add Startup event handler function that will register the global application event handler:
using System.Windows.Threading;
private void Application_Startup(object sender, StartupEventArgs e)
{
// Global exception handling
Application.Current.DispatcherUnhandledException += new DispatcherUnhandledExceptionEventHandler(AppDispatcherUnhandledException);
}
void AppDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
\#if DEBUG // In debug mode do not custom-handle the exception, let Visual Studio handle it
e.Handled = false;
\#else
ShowUnhandledException(e);
\#endif
}
void ShowUnhandledException(DispatcherUnhandledExceptionEventArgs e)
{
e.Handled = true;
string errorMessage = string.Format("An application error occurred.\nPlease check whether your data is correct and repeat the action. If this error occurs again there seems to be a more serious malfunction in the application, and you better close it.\n\nError: {0}\n\nDo you want to continue?\n(if you click Yes you will continue with your work, if you click No the application will close)",
e.Exception.Message + (e.Exception.InnerException != null ? "\n" +
e.Exception.InnerException.Message : null));
if (MessageBox.Show(errorMessage, "Application Error", MessageBoxButton.YesNoCancel, MessageBoxImage.Error) == MessageBoxResult.No) {
if (MessageBox.Show("WARNING: The application will close. Any changes will not be saved!\nDo you really want to close it?", "Close the application!", MessageBoxButton.YesNoCancel, MessageBoxImage.Warning) == MessageBoxResult.Yes)
{
Application.Current.Shutdown();
}
}
Best answer is probably https://stackoverflow.com/a/1472562/601990.
Here is some code that shows how to use it:
App.xaml.cs
public sealed partial class App
{
protected override void OnStartup(StartupEventArgs e)
{
// setting up the Dependency Injection container
var resolver = ResolverFactory.Get();
// getting the ILogger or ILog interface
var logger = resolver.Resolve<ILogger>();
RegisterGlobalExceptionHandling(logger);
// Bootstrapping Dependency Injection
// injects ViewModel into MainWindow.xaml
// remember to remove the StartupUri attribute in App.xaml
var mainWindow = resolver.Resolve<Pages.MainWindow>();
mainWindow.Show();
}
private void RegisterGlobalExceptionHandling(ILogger log)
{
// this is the line you really want
AppDomain.CurrentDomain.UnhandledException +=
(sender, args) => CurrentDomainOnUnhandledException(args, log);
// optional: hooking up some more handlers
// remember that you need to hook up additional handlers when
// logging from other dispatchers, shedulers, or applications
Application.Dispatcher.UnhandledException +=
(sender, args) => DispatcherOnUnhandledException(args, log);
Application.Current.DispatcherUnhandledException +=
(sender, args) => CurrentOnDispatcherUnhandledException(args, log);
TaskScheduler.UnobservedTaskException +=
(sender, args) => TaskSchedulerOnUnobservedTaskException(args, log);
}
private static void TaskSchedulerOnUnobservedTaskException(UnobservedTaskExceptionEventArgs args, ILogger log)
{
log.Error(args.Exception, args.Exception.Message);
args.SetObserved();
}
private static void CurrentOnDispatcherUnhandledException(DispatcherUnhandledExceptionEventArgs args, ILogger log)
{
log.Error(args.Exception, args.Exception.Message);
// args.Handled = true;
}
private static void DispatcherOnUnhandledException(DispatcherUnhandledExceptionEventArgs args, ILogger log)
{
log.Error(args.Exception, args.Exception.Message);
// args.Handled = true;
}
private static void CurrentDomainOnUnhandledException(UnhandledExceptionEventArgs args, ILogger log)
{
var exception = args.ExceptionObject as Exception;
var terminatingMessage = args.IsTerminating ? " The application is terminating." : string.Empty;
var exceptionMessage = exception?.Message ?? "An unmanaged exception occured.";
var message = string.Concat(exceptionMessage, terminatingMessage);
log.Error(exception, message);
}
}
In addition to the posts above:
Application.Current.DispatcherUnhandledException
will not catch exceptions that are thrown from a thread other than the main thread. You have to catch those exceptions on the same thread they are thrown. But if you want to Handle them on your global exception handler you can pass it to the main thread:
System.Threading.Thread t = new System.Threading.Thread(() =>
{
try
{
...
//this exception will not be catched by
//Application.DispatcherUnhandledException
throw new Exception("huh..");
...
}
catch (Exception ex)
{
//But we can handle it in the throwing thread
//and pass it to the main thread wehre Application.
//DispatcherUnhandledException can handle it
System.Windows.Application.Current.Dispatcher.Invoke(
System.Windows.Threading.DispatcherPriority.Normal,
new Action<Exception>((exc) =>
{
throw new Exception("Exception from another Thread", exc);
}), ex);
}
});
To supplement Thomas's answer, the Application class also has the DispatcherUnhandledException event that you can handle.
A complete solution is here
it's explained very nice with sample code. However, be careful that it does not close the application.Add the line
Application.Current.Shutdown();
to gracefully close the app.
As mentioned above
Application.Current.DispatcherUnhandledException will not catch
exceptions that are thrown from another thread then the main thread.
That actual depend on how the thread was created
One case that is not handled by Application.Current.DispatcherUnhandledException is System.Windows.Forms.Timer for which Application.ThreadException can be used to handle these
if you run Forms on other threads than the main thread you will need to set Application.ThreadException from each such thread
I have a WinForm async GUI app in which I've set up some "global" exception handling in program.cs. I also have a GUI thread that's doing an "await Task.WhenAll()" and catching its exception and throwing the awaited Task.Exception property, so that the AggregateException gets all the way to the exception handler in program.cs (I want to iterate over the inner exceptions and log them).
I can see that the exception being thrown out of my try/catch of the WhenAll() is indeed throwing an AggreateException, but when I debug the handler in program.cs, it's not an AggregateException anymore - it's just the first Exception of the AggregateException. I can't figure out what code is doing this "unwrapping" for me?
Program.cs:
static void Main() {
Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
...
}
static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e) {
if (e.Exception is AggregateException) {
// expect to log the contents of (e.Exception as AggregateException).Flatten().InnerExceptions, but exception coming
// in is not AggregateException but instead is
// ApplicationException("message 1")
}
else {
// handling for non aggregate exceptions
}
In Form1.cs
private async void button1_Click(object sender, EventArgs e) {
Task overall = Task.WhenAll(
Task.Run(()=> { throw new ApplicationException("message 1"); }),
Task.Run(() => { throw new ApplicationException("message 2"); })
);
try {
await overall;
}
catch {
throw overall.Exception; // this is AggregateException
}
}
}
It's not just AggregateException - WinForms will always only send GetBaseException() to the handler. That is, only the innermost exception of any InnerException chain.
Apparently this is a longstanding WinForms bug, probably permanent at this point.
You'll have to work around it with your own type:
public class ExceptionWrapper : Exception
{
public new Exception InnerException { get; set; }
}
throw new ExceptionWrapper { InnerException = overall.Exception };
The best possible workaround for this issue is capturing the raised exception via the AppDomain.FirstChangeException event and then comparing this exceptions base exception reference against the exception raised by Application.ThreadException.
Something like this:
private Exception lastFirstChanceException;
AppDomain.CurrentDomain.FirstChanceException += (sender, e) =>
{
lastFirstChanceException = e.Exception;
};
Application.ThreadException += (sender, e) =>
{
if (lastFirstChanceException?.GetBaseException() == e.Exception)
{
var realException = lastFirstChanceException; // This is the "real" exception thrown by some code
}
};
I have implemented software which have a DLL library which contains a set of classes which includes all the methods for my software.
Now I want to be able to handle some global errors like error #26 which is a no Network Related Error on all these classes instead of going to each class and add it. How should I do that?
If #26 is an exception then you can use AppDomain.CurrentDomain.UnhandledException event. If it's just a return value, then I don't see any chance to handle that globally.
public static void Main()
{
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);
// start main thread here
}
static void MyHandler(object sender, UnhandledExceptionEventArgs args)
{
Exception e = (Exception) args.ExceptionObject;
Console.WriteLine("MyHandler caught : " + e.Message);
}
Since its a winforms app you could just enclose Application.Run(new MainForm()); in a try catch block.
static void Main()
{
try {
Application.Run(new MainForm());
} catch(SystemException)//just as an example
{
//log or handle the error here.
}
}
I don't know any implications this kind of solution would cause, but I just told you what you needed.
Other options are subscribing to Application.ThreadException event.
Read more here: unhandledexceptions
There is also AppDomain.UnhandledException and you should read the difference between them here on MSDN.
From MSDN :
For certain application models, the UnhandledException event can be preempted by other events if the unhandled exception occurs in the main application thread.
In applications that use Windows Forms, unhandled exceptions in the main application thread cause the Application.ThreadException event to be raised. If this event is handled, the default behavior is that the unhandled exception does not terminate the application, although the application is left in an unknown state. In that case, the UnhandledException event is not raised. This behavior can be changed by using the application configuration file, or by using the Application.SetUnhandledExceptionMode method to change the mode to UnhandledExceptionMode.ThrowException before the ThreadException event handler is hooked up. This applies only to the main application thread. The UnhandledException event is raised for unhandled exceptions thrown in other threads.
With the reference of Centralized Exception Handling in C# Windows Application, I found one of good solution :
static class Program
{
[STAThread]
static void Main()
{
// Add handler to handle the exception raised by main threads
Application.ThreadException +=
new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
// Add handler to handle the exception raised by additional threads
AppDomain.CurrentDomain.UnhandledException +=
new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
// Stop the application and all the threads in suspended state.
Environment.Exit(-1);
}
static void Application_ThreadException
(object sender, System.Threading.ThreadExceptionEventArgs e)
{// All exceptions thrown by the main thread are handled over this method
ShowExceptionDetails(e.Exception);
}
static void CurrentDomain_UnhandledException
(object sender, UnhandledExceptionEventArgs e)
{// All exceptions thrown by additional threads are handled in this method
ShowExceptionDetails(e.ExceptionObject as Exception);
// Suspend the current thread for now to stop the exception from throwing.
Thread.CurrentThread.Suspend();
}
static void ShowExceptionDetails(Exception Ex)
{
// Do logging of exception details
MessageBox.Show(Ex.Message, Ex.TargetSite.ToString(),
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
In the above class, we shall attach an event handler to two events. It is better to attach these events as soon as the main method starts.
Application.ThreadException - This event will be raised when an exception is thrown in the main thread. If we add an event handler, then the exception is handled over the method.
AppDomain.CurrentDomain.UnhandledException - This event will be raised when an exception is thrown in the additional threads used in the application. The worse scenario here is as soon as the handlers' execution gets over, the exception is again thrown whereas the application ends. This need to be handled. Here I have used a bit of code to handle this situation and continue the execution of the application without interruption.
The logic I have used to overcome this situation is just suspending the thread in the event handler, so that the application continues to work fine. Again a problem arises in suspending this thread. When the main form is closed, the application normally needs to exit, but as the thread is in suspended state, the application will still remain running. So to exit the application completely and stop the process, Environment.Exit(-1) must be called before the ending of the main method.
First, You should add:
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
After that You can catch exceptions, for example:
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
Application.ThreadException += ApplicationThreadException;
AppDomain.CurrentDomain.UnhandledException += CurrentDomainOnUnhandledException;
Application.Run(new MainForm());
}
/// <summary>
/// Global exceptions in Non User Interface (other thread) handler
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void CurrentDomainOnUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
var message =
String.Format(
"Sorry, something went wrong.\r\n" + "{0}\r\n" + "{1}\r\n" + "Please contact support.",
((Exception)e.ExceptionObject).Message, ((Exception)e.ExceptionObject).StackTrace);
MessageBox.Show(message, #"Unexpected error");
}
/// <summary>
/// Global exceptions in User Interface handler
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void ApplicationThreadException(object sender, ThreadExceptionEventArgs e)
{
var message =
String.Format(
"Sorry, something went wrong.\r\n" + "{0}\r\n" + "{1}\r\n" + "Please contact support.",
e.Exception.Message, e.Exception.StackTrace);
MessageBox.Show(message, #"Unexpected error");
}
Handle the Application.ThreadException Event.
Global error interception in winforms
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
try
{
Application.Run(new myForm());
}
catch (Exception ex)
{
HandleException(ex);
}
}
internal static void HandleException(Exception ex)
{
string LF = Environment.NewLine + Environment.NewLine;
string title = $"Oups... I got a crash at {DateTime.Now}";
string infos = $"Please take a screenshot of this message\n\r\n\r" +
$"Message : {LF}{ex.Message}{LF}" +
$"Source : {LF}{ex.Source}{LF}" +
$"Stack : {LF}{ex.StackTrace}{LF}" +
$"InnerException : {ex.InnerException}";
MessageBox.Show(infos, title, MessageBoxButtons.OK, MessageBoxIcon.Error); // Do logging of exception details
}
}
As an extension of what is shown above, I use the following:
try
{
Application.Run(new FormMain());
}
catch (Exception ex)
{
RoboReporterConstsAndUtils.HandleException(ex);
}
...where the HandleException() method can be something like:
internal static void HandleException(Exception ex)
{
var exDetail = String.Format(ExceptionFormatString,
ex.Message,
Environment.NewLine,
ex.Source,
ex.StackTrace,
ex.InnerException);
ExceptionLoggingService.Instance.LogAndEmailExceptionData(string.Format("{0}: {1}: {2}",
DateTime.Now.ToLongDateString(), GetVersionInfo(), exDetail));
}
Another way to skin this cat is:
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
AppDomain.CurrentDomain.UnhandledException += Unhandled;
Application.Run(new FormMain());
}
static void Unhandled(object sender, UnhandledExceptionEventArgs exArgs)
{
ExceptionLoggingService.Instance.LogAndEmailMessage(String.Format
("From application-wide exception handler: {0}", exArgs.ExceptionObject));
}
Of course, you can do whatever you want within the Unhandled() method.