Dotnet dismantles my exceptions!!!


M

Martin

This simple code has two button handlers, one throws an exception, the
other asynchronously throws an exception. Each thrown exception has an
outer and inner part, the first exception thrown shows a message box
that says 'ApplicationException: Useful message -->
DivideByZeroException: Attempted to divide by zero' and then a stack
trace, the asynchronous throw produces a messagebox which says
'DivideByZeroException: Attempted to divide by zero'. This begs the
obvious question, in the asynchronous throw what has happened to the
exception I threw, how do I get it back, and how do I write exception
safe code when I have to expect that any exception I throw will be
dismantled before I ever get a chance to handle it?

using System;
using System.Threading;
using System.Windows.Forms;

namespace ExceptionTest2
{
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button2;
private System.ComponentModel.Container components = null;

public Form1()
{
InitializeComponent();
}

protected override void Dispose( bool disposing )
{
if(disposing)
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
this.SuspendLayout();

this.button1.Location = new System.Drawing.Point(96, 24);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(88, 48);
this.button1.TabIndex = 0;
this.button1.Text = "button1";
this.button1.Click += new
System.EventHandler(this.button1_Click);

this.button2.Location = new System.Drawing.Point(96, 96);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(88, 48);
this.button2.TabIndex = 1;
this.button2.Text = "button2";
this.button2.Click += new
System.EventHandler(this.button2_Click);

this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(292, 266);
this.Controls.Add(this.button2);
this.Controls.Add(this.button1);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
}
#endregion

[STAThread]
static void Main()
{
Application.ThreadException += new
ThreadExceptionEventHandler(OnThreadException);
Application.Run(new Form1());
}

private static void OnThreadException(object sender,
ThreadExceptionEventArgs e)
{
MessageBox.Show(e.Exception.ToString());
}

private void button1_Click(object sender, System.EventArgs e)
{
int a = 0;

try
{
int b = 1 / a;
}
catch(System.DivideByZeroException ex)
{
throw new ApplicationException("Useful message", ex);
}
}

private void button2_Click(object sender, System.EventArgs e)
{
BeginInvoke(new VoidDlg(AsyncThrow));
}

private void AsyncThrow()
{
int a = 0;

try
{
int b = 1 / a;
}
catch(System.DivideByZeroException ex)
{
throw new ApplicationException("Useful message", ex);
}
}
}

delegate void VoidDlg();
}
 
Ad

Advertisements

I

Ignacio Machin \( .NET/ C# MVP \)

Hi,

I remember something like this being discussed a while ago, that was
regarding to drag&drop operations , where the exception was eaten somewhere,

Maybe a similar thing is happening here, somewhere there is the code
catching the exception and throwing a new one and not updating the
InnerException
I even get the line number wrong. in the StackTrace


cheers,

--
Ignacio Machin,
ignacio.machin AT dot.state.fl.us
Florida Department Of Transportation



Martin said:
This simple code has two button handlers, one throws an exception, the
other asynchronously throws an exception. Each thrown exception has an
outer and inner part, the first exception thrown shows a message box
that says 'ApplicationException: Useful message -->
DivideByZeroException: Attempted to divide by zero' and then a stack
trace, the asynchronous throw produces a messagebox which says
'DivideByZeroException: Attempted to divide by zero'. This begs the
obvious question, in the asynchronous throw what has happened to the
exception I threw, how do I get it back, and how do I write exception
safe code when I have to expect that any exception I throw will be
dismantled before I ever get a chance to handle it?

using System;
using System.Threading;
using System.Windows.Forms;

namespace ExceptionTest2
{
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button2;
private System.ComponentModel.Container components = null;

public Form1()
{
InitializeComponent();
}

protected override void Dispose( bool disposing )
{
if(disposing)
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
this.SuspendLayout();

this.button1.Location = new System.Drawing.Point(96, 24);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(88, 48);
this.button1.TabIndex = 0;
this.button1.Text = "button1";
this.button1.Click += new
System.EventHandler(this.button1_Click);

this.button2.Location = new System.Drawing.Point(96, 96);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(88, 48);
this.button2.TabIndex = 1;
this.button2.Text = "button2";
this.button2.Click += new
System.EventHandler(this.button2_Click);

this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(292, 266);
this.Controls.Add(this.button2);
this.Controls.Add(this.button1);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
}
#endregion

[STAThread]
static void Main()
{
Application.ThreadException += new
ThreadExceptionEventHandler(OnThreadException);
Application.Run(new Form1());
}

private static void OnThreadException(object sender,
ThreadExceptionEventArgs e)
{
MessageBox.Show(e.Exception.ToString());
}

private void button1_Click(object sender, System.EventArgs e)
{
int a = 0;

try
{
int b = 1 / a;
}
catch(System.DivideByZeroException ex)
{
throw new ApplicationException("Useful message", ex);
}
}

private void button2_Click(object sender, System.EventArgs e)
{
BeginInvoke(new VoidDlg(AsyncThrow));
}

private void AsyncThrow()
{
int a = 0;

try
{
int b = 1 / a;
}
catch(System.DivideByZeroException ex)
{
throw new ApplicationException("Useful message", ex);
}
}
}

delegate void VoidDlg();
}
 
G

Guest

What were you expecting, if it was "Useful Message", then I suggest that you
replace e.Exception.ToString() by e.Exception.Message in your MessageBox.

Martin said:
This simple code has two button handlers, one throws an exception, the
other asynchronously throws an exception. Each thrown exception has an
outer and inner part, the first exception thrown shows a message box
that says 'ApplicationException: Useful message -->
DivideByZeroException: Attempted to divide by zero' and then a stack
trace, the asynchronous throw produces a messagebox which says
'DivideByZeroException: Attempted to divide by zero'. This begs the
obvious question, in the asynchronous throw what has happened to the
exception I threw, how do I get it back, and how do I write exception
safe code when I have to expect that any exception I throw will be
dismantled before I ever get a chance to handle it?

