I am trying to understand how a C# program handles an unhandled Exception.
I am doing my testing in a windows forms project, If the answer is different in other project types, please let me know.
I am running the program from the .exe file and not from the visual studio debugger.
Code:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
//timer1.Interval = 10000
private void timer1_Tick(object sender, EventArgs e)
{
//throw new Exception(Thread.CurrentThread.ManagedThreadId.ToString() + " This is an exception");
}
}
static class Program
{
static Form1 newForm;
static void Main()
{
Thread FormThread = new Thread(NewForm);
FormThread.Start();
Thread.Sleep(5000);
//throw new Exception(Thread.CurrentThread.ManagedThreadId.ToString() + " This is an exception");
}
static void NewForm()
{
newForm = new Form1();
Application.Run(newForm);
}
}
My question is what will be the windows response for an unhandled Exception in a C# program?
in the above example:
If the exception is thrown from the timer1_Tick function (by deleting the comment prefix) I am getting the following message:
If the exception is thrown from the Main function (by deleting the comment prefix) I am getting the following message:
why I am getting 2 different messages and how the windows/program "choose" which message to pop.
Thank you.
In a WinForms application, event handlers are invoked by the WindowsFormsSynchronizationContext. When an event handler throws an unhandled exception, the context handles it by displaying the first error dialog. At that point the synchronization context (which is simply a message pump) is still running and it could still proceed handling other events, so you are given a choice.
The Main method, in contrast, is invoked by the operating system itself, to start the application. If there is an unhandled exception there, WIndows has no option but to terminate the application, and it shows the second dialog to inform you of this.
Related
In a C# program, I want to do some action,when an exception happens; that is when an exception happens and exception window appears, I want to screen capture it and save the image(and other info such as the time and user running the program)of the exception in the db.
Please note that in situation an exception occurs, the program stops until for the user clicks on the button(and if the user clicks on Quit button the app will end).
Your error says Unhandled Exception.
Just put your code in try catch block, and handle it accordingly
try
{
int zero = 0;
double i = (1/zero);
}
catch(Exception ex)
{
//ex contains your error and you can do whatever when you catch it in here
Console.WriteLine("Error: {0}", ex.Message);
}
If you want to catch all unhandled exceptions then you can use the application thread exception method.
In your program.cs you need to register the thread exception, and add a method to do your handling.
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
//Register your thread exception method here
Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1(args));
}
//This method will then be called and you can handle your exception anyway you wish
private static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
//Add your custom handling code here
}
}
I have used MouseKeyboardActivityMonitor to set some limitations for user activities for example disable mouse.
www.codeproject.com/Articles/7294/Processing-Global-Mouse-and-Keyboard-Hooks-in-C
I have these code in my form
public partial class MyForm:Form
{
KeyboardHookListener kl;
MouseHookListener ml;
MyForm:Form()
{
ml = new MouseHookListener( new GlobalHooker());
ml.Enabled=true;
}
private void MyForm_Load
{
ml.MouseDownExt += ml_MouseDownExt;
// And same thing for Click or ...
}
private void ml_MouseDownExt( object sender,MouseEventExtArgs e)
{
e.Handled= true;
// I have got hard disk serial number here
string sn = HardDisk.Serial;
}
}
And code of HardDisk.Serial
ManagementObjectSearcher s= new ManagementObjectSearcher(" SELECT *...");
foreach( var wmi in s.Get())
{
}
I get error when I click on MyForm .
When I built my solution and run it manually
I get this error
The application called an interface that was Marshalled for different thread
Stack:
at system.management.MangementException.ThrowWithExtendedInfo( Exception e)
at system.management.MangementObjectSearcher.Get()
at HardDisk.Get_serial()
at ml_MouseDownExt( object sender,MouseEventExtArgs e)
at MouseKeyboardActivityMonitor.MouseHookListener.InvokeMouseEventHandlerExt(EventHandler'1 handler,MouseEventExtArgs e)
But when I run my solution with visual studio an exception will throw at HardDisk.serial
at s.Get line , I get this
Error:
Managed debugging assistant ' DisconnectedContext'
Has detected a problem in 'my app Name.exe'
Transition into com context 0xa4206 for this runtime callable wrapper failed with following error :
an outgoing call can't be made since the application is dispatching an input asynchronous call
It obvious that two error is from MangementObjectSearcher class.I get serial number in another place in MyForm .errors just occurres when get serial in ml_MouseDownExt method or other method that has been added to events of GlobalHooker .I have seen msdn. In inheritance hierarchy of MangementObjectSearcher I see System.MarshalByRefObject
https://msdn.microsoft.com/en-us/library/system.management.managementobjectsearcher(v=vs.110).aspx
I don't know that it is related to these errors or not
How should I avoid these errors?
Your hook callback isn't being raised on the right thread. And that's just the first problem. Wrap it in a BeginInvoke and all will be well:
private void ml_MouseDownExt( object sender,MouseEventExtArgs e)
{
e.Handled= true;
var wrongThread = new Action(()=>
{
// I have got hard disk serial number here
string sn = HardDisk.Serial;
//put anything else you were planning on doing with sn here
}
BeginInvoke(wrongThread, null);
}
The second problem is that you're trying to interact with a COM object in the handler for a global hook. BeginInvoke should get around that nicely by delaying it for a few microseconds.
Don't forget to make sure Dispose gets called on that global hook. Closing the app isn't enough unless you like rebooting often.
I have a context menu option that makes screenshots:
trayMenu.MenuItems.Add("Make a screenshot", makeScreenShot);
private void makeScreenShot(object sender, EventArgs e)
{
Screenshot currentScreenshot = new Screenshot();
}
And in the Screenshot class I have this commands:
Clipboard.Clear();
Clipboard.SetImage(screenshot);
And everything is OK when I am using this context option, BUT I also use a special .dll that helps me to make some shortcut combinations. One of these combinations has the same event handler.
HotKeysManager manager = new HotKeysManager();
manager.AddHotKey(new HotKeyCombination(new Keys[] { Keys.LControlKey, Keys.E }, makeScreenShot));
private void makeScreenShot()
{
Screenshot screenshot = new Screenshot();
}
The problem is, when I am trying to set an image in the clipboard, using the shortcut combination, it causes System.Threading.ThreadStateException.
The exception throws here: Clipboard.Clear();
Exception description:
Exception of type "System.Threading.ThreadStateException" appeared in System.Windows.Forms.dll, but was not handled in user code
More information: The current thread must be specified as a single-threaded stream container (STA), that calls OLE became possible. Check that your Main function is marked attribute STAThreadAttribute.
If this exception handler is available, program execution can be continued safely.
we're having an application on server instance and quite rarely, but we have out of memory exception (program is not leaking, just instance is quite small and it operates with quite big amounts of data).
That would be not a problem, as we monitor processes on that server instance and if some of the processes are not found in process list, alert email is sent.
Now the problem is with this:
That prevents process from disappearing from process list, so we don't get alert email about it's failure. Is it possible to disable this message, that if program fails on something we don't catch, it would close without user interaction?
Assuming Windows Forms, I typically do multiple steps to prevent this message box.
First, I connect several handlers in the Main function:
[STAThread]
private static void Main()
{
Application.ThreadException +=
application_ThreadException;
Application.SetUnhandledExceptionMode(
UnhandledExceptionMode.CatchException);
AppDomain.CurrentDomain.UnhandledException +=
currentDomain_UnhandledException;
Application.Run(new MainForm());
}
Those handlers are being called when an otherwise unhandled exception occurs. I would define them something like:
private static void application_ThreadException(
object sender,
ThreadExceptionEventArgs e)
{
doHandleException(e.Exception);
}
private static void currentDomain_UnhandledException(
object sender,
UnhandledExceptionEventArgs e)
{
doHandleException(e.ExceptionObject as Exception);
}
The actual doHandleException function that is then called does the actual error handling. Usually this is logging the error and notifying the user, giving him the options to continue the application or quit it.
An example from a real-world application looks like:
private static void doHandleException(
Exception e)
{
try
{
Log.Instance.ErrorException(#"Exception.", e);
}
catch (Exception x)
{
Trace.WriteLine(string.Format(
#"Error during exception logging: '{0}'.", x.Message));
}
var form = Form.ActiveForm;
if (form == null)
{
MessageBox.Show(buildMessage(e),
"MyApp", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else
{
MessageBox.Show(form, buildMessage(e),
"MyApp", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
With the helper function:
public static string buildMessage(Exception exception)
{
var result = new StringBuilder();
while (exception != null)
{
result.AppendLine(exception.Message);
result.AppendLine();
exception = exception.InnerException;
}
return result.ToString().Trim();
}
If you are using not Windows Forms but e.g. a Console application or WPF, some handlers are not present, while others are present instead.
The idea stays the same: Subscribe to event handlers that are being called if you have no try...catch around your code blocks.
Personally, I try to have as few of those try...catch blocks as possible (ideally none).
don't know if you can deactivate this - but I think you should not.
Find the bug/problem in your application and handle the problem with a craceful shutdown or by preventing the problem in first case.
Everything else will be a real crude workaround and I don't think your client will be pleased to have such a behavior (after all won't there be data lost? If not this has allways the buggy / not finished touch)
You could put a global try/catch block in your program and exit the program on any unexpected exception.
If using WPF you can try-catch the following two exceptions in your app.xaml.cs. There may be other/complementary exceptions to handle, but this are the two I am usually looking for:
AppDomain.CurrentDomain.UnhandledException - "This event provides notification of uncaught exceptions. It allows the application to log information about the exception before the system default handler reports the exception to the user and terminates the application. If sufficient information about the state of the application is available, other actions may be undertaken — such as saving program data for later recovery. Caution is advised, because program data can become corrupted when exceptions are not handled."
Dispatcher.UnhandledException - "Occurs when a thread exception is thrown and uncaught during execution of a delegate by way of Invoke or BeginInvoke."
ie:
public partial class App : Application
{
public App()
{
this.Dispatcher.UnhandledException += DispatcherUnhandledException;
AppDomain.CurrentDomain.UnhandledException += CurrentDomainUnhandledException;
}
private void CurrentDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
// log and close gracefully
}
private new void DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
e.Handled = true;
// log and close gracefully
}
}
I have a test winforms app with ThreadExceptionHandler that displays a message box when an unhandled exception is caught, as follows:
[STAThread]
static void Main()
{
Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
{
MessageBox.Show("error caught");
}
When I force an error in the ctor of Form 1 (e.g. dividebyzero) as follows:
public Form1()
{
InitializeComponent();
int i = 0;
int x = 5 / i;
}
and run the app outside of Visual Studio (in Windows 7), the divide by zero exception is not handled - I get an unhelpful "WindowsFormApplication1 has stopped working..." message.
However, when I move the dividebyzero exception to the Form1_Load event and rerun, the exception is handled properly.
Can someone explain why this is the case? The reason I ran this test program is because I am experiencing a similar unhandled exception issue in another, enterprise app that I am trying to track down.
This is probably due to the fact that the constructor is executed before Application.Run() is called. Your code could also be written as
[STAThread]
static void Main()
{
Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Form1 MyForm = new Form1();
Application.Run(MyForm);
}
Your thread exception handler only becomes active when Application.Run() is executing. In order to catch exceptions in the form constructor, you need to surround Form1 MyForm = new Form1(); witch a seperate try/catch block.
The error is being thrown in the constructor, not in the threaded code. Your code:
Application.Run(new Form1());
is going to throw the exception right then and there, on that very line of code, before the call to Application.Run(), so the threaded code doesn't even begin executing.
ThreadException handles exceptions UI thread exceptions. UnhandledException handles non-UI thread exceptions.
You need to add this line to your Main():
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
and the following to your class:
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
MessageBox.Show("error caught 2");
}
Application.ThreadException event is called every time Application throws an exception, however in your example, the exception is thrown in the main thread, you can add a try catch block for it.