I'm creating a Windows Forms application using Visual Studio 2012, C#, .NET 4.5; Windows 7.
I would like to handle any unhandled exception with my own error handler. I wrote some code like the own shown below. I even tried two different ways of error handling.
Now when I run this program within Visual Studio (2012), then this works very fine !
But when I start the program from explorer, then my error handler is never called; instead, there will always pop up the standard error handler from .NET Framework.
So what am I doing wrong?
static void Main()
{
try
{
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(HandleUnhandledException);
Application.Run(new frmMainFrame());
}
catch (Exception ex)
{
// Here is my error handler ....
}
}
static void HandleUnhandledException(object sender, UnhandledExceptionEventArgs args)
{
Exception ex = (Exception) args.ExceptionObject;
// Here is my error handler ....
}
Hook up Application.ThreadException as well.
Or set Application.SetUnhandledExceptionMode to UnhandledExceptionMode.ThrowException to have your appdomain handler kickin.
First at all i would use the Debugger.Break() Method to attach your program into to problematic code part. Than maybe just check if currentDomain is not null. Assumed that you don't raise a Exception that forces the CLI to stop.
Related
I'm programming a dll as extension for a program (Windows 10, Visual Studio Professional 2019). In this dll I have a very weird behaviour. The scenario:
From then 'main' module of the dll (where the callbacks for the application are located) I open a dialog window (own module) which is calling functions in a third module in it's 'Form Shown' event. In this third module I throw an exception (because the user cancelled an action) which I want to catch in the 'main' module.
When I run this dll in VisualStudio debugger (either Debug or Release Configuration, no difference), the Application is started, the dll is loaded and the process described above works like a charm.
When I run the application w/o VisualStudio, the Application is started, the dll is loaded but after throwing the exception it's not caught as before and I get told by the system that an exception was thrown and not caught.
So why does the code work in the IDE environment but not 'standalone'?
The only thing I could imagine was that there are differences in the event handling code of .NET. In the call stack when I stop in the 'Shown' event function, I see that there are calls to "mscorlib.dll!System.Threading.ExecutionContext". Is it possible that outside of VS the dll is in another execution context so that the exception is mislead?
I would appreciate if someone could explain me this behaviour. Again, it's not a matter of debug or release version, it's about the execution environment.
Thanks in advance,
Jörg
EDIT
I hope this clears the scenario:
dll.cs:
// This function is called from the host application
void callback()
{
try
{
Form dialog = new Form();
dialog.ShowDialog();
}
catch (ExceptionType1)
{
...
}
catch (ExceptionType2)
{
...
}
catch
{
...
}
}
dialog.cs
...
// event function for the 'shown' event of Form class
private void SynchronizationDialog_Shown(object sender, EventArgs e)
{
HelperFunction();
}
...
helper.cs
// here the exception is thrown
void HelperFunction()
{
...
if(...)
{
throw new ExceptionType1();
}
...
}
When debugging the dll in VS, the exception thrown in helper.cs is caught by the catch block, which is as expected.
When running the application calling the dll standalone, the exception is not caught.
EDIT
I now can provide an example project (VS2020): ExceptionCatchTest
If you run it in VS, Exception got caught, else not.
I created a test project using your code and was able to reproduce your problem. Looking through the exception's stack trace it seems the windows message processor Control.WndProc for the form is only in the stack while running from visual studio. As a test, I overrode the WndProc method in the form to add a try-catch block around the call to the base method
protected override void WndProc(ref Message m)
{
try
{
base.WndProc(ref m);
}
catch
{
MessageBox.Show("WndProc caught");
throw;
}
}
when running from Visual Studio, a message box appears indicating "WndProc caught". When not running in Visual Studio, this message never appears before the program crashes.
Thinking about it, probably the best solution to your problem would be to instead add a publicly visible enumeration such as public ErrorStatus errorStatus = ErrorStatus.NoError;. Then, instead of throwing and exception, you could use the following code
errorStatus = ErrorStatus.Error1;
DialogResult = DialogResult.Abort;
return;
You could then change your calling function to
void callback()
{
using (Form dialog = new Form())
{
DialogResult result = dialog.ShowDialog();
if (result == DialogResult.Abort)
{
switch (dialog.errorStatus)
{
case ErrorStatus.Error1:
...
break;
case ErrorStatus.Error2:
...
break;
}
}
}
}
This is getting extremely irritating. Right now I have a winforms application, and things were not working right, but no exceptions were being thrown as far as I could tell. After stepping through almost all pieces of relevant code, it turns out that an exception was being thrown at the start of my application.
Long story short, in WinForms, being as awesome as it is, if an exception occurs the WinForms library ignores it. No "an unhandled exception has occurred" JIT message is thrown, it just stops processing the current event and goes back to the GUI.
This is causing random bugs, because code to load data isn't being called due to the exception occurring prior to this data being loaded.
To see this in action I created a brand new WinForms application, and entered the following code:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
string blah = null;
blah.Trim();
}
}
Press F5 and the form loads without any errors showing, even though a null reference is being thrown.
I then tried to go to my Program.cs main method and add Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException); to it. Still my form loads without causing any errors to be thrown.
Even though I know that I can tell VS to break on all exceptions, I find this situation really bad. It causes really wierd issues that are hard to debug in production, and as this is an internal tool I really want to have it so it actually errors out when an exception occurs, and not silently disregards it.
Does anyone know how to do this?
Update: Just to update on things I have learned from the comments.
This does appear to be a 64-bit issue with windows, as I learned from this question which I did not see before posting. In that question it pointed to a Microsoft bug report about this, which had this to say:
Hello,
This bug was closed as "External" because this behavior results from how x64 version of Windows handle exceptions. When a user mode exception crosses a kernel transition, x64 versions of Windows do not allow the exception to propagate. Therefore attached debuggers are unaware of the fact that an exception occured resulting in the debugger failing to break on the unhandled exception.
Unfortunately where is nothing that the Visual Studo team can do to address this, it is the result of operating system design. All feedback regarding this issue should be addressed to the Windows team; however the Windows team considers this to be the "correct" operating system design, and considers the x86 behavior to be "incorrect".
Best Regards,
Visual Studio Debugger
That being said, builds not run through visual studio (or using Ctrl+F5 to run) does seem to show the JIT exception message box EXCEPT if you have the following code in your Program.cs:
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);
That code will cause windows to ignore the exception.
However, if you (instead) subscribe to the Application.ThreadException event, not only will your exceptions be caught, visual studio's debugger will break on unhandled exceptions!
In your Program.cs' Main function you should also ensure that you've wrapped your call to open the form in a try/catch. Additionally use the AppDomain.UnhandledException to catch exceptions. We also add Application.ThreadException too.
I believe the following will give you hooks into all the exceptions that can be thrown...
static void Main()
{
try
{
System.Windows.Forms.Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
System.Windows.Forms.Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(OnGuiUnhandedException);
AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
var form = new MainForm();
form.ShowDialog();
}
catch (Exception e)
{
HandleUnhandledException(e);
}
finally
{
// Do stuff
}
}
private static void HandleUnhandledException(Object o)
{
// TODO: Log it!
Exception e = o as Exception;
if (e != null)
{
}
}
private static void OnUnhandledException(Object sender, UnhandledExceptionEventArgs e)
{
HandleUnhandledException(e.ExceptionObject);
}
private static void OnGuiUnhandedException(object sender, System.Threading.ThreadExceptionEventArgs e)
{
HandleUnhandledException(e.Exception);
}
Try the following.
Handle exceptions in your main application entry point.
Also, manage unhandled thread exceptions using a ThreadExceptionEventHandler
This is the code snippet:
[STAThread]
public static void Main(string[] args)
{
try
{
Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
//your program entry point
}
catch (Exception ex)
{
//manage also these exceptions
}
}
private void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
ProcessException(e.Exception);
}
An easy fix is not to run under the debugger.
The debugger is masking the exception for some reason. If you run your app normally (Ctrl+F5), you'll get the usual "Unhandled exception has occurred in your application... Continue/Quit?" dialog.
Having experienced this often and identified the issue regarding 64 bit OS and the Form.Load event, I always just make a point of doing all my start up functions in the Form.Shown event. For all practical purposes this is the same thing (aside from a few rare, exceptional circumstances), and the JIT message is produced in the Shown event.
I cant seem to make heads or tails of how I am supposed to properly handle unexpected exceptions.
Consider the following application:
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new SomeForm());
}
class SomeForm : Form
{
public SomeForm()
{
Button btn = new Button();
btn.Text = "Click ME";
btn.Location = new System.Drawing.Point(20, 20);
btn.Click += new EventHandler(btn_Click);
Controls.Add(btn);
}
void btn_Click(object sender, EventArgs e)
{
throw new Exception("This is an Exception");
}
}
If I run this application and click the button I get an unhandled exception as expected. At first I tried surrounding the Application.Run with a try catch block like so:
try { Application.Run(new SomeForm()); }
catch { MessageBox.Show("Exception caught in try catch"); }
At first this seems to work, until I ran the application outside of the Debugger. When you run the application outside of the Debugger, the exception is reported as an unhandled error. After doing some reading I discovered I should be looking at the Application.ThreadException event. So I do the following:
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
try { Application.Run(new SomeForm()); }
catch { MessageBox.Show("Exception caught in try catch"); }
}
static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
{
MessageBox.Show("Exception caught in event");
}
Now when I run my application outside of the debugger the exception is handled and the MessageBox indicates it was caught in the event handler. Then I go back into the debugger and run it. Now the Debugger kicks it up as an unhandled exception even though I have surrounded it in a try catch AND I am tied onto the Application.ThreadException event. If I do not tie up the to Application.ThreadException event the exception is caught correctly by the try catch block.
Now to the questions:
What the heck is going on here?
Is there a way that I can catch/handle all exceptions in my application that works both in the debugger and outside of the debugger?
Am I just doing the completely wrong thing here?
You can handle them using AppDomain.CurrentDomain.UnhandledException and Application.ThreadException, look for more.
What's the difference between Application.ThreadException and AppDomain.CurrentDomain.UnhandledException?
The debugger considers exceptions that propagate to Application_ThreadException to be unhandled exceptions, since that event handler is used as a final location to log and terminate gracefully. This allows you to stop at the point of the exception when running the debugger, which is often very helpful.
It's not possible to handle all exceptions in one global place because there is not enough context to know how to actually handle them. You can catch all exceptions (even the unhandled ones) using Application_ThreadException (and AppDomain.UnhandledException for exceptions on other threads), but the next thing you should do in that case is shut down your application.
You should handle exceptions in each method separately, based on the information you have and the knowledge of the types of exceptions that can occur. Exceptions you don't know how to handle should not be caught and will percolate to the 'global' event handlers, which should log the details and politely shut down the application.
I tried to write a little crash reporter for uncatched expetions. This works perfectly when starting my App in VS.
But as soon as I try to start the .exe it only shows me the standard "There is an uncaught expetion"-thingy from windows.
And no it's not the crashreporter which crashes.
This is my code in the Program.cs
try
{
Application.Run(new TestServer());
}
catch (Exception e)
{
Application.Run(new CrashReporter(e.StackTrace.ToString()));
}
}
This is because you use a debugger. Winforms detects this and disables the event handler for Application.ThreadException. That's important, it lets you debug exceptions. To get your catch clause to work without a debugger, you'll have to add this statement to your Main() method, before the Run() call:
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);
It now does make more sense to write an event handler for AppDomain.Current.UnhandledException instead, you'll also get notified about unhandled exceptions in worker threads.
Instead of this you can handle following event (which is the preferred way of handling unhandled application exceptions):
AppDomain.CurrentDomain.UnhandledException += (sender, e) =>
{
Application.Run(new CrashReporter(e.StackTrace.ToString()));
}
Application.Run(new TestServer());
Are you running on a 64 bit OS? This sounds like the problem Hans Passant answered here.
Debugging can swallow errors on Form construction and Forms_Load in 64 bit CLR...
Are you sure this thing works? I mean, did this strategy work for you previously?
I use (and suggested way) this way to catch the unhandled exceptions globally:
AppDomain.CurrentDomain.UnhandledException +=
new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
//then start the main form...
Application.Run(new TestServer());
Here is the documentation
http://msdn.microsoft.com/en-us/library/system.appdomain.unhandledexception.aspx
CrashReporter is causing it. An uncaught exception in a catch statement will cause an uncaught exception. You need another try/catch in your catch and another fall back.
protected override void OnStart(string[] args)
{
AppDomain.CurrentDomain.UnhandledException +=
new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
Thread.Sleep(10000);
throw new Exception();
}
void CurrentDomain_UnhandledException(object sender,
UnhandledExceptionEventArgs e)
{
}
I attached a debugger to the above code in my windows service, setting a breakpoint in CurrentDomain_UnhandledException, but it was never hit. The exception pops up saying that it is unhandled, and then the service stops. I even tried putting some code in the event handler, in case it was getting optimized away.
Is this not the proper way to set up unhandled exception handling in a windows service?
The reason that the UnhandledException event on the current AppDomain does not fire is how services are executed.
User sends a Start command from the Windows Service Control Manager (SCM).
The command is received by the framework's ServiceBase implementation and dispatched to the OnStart method.
The OnStart method is called.
Any exception which is thrown by OnStart is handled in the base class, logged to the Event Log, and translated into an error status code returned to the SCM. So the exception never propagates to the AppDomain's unhandled exception handler.
I think you would find that an unhandled exception thrown from a worker thread in your service would be caught by the AppDomain's unhandled exception handler.
In a Windows Service you do NOT want to be running much code in the OnStart method. All you want there is the code to launch your service thread and then return.
If you do that you can handle exceptions that happen in your service thread just fine.
e.g.
public static void Start()
{
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(currentDomain_UnhandledException);
running = true;
ThreadStart ts = new ThreadStart(ServiceThreadBody);
thread = new Thread(ts);
thread.Name = "ServiceThread";
thread.Priority = ThreadPriority.BelowNormal;
thread.Start();
}
When I was working on my own Windows Service, it was stoping itself oddly enough. I thought it was because of unhanded exception. At the moment I am catching unhanded exceptions on text file. First of all you have to create new file ServiceLog.txt on C locations due to logging excaptions on text file. With below coding I got all unhanded exceptions with them line numbers.
using System.Security.Permissions;
using System.IO;
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.ControlAppDomain)]
protected override void OnStart(string[] args)
{ AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);
...
Your codes...
....
}
void MyHandler(object sender, UnhandledExceptionEventArgs args)
{
Exception e = (Exception)args.ExceptionObject;
WriteToFile("Simple Service Error on: {0} " + e.Message + e.StackTrace);
}
private void WriteToFile(string text)
{
string path = "C:\\ServiceLog.txt";
using (StreamWriter writer = new StreamWriter(path, true))
{
writer.WriteLine(string.Format(text, DateTime.Now.ToString("dd/MM/yyyy hh:mm:ss tt")));
writer.Close();
}
}
Know this thread is a bit old, but thought it would be useful to add some comments based on personal experience developing Windows services in .NET. The best approach is to avoid developing under the Service Control Manager as much as you can - for this you need a simple harness that mimics the way services get started - something that can create an instance of your service class (that you already derived from ServiceBase) and call your OnStart, OnStop etc methods. This harness can be a console app or a Windows app as you desire.
This is pretty much the only way I have found of debugging service start-up issues in .NET - the interaction between your code, Visual Studio and the real Service Control Manager just makes the process impossible otherwise.
HTH.
Just curious, what are you trying to accomplish: avoiding service crashing, or reporting errors?
For reporting, I think your best bet is to add top-level try/catch statements. You can try to log them to the Windows event log and/or a log file.
You can also set the ExitCode property to a non-zero value until you successfully stop the service. If the system administrator starts your service from the Services control panel, and your service stops suddenly with a non-zero exit code, Windows can show an error message with the description of the error.