using System;
using System.Threading;
using System.Windows.Forms;

namespace ExceptionTest2
{
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button2;
private System.ComponentModel.Container components = null;

public Form1()
{
InitializeComponent();
}

protected override void Dispose( bool disposing )
{
if(disposing)
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
this.SuspendLayout();

this.button1.Location = new System.Drawing.Point(96, 24);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(88, 48);
this.button1.TabIndex = 0;
this.button1.Text = "button1";
this.button1.Click += new
System.EventHandler(this.button1_Click);

this.button2.Location = new System.Drawing.Point(96, 96);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(88, 48);
this.button2.TabIndex = 1;
this.button2.Text = "button2";
this.button2.Click += new
System.EventHandler(this.button2_Click);

this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(292, 266);
this.Controls.Add(this.button2);
this.Controls.Add(this.button1);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
}
#endregion

[STAThread]
static void Main()
{
Application.ThreadException += new
ThreadExceptionEventHandler(OnThreadException);
Application.Run(new Form1());
}

private static void OnThreadException(object sender,
ThreadExceptionEventArgs e)
{
MessageBox.Show(e.Exception.ToString());
}

private void button1_Click(object sender, System.EventArgs e)
{
int a = 0;

try
{
int b = 1 / a;
}
catch(System.DivideByZeroException ex)
{
throw new ApplicationException("Useful message", ex);
}
}

private void button2_Click(object sender, System.EventArgs e)
{
BeginInvoke(new VoidDlg(AsyncThrow));
}

private void AsyncThrow()
{
int a = 0;

try
{
int b = 1 / a;
}
catch(System.DivideByZeroException ex)
{
throw new ApplicationException("Useful message", ex);
}
}
}

delegate void VoidDlg();
}
 
I

Ignacio Machin \( .NET/ C# MVP \)

Hi,

I think that what he is suggesting is that the exception he throw is not
what gets to OnThreadException , that's the whole point.

Cheers,

--
Ignacio Machin,
ignacio.machin AT dot.state.fl.us
Florida Department Of Transportation



tony lock said:
What were you expecting, if it was "Useful Message", then I suggest that you
replace e.Exception.ToString() by e.Exception.Message in your MessageBox.

Martin said:
This simple code has two button handlers, one throws an exception, the
other asynchronously throws an exception. Each thrown exception has an
outer and inner part, the first exception thrown shows a message box
that says 'ApplicationException: Useful message -->
DivideByZeroException: Attempted to divide by zero' and then a stack
trace, the asynchronous throw produces a messagebox which says
'DivideByZeroException: Attempted to divide by zero'. This begs the
obvious question, in the asynchronous throw what has happened to the
exception I threw, how do I get it back, and how do I write exception
safe code when I have to expect that any exception I throw will be
dismantled before I ever get a chance to handle it?

using System;
using System.Threading;
using System.Windows.Forms;

namespace ExceptionTest2
{
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button2;
private System.ComponentModel.Container components = null;

public Form1()
{
InitializeComponent();
}

protected override void Dispose( bool disposing )
{
if(disposing)
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
this.SuspendLayout();

this.button1.Location = new System.Drawing.Point(96, 24);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(88, 48);
this.button1.TabIndex = 0;
this.button1.Text = "button1";
this.button1.Click += new
System.EventHandler(this.button1_Click);

this.button2.Location = new System.Drawing.Point(96, 96);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(88, 48);
this.button2.TabIndex = 1;
this.button2.Text = "button2";
this.button2.Click += new
System.EventHandler(this.button2_Click);

this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(292, 266);
this.Controls.Add(this.button2);
this.Controls.Add(this.button1);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
}
#endregion

[STAThread]
static void Main()
{
Application.ThreadException += new
ThreadExceptionEventHandler(OnThreadException);
Application.Run(new Form1());
}

private static void OnThreadException(object sender,
ThreadExceptionEventArgs e)
{
MessageBox.Show(e.Exception.ToString());
}

private void button1_Click(object sender, System.EventArgs e)
{
int a = 0;

try
{
int b = 1 / a;
}
catch(System.DivideByZeroException ex)
{
throw new ApplicationException("Useful message", ex);
}
}

private void button2_Click(object sender, System.EventArgs e)
{
BeginInvoke(new VoidDlg(AsyncThrow));
}

private void AsyncThrow()
{
int a = 0;

try
{
int b = 1 / a;
}
catch(System.DivideByZeroException ex)
{
throw new ApplicationException("Useful message", ex);
}
}
}

delegate void VoidDlg();
}
 
W

Willy Denoyette [MVP]

Martin said:
This simple code has two button handlers, one throws an exception, the
other asynchronously throws an exception. Each thrown exception has an
outer and inner part, the first exception thrown shows a message box
that says 'ApplicationException: Useful message -->
DivideByZeroException: Attempted to divide by zero' and then a stack
trace, the asynchronous throw produces a messagebox which says
'DivideByZeroException: Attempted to divide by zero'. This begs the
obvious question, in the asynchronous throw what has happened to the
exception I threw, how do I get it back, and how do I write exception
safe code when I have to expect that any exception I throw will be
dismantled before I ever get a chance to handle it?

First, by calling BeginInvoke you effectively execute the procedure on a
worker thread and Exceptions do not flow from thread to thread.
Second, every delegate BeginInvoke must be paired with a EndInvoke call on
the same delegate.

To solve both issues you have to pass some state to the delegate, lets say a
simple object like this:

class StateObject {
// Put whatever you need to pass to the delegate's EndInvoke
}

