Code Snippet
using
System;
using
System.Collections.Generic;
using
System.ComponentModel;
using
System.Data;
using
System.Drawing;
using
System.Text;
using
System.Windows.Forms;
using
System.Threading;
namespace
WindowsApplication4 {
public partial class Form1 : Form {
private ThreadExceptionEventHandler threadExceptionHandler;
private delegate void CrasherDelegate();
private Exception callbackException;
private Exception CallbackException {
set {
callbackException = value;
timer1.Enabled = true;
}
}
public Form1() {
InitializeComponent();
threadExceptionHandler = new ThreadExceptionEventHandler(application_ThreadException);
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(currentDomain_UnhandledException);
System.Windows.Forms.Application.ThreadException += threadExceptionHandler;
}
private void currentDomain_UnhandledException(object source, UnhandledExceptionEventArgs e) {
Exception ex = (Exception) e.ExceptionObject;
label1.Text = "There was a problem (Unhandled Exception - Terminating: " + e.IsTerminating + ")\n" + ex.Message;
MessageBox.Show(this, ex.Message, "There was a problem (Unhandled Exception - Terminating: " + e.IsTerminating + ")", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
private void application_ThreadException(object source, ThreadExceptionEventArgs e) {
Exception ex = e.Exception;
label1.Text = "There was a problem (Thread Exception)\n" + ex.Message;
MessageBox.Show(this, ex.Message, "There was a problem (Thread Exception)", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
private void Crasher() {
throw new ArgumentException("Crasher threw on thread: " + Thread.CurrentThread.ManagedThreadId);
}
private void CrasherWithParam(object param) {
throw new ArgumentException("Crasher(" + param + ") threw on thread: " + Thread.CurrentThread.ManagedThreadId);
}
private void Callback(IAsyncResult iar) {
if (!this.InvokeRequired) {
CrasherDelegate d = iar.AsyncState as CrasherDelegate;
if (d != null) {
MessageBox.Show("Calling EndInvoke on thread: " + Thread.CurrentThread.ManagedThreadId);
d.EndInvoke(iar);
}
}
else {
this.Invoke((MethodInvoker) delegate {
this.Callback(iar);
});
}
}
private void CallbackMarshalToForm(IAsyncResult iar) {
if (!this.InvokeRequired) {
CrasherDelegate d = iar.AsyncState as CrasherDelegate;
if (d != null) {
try {
MessageBox.Show("Calling EndInvoke on thread: " + Thread.CurrentThread.ManagedThreadId);
d.EndInvoke(iar);
}
catch (Exception e) {
CallbackException = e;
}
}
}
else {
this.Invoke((MethodInvoker) delegate {
this.CallbackMarshalToForm(iar);
});
}
}
private void CallbackNoInvoke(IAsyncResult iar) {
CrasherDelegate d = iar.AsyncState as CrasherDelegate;
if (d != null) {
MessageBox.Show("Calling EndInvoke on thread: " + Thread.CurrentThread.ManagedThreadId);
d.EndInvoke(iar);
}
}
private void CallbackFireAndForgetMarshalling(IAsyncResult iar) {
if (!this.InvokeRequired) {
CrasherDelegate d = iar.AsyncState as CrasherDelegate;
if (d != null) {
MessageBox.Show("Calling EndInvoke on thread: " + Thread.CurrentThread.ManagedThreadId);
d.EndInvoke(iar);
}
}
else {
this.BeginInvoke((MethodInvoker) delegate {
this.Callback(iar);
});
}
}
private void timer1_Tick(object sender, EventArgs e) {
timer1.Enabled = false;
MessageBox.Show("re-throwing on thread: " + Thread.CurrentThread.ManagedThreadId);
throw callbackException;
}
private void button1_Click(object sender, EventArgs e) {
// call the crasher directly
// result: the ThreadException handler will catch the exception and the app will continue
Crasher();
}
private void button2_Click(object sender, EventArgs e) {
// call the crasher by synchronous invoke of a delegate
// result: the ThreadException handler will catch the exception and the app will continue
CrasherDelegate d = new CrasherDelegate(Crasher);
d.Invoke();
}
private void button3_Click(object sender, EventArgs e) {
// call the crasher by asynchronous invoke of a delegate (on a thread pool thread), but block right after and wait for it to complete
// result: the ThreadException handler will catch the exception and the app will continue
CrasherDelegate d = new CrasherDelegate(Crasher);
IAsyncResult iar = d.BeginInvoke(null, d);
// both of these work equally well
d.EndInvoke(iar);
//Callback(iar);
}
private void button4_Click(object sender, EventArgs e) {
// call the crasher by asynchronous invoke of a delegate (on a thread pool thread), and specify a callback that marshals the EndInvoke to the UI thread by Invoking the Form
// result: the ThreadException handler does NOT catch the exception. The app will be killed by an UnhandledException
CrasherDelegate d = new CrasherDelegate(Crasher);
AsyncCallback cb = new AsyncCallback(Callback);
IAsyncResult iar = d.BeginInvoke(cb, d);
}
private void button5_Click(object sender, EventArgs e) {
// call the crasher by queueing a work item (on a thread pool thread)
// result: the ThreadException handler does NOT catch the exception. The app will be killed by an UnhandledException
WaitCallback cb = new WaitCallback(CrasherWithParam);
ThreadPool.QueueUserWorkItem(cb);
}
private void button6_Click(object sender, EventArgs e) {
// call the crasher by asynchronous invoke of a delegate (on a thread pool thread), and specify a callback that catches the exception, stores it and starts a timer that rethrows it on the first Tick
// result: the ThreadException handler will catch the exception and the app will continue
CrasherDelegate d = new CrasherDelegate(Crasher);
AsyncCallback cb = new AsyncCallback(CallbackMarshalToForm);
IAsyncResult iar = d.BeginInvoke(cb, d);
}
private void button7_Click(object sender, EventArgs e) {
// call the crasher by asynchronous invoke of a delegate (on a thread pool thread), and specify a callback that does the EndInvoke directly on the thread pool thread
// result: the ThreadException handler does NOT catch the exception. The app will be killed by an UnhandledException
CrasherDelegate d = new CrasherDelegate(Crasher);
AsyncCallback cb = new AsyncCallback(CallbackNoInvoke);
IAsyncResult iar = d.BeginInvoke(cb, d);
}
private void button8_Click(object sender, EventArgs e) {
// call the crasher by asynchronous invoke of a delegate (on a thread pool thread), and specify a callback that marshals the EndInvoke to the UI thread by BeginInvoking the Form
// result: the ThreadException handler will catch the exception and the app will continue
CrasherDelegate d = new CrasherDelegate(Crasher);
AsyncCallback cb = new AsyncCallback(CallbackFireAndForgetMarshalling);
IAsyncResult iar = d.BeginInvoke(cb, d);
}
private void button9_Click(object sender, EventArgs e) {
// call the crasher by using a BackgroundWorker
// result: the ThreadException handler will catch the exception and the app will continue
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork +=
new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerCompleted +=
new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
worker.RunWorkerAsync();
}
private void worker_DoWork(object sender, DoWorkEventArgs e) {
Crasher();
}
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
if (e.Error != null) {
throw e.Error;
}
}
}
}