When you want to retrieve the results of the asynchronous call just wrap the
EndInvoke call in a try/catch block:

private void button2_Click(object sender, System.EventArgs e)
{
VoidDlg vdlg = new VoidDlg(AsyncThrow);
// StateObject not used (3rd arg = null)
IAsyncResult ar = vdlg.BeginInvoke(null, null, null);
// Call EndInvoke from within a guarded block to retrieve the results.
try
{
vdlg.EndInvoke(ar);
// Get state from IAsyncResult (ar)if any
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
....

Change your delegate declaration...

delegate void VoidDlg(StateObject o);

Problem solved....

Willy.
 
M

Martin

But I'm calling Control.BeginInvoke not Delegate.BeginInvoke! The SDK
documentation states 'executes the specified delegate asynchronously
on the thread that the control's underlying handle was created on'.
The documentation then goes on to say 'the BeginInvoke method calls
the specified delegate back on a different thread pool thread' which
is in contradication to what it says five sentences before, but that's
Microsoft documention for you. Testing indicates that the delegate is
executed on the UI thread in idle time. Also the SDK documentation
does not indicate that there is any requirement to match calls to
Control.BeginInvoke with a call to Control.EndInvoke. The
documentation for Control.BeginInvoke does however state, 'Exceptions
within the delegate method are considered untrapped and will be sent
to the application's untrapped exception handler'.
I was already aware of how this works with Delegate.BeginInvoke and
Delegate.EndInvoke, but I tested the code you posted anyway and it
does work as you have indicated, although your delegate has a state
parameter which is passed null in your call to BeginInvoke and the
code works exactly the same with a void delegate so the state
parameter is irrelevant. One design flaw with your code though is that
Delegate.BeginInvoke is asynchronous whereas Delegate.EndInvoke
blocks, so if you call EndInvoke straight after you call BeginInvoke
on the same thread it totally defeats the point since the thread that
calls BeginInvoke will block at the call to EndInvoke until the
delegate has completed executing, in other words in terms of execution
order it has the same effect as just calling the delegate method
directly and the only difference is that the delegate method will
execute on a thread pool thread.
So then I modified my original example so that it calls BeginInvoke,
stores the object pointer and the IAsyncResult so that in Idle time
once the delegate has completed executing, the app can call EndInvoke
and catch any exceptions. I am aware that this sample is no longer
thread safe but it nevertheless demonstrates the point. The result is
exactly the same as my first sample in that the caught exception will
not be the one I threw.
The application I work on has over a hundred asynchronous handlers,
and at the moment the only way around this that I can see is for every
handler to have a top level try/catch block and when it catches an
exception the handler passes it back to the caller as a return value
and the caller then rethrows the exception on the UI thread so that it
cannot be ignored. But as a solution to say that this is not elegant
is a masterpiece of understatement.


using System;
using System.Threading;
using System.Collections;
using System.Windows.Forms;

namespace ExceptionTest2
{
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button2;
private System.ComponentModel.Container components = null;
private static ArrayList m_AsyncOperations = new ArrayList();

private struct AsyncOp
{
public readonly Form1 Source;
public readonly IAsyncResult Op;

public AsyncOp(Form1 source, IAsyncResult op)
{
Source = source;
Op = op;
}
}

public Form1()
{
InitializeComponent();
}

// Dispose and InitialiseComponent methods snipped for brevity.

[STAThread]
static void Main()
{
Application.ThreadException += new
ThreadExceptionEventHandler(OnThreadException);
Application.Idle += new EventHandler(OnIdle);
Application.Run(new Form1());
}

private static void OnThreadException(object sender,
ThreadExceptionEventArgs e)
{
MessageBox.Show(e.Exception.ToString(), "OnThreadException");
}

private static void OnIdle(object sender, EventArgs arg)
{
for(int i = 0, n = m_AsyncOperations.Count; i < n; ++i)
{
AsyncOp asyncOp = (AsyncOp)m_AsyncOperations;

if(asyncOp.Op.IsCompleted)
{
try
{
asyncOp.Source.EndInvoke(asyncOp.Op);
}
catch(Exception ex)
{
MessageBox.Show(ex.ToString(), "OnIdle");
}
finally
{
m_AsyncOperations.Remove(asyncOp);
}

break;
}
}
}

private void button1_Click(object sender, System.EventArgs e)
{
int a = 0;

try
{
int b = 1 / a;
}
catch(System.DivideByZeroException ex)
{
throw new ApplicationException("Useful message", ex);
}
}

private void button2_Click(object sender, System.EventArgs e)
{
m_AsyncOperations.Add(new AsyncOp(this, BeginInvoke(new
VoidDlg(AsyncThrow))));
}

private void AsyncThrow()
{
int a = 0;

try
{
int b = 1 / a;
}
catch(System.DivideByZeroException ex)
{
throw new ApplicationException("Useful message", ex);
}
}
}

delegate void VoidDlg();
}
 
Ad

Advertisements

W

Willy Denoyette [MVP]

See Inline ****
Willy.

Martin said:
But I'm calling Control.BeginInvoke not Delegate.BeginInvoke!

*** I know but you call Control.BeginInvoke from the UI thread, this makes
little sense as the delegate method will run on the same UI thread.
You should only call Control.Invoke/BeginInvoke from the non UI thread. (see
Control.InvokeRequired)

The SDK
documentation states 'executes the specified delegate asynchronously
on the thread that the control's underlying handle was created on'.

*** This is correct for Control.BeginInvoke, as long it's called from the
non UI thread it runs asynchronously, but you call it from the UI thread so
the delegate method runs on the UI thread as well.

The documentation then goes on to say 'the BeginInvoke method calls
the specified delegate back on a different thread pool thread' which
is in contradication to what it says five sentences before, but that's
Microsoft documention for you.

*** Correct, the documentation mixes up Deletate.BeginInvoke with
Control.BeginInvoke semantics which are totaly different, I for one whish
MSFT had named Control.BeginInvoke differently.

Testing indicates that the delegate is
executed on the UI thread in idle time. Also the SDK documentation
does not indicate that there is any requirement to match calls to
Control.BeginInvoke with a call to Control.EndInvoke.

*** Right, the documentation should clearly state that calling
Control.EndInvoke is optional, as it should clearly say the it is mandatory
for Delegate.BeginInvoke
to be paired with EndInvoke.

The
documentation for Control.BeginInvoke does however state, 'Exceptions
within the delegate method are considered untrapped and will be sent
to the application's untrapped exception handler'.

*** This is what's hapening in your original sample, the "Divide by Zero
exception" is sent to the untrapped exception handler, it's NOT handled by
your catch handler, so there is no inner exception.
Note that this behavior changes in V2.0 (at least it does in the beta).
I was already aware of how this works with Delegate.BeginInvoke and
Delegate.EndInvoke, but I tested the code you posted anyway and it
does work as you have indicated, although your delegate has a state
parameter which is passed null in your call to BeginInvoke and the
code works exactly the same with a void delegate so the state
parameter is irrelevant.

*** Exact, it was only meant as a sample.

One design flaw with your code though is that
Delegate.BeginInvoke is asynchronous whereas Delegate.EndInvoke
blocks, so if you call EndInvoke straight after you call BeginInvoke
on the same thread it totally defeats the point since the thread that
calls BeginInvoke will block at the call to EndInvoke until the
delegate has completed executing, in other words in terms of execution
order it has the same effect as just calling the delegate method
directly and the only difference is that the delegate method will
execute on a thread pool thread.

*** Exact, but this is only a sample, there is no need to call EndInvoke
directly after calling BeginInvoke.
So then I modified my original example so that it calls BeginInvoke,
stores the object pointer and the IAsyncResult so that in Idle time
once the delegate has completed executing, the app can call EndInvoke
and catch any exceptions. I am aware that this sample is no longer
thread safe but it nevertheless demonstrates the point. The result is
exactly the same as my first sample in that the caught exception will
not be the one I threw.

*** Which is as expected, you still call Control.BeginInvoke from the UI
thread, so AsyncThrow runs synchronously ( on the UI thread).
m_AsyncOperations.Add(new AsyncOp(this, BeginInvoke(new
VoidDlg(AsyncThrow))));

You have to declare an asynchronous delegate and call this like I did in my
sample.

private struct AsyncOp
{
public readonly object Source;
public readonly IAsyncResult Op;

public AsyncOp(object source, IAsyncResult op) // 1st arg. is a delegate
{
Source = source;
Op = op;
}
}

// button2_Click
ParamDlg vdlg = new ParamDlg(AsyncThrow);
m_AsyncOperations.Add(new AsyncOp(vdlg, vdlg.BeginInvoke(null, null,
null)));

// On_Idle
((ParamDlg)asyncOp.Source).EndInvoke(asyncOp.Op);

// your delegate
delegate void ParamDlg(StateObject o);

Another option would be to pass the delegate and the innerexception object
to the state object, and inspect the innerexception in your On_Idle method.

The application I work on has over a hundred asynchronous handlers,

*** Your handler(s) are not asynchronous, as I said before.....
 
W

Willy Denoyette [MVP]

Here's another possible solution.

// On_Click
{
....
// Run AsyncThrow on a ThreadPool thread (asynchronous)
MethodInvoker minv = new MethodInvoker(AsyncThrow);
AsyncCallback acb = new AsyncCallback(CleanUpAsync);
minv .BeginInvoke(acb, null); // This will not block.
}

private void CleanUpAsync(IAsyncResult iar) {
// called on the same thread as the delegate method (AsyncThrow)
// Don't be tempted to touch the UI from here!!!
AsyncResult ar = (AsyncResult) iar;
MethodInvoker minv = (MethodInvoker) ar.AsyncDelegate;
try
{
// Get result from async delegate call
minv .EndInvoke(iar);
}
catch (Exception ex)
{
//Here's your exception object
MessageBox.Show(ex.ToString());
}
}


Willy.
 
M

Martin

Firstly thanks very much for your time Willy. I have to admit that
dotnet exception handling has left me somewhat bemused for quite some
time now, and a third parties professional opinion is more valuable
that all the MS documentation in the world. So here we go:
But I'm calling Control.BeginInvoke not Delegate.BeginInvoke!

*** I know but you call Control.BeginInvoke from the UI thread, this
makes
little sense as the delegate method will run on the same UI thread.
You should only call Control.Invoke/BeginInvoke from the non UI
thread. (see
Control.InvokeRequired)

The SDK
documentation states 'executes the specified delegate asynchronously
on the thread that the control's underlying handle was created on'.

*** This is correct for Control.BeginInvoke, as long it's called from
the
non UI thread it runs asynchronously, but you call it from the UI
thread so
the delegate method runs on the UI thread as well.

This is wrong Willy. It makes perfect sense to call BeginInvoke from
the UI thread if you want your operation to occur asynchronously and
it needs to interact with a single threaded control. The documentation
explicitly states that BeginInvoke can be called from _any_ thread,
which thread BeginInvoke is called from makes no difference, the point
is that BeginInvoke is _always_ an asynchronous operation, even if
called from the UI thread. Asynchronous meaning that the BeginInvoke
call returns before running the delegate, not necessarily meaning the
the delegate must run on another thread because it can run on the UI
thread while it is idling. Stepping through the code proves that
BeginInvoke and the button_click handler have both returned before the
delegate executes.

The
documentation for Control.BeginInvoke does however state, 'Exceptions
within the delegate method are considered untrapped and will be sent
to the application's untrapped exception handler'.

*** This is what's hapening in your original sample, the "Divide by
Zero
exception" is sent to the untrapped exception handler, it's NOT
handled by
your catch handler, so there is no inner exception.
Note that this behavior changes in V2.0 (at least it does in the
beta).

I think this is wrong also. I know you mean that there is no _outer_
exception but I don't think it is because the handler has not executed
and the DivideByZeroException has gone straight to the untrapped
exception handler (Application.ThreadException), you need only step
throught the code in the debugger to see that the catch handler is
executed. In this new demo I wrap the DivideByZeroException in a home
made AppException. The difference with this is that the InnerException
is stored in a new field of the AppException where dotnet cannot get
at it and the base class Exception.InnerException field is left null,
the result of this is that this exception arrives at the
ThreadException handler pristine and unmolested just as it should do.
I believe the inescapable conclusion of this is that between throwing
the exception and handling it in the ThreadException handler dotnet
has for some reason unwrapped it and discarded all but the innermost
exception.

I'm from a C++ background and to me exception handling is the bedrock
upon which all other code depends, and I'm utterly gobsmacked by what
dotnet gets up to in this area. My opinion is that the main benefit of
exceptions is that they flag errors in a way that cannot be ignored,
with a supporting functionality being the ability to rollback state by
unwinding the stack. Dotnet seems to go out of its way to completely
pervert this functionality. Idle time exceptions are dismantled,
worker thread exceptions are eaten unless AppDomain.UnhandledException
is overriden, thread pool exceptions can only be retrieved by putting
a try/catch block around the call to EndInvoke, and
destructor/finaliser exceptions are eaten. And most other programmers
do not seem to expect this behaviour either. The program I'm working
on has been being maintained and upgraded for a couple of years now
and has a reputation for fragility, but none of the other programmers
working on it were aware that most of the exceptions generated by the
program were being silently eaten by dotnet.

I know Delegate.BeginInvoke can be used without this happening but I
need the asynchronous operation to interact with a control on the UI
thread so that will not work for me.

I'm sorry my demo is getting a bit larger but I need to make sure I
can get functional exception handling in all scenarios. The
problematic one we have been discussing is the one occuring where the
'IdleHandler exception' button is pressed. I could have just posted
the changes but I prefer to post complete working samples that others
can just paste and compile.

// Demo.
using System;
using System.Text;
using System.Threading;
using System.Collections;
using System.Windows.Forms;

namespace ExceptionTest2
{
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button messageHandlerBtn;
private System.Windows.Forms.Button idleHandlerBtn;
private System.Windows.Forms.Button workerThreadBtn;
private System.Windows.Forms.Button poolThreadBtn;
private System.ComponentModel.Container components = null;

public Form1()
{
InitializeComponent();
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose(bool disposing)
{
if(disposing)
{
if(components != null)
{
components.Dispose();
}
}

base.Dispose(disposing);
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.messageHandlerBtn = new System.Windows.Forms.Button();
this.idleHandlerBtn = new System.Windows.Forms.Button();
this.workerThreadBtn = new System.Windows.Forms.Button();
this.poolThreadBtn = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// messageHandlerBtn
//
this.messageHandlerBtn.Location = new System.Drawing.Point(88,
8);
this.messageHandlerBtn.Name = "messageHandlerBtn";
this.messageHandlerBtn.Size = new System.Drawing.Size(104, 48);
this.messageHandlerBtn.TabIndex = 0;
this.messageHandlerBtn.Text = "MessageHandler exception";
this.messageHandlerBtn.Click += new
System.EventHandler(this.messageHandlerBtn_Click);
//
// idleHandlerBtn
//
this.idleHandlerBtn.Location = new System.Drawing.Point(88, 72);
this.idleHandlerBtn.Name = "idleHandlerBtn";
this.idleHandlerBtn.Size = new System.Drawing.Size(104, 48);
this.idleHandlerBtn.TabIndex = 1;
this.idleHandlerBtn.Text = "IdleHandler exception";
this.idleHandlerBtn.Click += new
System.EventHandler(this.idleHandlerBtn_Click);
//
// workerThreadBtn
//
this.workerThreadBtn.Location = new System.Drawing.Point(88,
136);
this.workerThreadBtn.Name = "workerThreadBtn";
this.workerThreadBtn.Size = new System.Drawing.Size(104, 48);
this.workerThreadBtn.TabIndex = 2;
this.workerThreadBtn.Text = "WorkerThread exception";
this.workerThreadBtn.Click += new
System.EventHandler(this.workerThreadBtn_Click);
//
// button1
//
this.poolThreadBtn.Location = new System.Drawing.Point(88, 208);
this.poolThreadBtn.Name = "poolThreadBtn";
this.poolThreadBtn.Size = new System.Drawing.Size(104, 48);
this.poolThreadBtn.TabIndex = 3;
this.poolThreadBtn.Text = "PoolThread exception";
this.poolThreadBtn.Click += new
System.EventHandler(this.poolThreadBtn_Click);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(292, 266);
this.Controls.Add(this.poolThreadBtn);
this.Controls.Add(this.workerThreadBtn);
this.Controls.Add(this.idleHandlerBtn);
this.Controls.Add(this.messageHandlerBtn);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);

}
#endregion

[STAThread]
static void Main()
{
AppDomain.CurrentDomain.UnhandledException += new
UnhandledExceptionEventHandler(OnUnhandledException);
Application.ThreadException += new
ThreadExceptionEventHandler(OnThreadException);
Application.Run(new Form1());
}

// Catches worker thread exceptions.
private static void OnUnhandledException(object sender,
UnhandledExceptionEventArgs arg)
{
MessageBox.Show("The thread " + Thread.CurrentThread.Name + "
has thrown an unhandled exception:\r\n\r\n" +
arg.ExceptionObject.ToString(), "OnUnhandledException");
}

// Catches message handler and idle handler exceptions.
private static void OnThreadException(object sender,
ThreadExceptionEventArgs e)
{
MessageBox.Show("The thread " + Thread.CurrentThread.Name + "
has thrown an unhandled exception:\r\n\r\n" + e.Exception.ToString(),
"OnThreadException");
}

// Throws an exception from a window message handler.
// Normally the default Application.ThreadException handler
handles this fine.
private void messageHandlerBtn_Click(object sender,
System.EventArgs e)
{
int a = 0;

try
{
int b = 1 / a;
}
catch(System.DivideByZeroException ex)
{
throw new ApplicationException("Useful message", ex);
}
}

// Throws an exception from the idle processing handler.
// Normally the default Application.ThreadException handler only
gets
// the innermost exception, throwing an AppException instead fixes
this.
private void idleHandlerBtn_Click(object sender, System.EventArgs
e)
{
BeginInvoke(new VoidDlg(IdleThrow));
}

private void IdleThrow()
{
int a = 0;

try
{
int b = 1 / a;
}
catch(System.DivideByZeroException ex)
{
// This will not work, only the inner exception will be
caught??
//throw new ApplicationException("Useful message", ex);

// Now this will work.
throw new AppException("Useful message", ex);
}
}

// Throws an exception from a worker thread.
// This is normally eaten silently. Override
AppDomain.UnhandledException
// to display a messagebox and terminate the Application and this
is fine.
private void workerThreadBtn_Click(object sender, System.EventArgs
e)
{
Thread thread = new Thread(new ThreadStart(WorkerThreadThrow));
thread.Name = "MyWorkerThread";
thread.Start();
}

private void WorkerThreadThrow()
{
int a = 0;

try
{
int b = 1 / a;
}
catch(System.DivideByZeroException ex)
{
throw new ApplicationException("Useful message", ex);
}
}

// Throws an exception from a pool thread.
// This is normally eaten silently, even after overriding
// AppDomain.UnhandledException this is still eaten silently.
private void poolThreadBtn_Click(object sender, System.EventArgs
e)
{
VoidDlg voidDlg = new VoidDlg(PoolThreadThrow);
voidDlg.BeginInvoke(new AsyncCallback(OnAsyncResult), voidDlg);
}

private void PoolThreadThrow()
{
int a = 0;

try
{
int b = 1 / a;
}
catch(System.DivideByZeroException ex)
{
throw new ApplicationException("Useful message", ex);
}
}

private void OnAsyncResult(IAsyncResult result)
{
VoidDlg voidDlg = (VoidDlg)result.AsyncState;

try
{
voidDlg.EndInvoke(result);
}
catch(Exception e)
{
OnUnhandledException(this, new UnhandledExceptionEventArgs(e,
false));
}
}
}

delegate void VoidDlg();

public class AppException : Exception
{
Exception m_InnerException = null;

public AppException(string message, Exception innerException) :
base(message)
{
m_InnerException = innerException;
}

public Exception InnerAppException
{
get{ return m_InnerException; }
}

public override string ToString()
{
StringBuilder message = new StringBuilder(2048);
GenerateMessage(this, ref message, true);
return message.ToString();
}

private void GenerateMessage(Exception e, ref StringBuilder
message, bool topLevelRecurse)
{
System.Type exceptionType = e.GetType();
message.Append(exceptionType.ToString());
message.Append(": ");
message.Append(e.Message);

AppException AppException = e as AppException;

if(AppException != null)
{
if(AppException.InnerAppException != null)
{
message.Append(" ---> ");
GenerateMessage(AppException.InnerAppException, ref message,
false);
}
}
else if(e.InnerException != null)
{
message.Append(" ---> ");
GenerateMessage(e.InnerException, ref message, false);
}

message.Append("\r\n");
message.Append(e.StackTrace.ToString());

if(!topLevelRecurse)
{
message.Append("\r\n --- End of inner exception stack trace
---");
}
}
}
}
 
W

Willy Denoyette [MVP]

Martin,
This is wrong Willy. It makes perfect sense to call BeginInvoke from
the UI thread if you want your operation to occur asynchronously and
it needs to interact with a single threaded control.

**** But you can interact with a control from ANY thread in the process, as
long as you marshal the call ( using ... Control.BeginInvoke) to the thread
owning the handle of the control.
So IMO what you need it to run your delegate method on a pool thread.

The documentation
explicitly states that BeginInvoke can be called from _any_ thread,
which thread BeginInvoke is called from makes no difference, the point
is that BeginInvoke is _always_ an asynchronous operation, even if
called from the UI thread. Asynchronous meaning that the BeginInvoke
call returns before running the delegate, not necessarily meaning the
the delegate must run on another thread because it can run on the UI
thread while it is idling. Stepping through the code proves that
BeginInvoke and the button_click handler have both returned before the
delegate executes.
*** Hmmm.... let's say I was a little affraid you were thinking you were
running your delegate on a separate thread, what means you need an
asynchronous delegate.
I know BeginInvoke returns before the operation (the delegate method)
actualy run's.
Now in this particular case (calling BeginInvoke from the UI thread) the
delegate method cannot even start running before the Click handler returns,
suppose you have some work to finish up before yield execution of the
delegate, you can continue execution of your code in the click handler -
(which is IMO the only reason why you should call BeginInvoke from the UI
thread). Only after you exit your handler and then only during the next set
of of activity on the messagepump will the delegate method be run (well, in
the order it was placed on the queue).
So the execution is constrained by the activity on the UI threads, and
that's why I said it wasn't asynchronous, - the caller is not blocked
waiting for the delegate method to return, but the delegate method is
blocked waiting for the MSG queue to drain, and this only happens when the
caller returns from a message handler. Again that is why I said the delegate
run's synchronoulsly.

I think this is wrong also. I know you mean that there is no _outer_
exception but I don't think it is because the handler has not executed
and the DivideByZeroException has gone straight to the untrapped
exception handler (Application.ThreadException), you need only step
throught the code in the debugger to see that the catch handler is
executed. In this new demo I wrap the DivideByZeroException in a home
made AppException. The difference with this is that the InnerException
is stored in a new field of the AppException where dotnet cannot get
at it and the base class Exception.InnerException field is left null,
the result of this is that this exception arrives at the
ThreadException handler pristine and unmolested just as it should do.
I believe the inescapable conclusion of this is that between throwing
the exception and handling it in the ThreadException handler dotnet
has for some reason unwrapped it and discarded all but the innermost
exception.

*** Sorry, I wrong here, I was looking on V2.0 not V1.1, need to investigate
this further.
I'm from a C++ background and to me exception handling is the bedrock
upon which all other code depends, and I'm utterly gobsmacked by what
dotnet gets up to in this area. My opinion is that the main benefit of
exceptions is that they flag errors in a way that cannot be ignored,
with a supporting functionality being the ability to rollback state by
unwinding the stack. Dotnet seems to go out of its way to completely
pervert this functionality. Idle time exceptions are dismantled,

*** What exactly are Idle time exceptions?
worker thread exceptions are eaten unless AppDomain.UnhandledException
is overriden, thread pool exceptions can only be retrieved by putting
a try/catch block around the call to EndInvoke, and
destructor/finaliser exceptions are eaten.

*** This is because exceptions do not flow accross threads (worker threads -
thread pool threads), without an explicit request for it (the exception
object) by means of a call to EndInvoke. This is exactly the same behavior
when using threads in C++.

And most other programmers
do not seem to expect this behaviour either. The program I'm working
on has been being maintained and upgraded for a couple of years now
and has a reputation for fragility, but none of the other programmers
working on it were aware that most of the exceptions generated by the
program were being silently eaten by dotnet.

I know Delegate.BeginInvoke can be used without this happening but I
need the asynchronous operation to interact with a control on the UI
thread so that will not work for me.

*** If you mean by - asynchronous operation - your delegate method, what
stops you to interact with a control from this method?
You don't even have to marshal the call (using Control.BeginInvoke/Invoke)
as you run the delegate method on the same UI thread, or am I missing
something?
Another thing which isn't clear is, why you need your delegate method to run
on the UI thread?


The
problematic one we have been discussing is the one occuring where the
'IdleHandler exception' button is pressed. I could have just posted
the changes but I prefer to post complete working samples that others
can just paste and compile.

Well, that is exactly the thing that works in V1.X but doesn't work in V2.0.
I will take some time to investigate further and post my findings when done.

Willy.
 
M

Martin

**** But you can interact with a control from ANY thread in the
process, as
long as you marshal the call ( using ... Control.BeginInvoke) to the
thread
owning the handle of the control.
So IMO what you need it to run your delegate method on a pool thread

If you have a method that calls into several controls a dozen times
each, it is more efficient to bundle all that interaction into a
separate method and BeginInvoke that method once instead of
BeginInvoking every call to every control. Also how could you
BeginInvoke a property set like Control.Text = "whatever" or attach an
event handler from another thread? I think there are times when it is
just a damn sight simpler to be on the 'right' thread.

*** Hmmm.... let's say I was a little affraid you were thinking you
were
running your delegate on a separate thread, what means you need an
asynchronous delegate.
I know BeginInvoke returns before the operation (the delegate method)
actualy run's.
Now in this particular case (calling BeginInvoke from the UI thread)
the
delegate method cannot even start running before the Click handler
returns,
suppose you have some work to finish up before yield execution of the
delegate, you can continue execution of your code in the click handler
-
(which is IMO the only reason why you should call BeginInvoke from the
UI
thread). Only after you exit your handler and then only during the
next set
of of activity on the messagepump will the delegate method be run
(well, in
the order it was placed on the queue).
So the execution is constrained by the activity on the UI threads, and
that's why I said it wasn't asynchronous, - the caller is not blocked
waiting for the delegate method to return, but the delegate method is
blocked waiting for the MSG queue to drain, and this only happens when
the
caller returns from a message handler. Again that is why I said the
delegate
run's synchronoulsly.

The scenario you describe here is exactly what happens when you attach
a handler to the Application.Idle event from a method running on the
UI thread. For the same reason the Application.Idle event will not
occur until the current handler returns and the message queue is
emptied. Using BeginInvoke is just a convienient way of executing a
handler with an arbitrary method signature once only, if you use
Application.Idle you have to attach an EventHandler delegate and the
handler will be executed every time the message queue is emptied until
you detach the handler. The invokation is asynchronous in the normal
programming sense that it does not block the calling code, however
execution of the current handler will have completely finished before
the invoked handler begins and execution of the two handlers will
never overlap which I think is what you mean when you say they execute
synchronously, but I believe this is less ambiguously described by
saying the handler is called asynchronously, it just executes
concurrently.

This is what I mean by an idle time exception. An idle handler is a
handler that executes not as a result of user input, but when the
message queue is emptied, eg a BeginInvoked handler or a handler
attached to the Application.Idle event. An idle time exception is an
exception thrown from one of these handlers.

I have just noticed that an exception thrown from the Application.Idle
handler is not stripped down to just its innermost exception in the
same way as an exception thrown from a BeginInvoked handler, I wonder
if I could devise a way to attach an abitrary delegate to the Idle
event so that it is executed just once.
worker thread exceptions are eaten unless AppDomain.UnhandledException
is overriden, thread pool exceptions can only be retrieved by putting
a try/catch block around the call to EndInvoke, and
destructor/finaliser exceptions are eaten.

*** This is because exceptions do not flow accross threads (worker
threads -
thread pool threads), without an explicit request for it (the
exception
object) by means of a call to EndInvoke. This is exactly the same
behavior
when using threads in C++.

I understand that exceptions do not flow across thread boundaries
automatically in dotnet or C++, but the behaviour is not exactly the
same in dotnet as in C++ because in C++ if a worker thread throws an
exception that is not handled a message is displayed by the C runtime
and the application is terminated. This means the exception cannot be
ignored or missed by developers which is far preferable to it being
silently eaten which IMO completely defeats the point. I know you
_can_ handle the exception in dotnet if you choose to (and can work
out how to do it), the point is it should be impossible to 'not handle
the exception and yet still have the application continue as if
nothing has happened'.

And most other programmers
do not seem to expect this behaviour either. The program I'm working
on has been being maintained and upgraded for a couple of years now
and has a reputation for fragility, but none of the other programmers
working on it were aware that most of the exceptions generated by the
program were being silently eaten by dotnet.

I know Delegate.BeginInvoke can be used without this happening but I
need the asynchronous operation to interact with a control on the UI
thread so that will not work for me.

*** If you mean by - asynchronous operation - your delegate method,
what
stops you to interact with a control from this method?
You don't even have to marshal the call (using
Control.BeginInvoke/Invoke)
as you run the delegate method on the same UI thread, or am I missing
something?
Another thing which isn't clear is, why you need your delegate method
to run
on the UI thread?

In my sample I am BeginInvoking from the UI thread but our actual
application does this from background threads, possibly hardware event
handlers which must return very quickly to prevent deadlocks
elsewhere. Also I do not know how to set control properties or attach
handlers to controls from other threads. Bear in mind that the posted
application is just a demonstration, it is obviously somewhat
contrived.

Thanks again for your insights Willy, I will be very interested to see
the results of your investigation.
 
Ad

Advertisements

W

Willy Denoyette [MVP]

Martin said:
**** But you can interact with a control from ANY thread in the
process, as
long as you marshal the call ( using ... Control.BeginInvoke) to the
thread
owning the handle of the control.
So IMO what you need it to run your delegate method on a pool thread

If you have a method that calls into several controls a dozen times
each, it is more efficient to bundle all that interaction into a
separate method and BeginInvoke that method once instead of
BeginInvoking every call to every control. Also how could you
BeginInvoke a property set like Control.Text = "whatever" or attach an
event handler from another thread? I think there are times when it is
just a damn sight simpler to be on the 'right' thread.

Martin,

Here is a sample on how you can marshal method invocations to the UI thread.
The way you do this is as efficient as calling BeginInvoke from the UI
thread, both simply post a message to the message queue, and run the
delegate method on the UI thread. Sure this involves a thread switch, but
long running tasks should never run on the UI thread anyway (here, I
consider > 2 sec. long running).

public class Form1 : System.Windows.Forms.Form
{
// define some getters for the stuff you want to expose to the public
public Form mainForm
{
get { return this;}
}

public Button poolThButton
{
get { return poolThreadBtn;}
}
.....


// This runs on a worker thread
private void PoolThreadThrow()
{
int a = 0;
DoSetSomeUIStuff();
try
{
int b = 1 / a;
}
catch(System.DivideByZeroException ex)
{
throw new ApplicationException("Useful message", ex);
}
}

private void DoSetSomeUIStuff()
{
// are we on the right UI thread?
if(mainForm.InvokeRequired)
{
// No we don't, so we need to marshal the call to the UI thread,
// here we use a MethodInvoker delegate, but other delegates
// will do as well
poolThreadBtn.BeginInvoke(new MethodInvoker(DoSetSomeUIStuff));
}
else
{
// we run on the UI thread, so we can directly touch the mainForm control
and its child controls
// here you can bundle all activities you need to perform on the UI
elements
mainForm.Text = "Hello";
poolThreadBtn.BackColor = System.Drawing.Color.Red;
}
}

Willy.
 
Ad

Advertisements

M

Martin

I think we have misunderstood each other about this bit Willy. When
you said:
**** But you can interact with a control from ANY thread in the
process, as
long as you marshal the call ( using ... Control.BeginInvoke) to the
thread
owning the handle of the control.
So IMO what you need it to run your delegate method on a pool thread

I then said:
If you have a method that calls into several controls a dozen times
each, it is more efficient to bundle all that interaction into a
separate method and BeginInvoke that method once instead of
BeginInvoking every call to every control. Also how could you
BeginInvoke a property set like Control.Text = "whatever" or attach an
event handler from another thread? I think there are times when it is
just a damn sight simpler to be on the 'right' thread.

Because I thought you were advocating this style where the actual
calls into the controls are marshalled.

void ThreadPoolMethod()
{
// Do some UI stuff.
BeginInvoke(new SetStyleDelegate(control1.SetStyle), new object[]{
ControlStyles.UserPaint, true });
BeginInvoke(new VoidDelegate(control1.Show));

// But this cannot be done.
BeginInvoke(new SetTextDelegate(control1.set_Text), new object[]{
"New Text" });

}

Whereas I was advocating the style you then demonstrated in your
sample where all the UI stuff is bundled together in a separate helper
method which is BeginInvoked once. So in this regard we are in
complete agreement, I simply misunderstood your initial reply.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top