Exceptional enlightenment

  • Thread starter Thread starter Henry
  • Start date Start date
H

Henry

I am puzzled by something. I have a program foo.cs it has
a reference to an assembly bar.cs. The latter
intentionally performs a divide by zero. The former has a
try/catch pair for the offending method invocation which
works in 2/3 of the cases I have tested. I am calling the
bar.method() (which returns a string) as the first
argument to MessageBox.show():

1) Running in the debugger - works
2) Running from bin/Debug - does not (unhandled exception)
3) Running from bin/Debug with bar.exe.config - works

bar.exe.config contains:

<system.windows.forms jitDebugging="true" />

I suspect it is choking in the MessageBox.Show method. I
can certainly work around it, but I would really like to
know what is going on before adding a string object to do
that.

Can I get an expert opinion on this?

Sorry if this is a repeat question

Henry
 
I don't fully understand exceptions on other threads / UI threads.. yet.
I've been looking into it for windows forms applications. I'm not sure if
this is applicable to your MessageBox.Show problem, but I had very similar
results to you where it worked / didn't work.

These are the two exception handler statements I've setup to catch unhandled
exceptions for the entire app. (See example below).

Application.ThreadException += new
System.Threading.ThreadExceptionEventHandler
(CatchThreadException);
AppDomain.CurrentDomain.UnhandledException += new
UnhandledExceptionEventHandler (CatchUnhandledException);


--
Mike Mayer
http://www.mag37.com/csharp/
(e-mail address removed)

Full test program...


using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;

namespace UnhandledExceptions
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button button1;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

public Form1()
{
//
// Required for Windows Form Designer support
//
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.button1 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(88, 64);
this.button1.Name = "button1";
this.button1.TabIndex = 0;
this.button1.Text = "button1";
this.button1.Click += new
System.EventHandler(this.button1_Click);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(292, 266);
this.Controls.AddRange(new System.Windows.Forms.Control[] {

this.button1});
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);

}
#endregion

private void button1_Click(object sender, System.EventArgs e)
{
BadMethod();
}

void BadMethod ()
{
throw new Exception ("Not a helpful message");
}

static void CaughtException (Exception e)
{
Console.WriteLine ("I caught the exception: ");
if (e != null)
{
Console.WriteLine (e.ToString());
}
Console.ReadLine();
Console.WriteLine ("Cool");
}

static void CatchThreadException (
object sender,
System.Threading.ThreadExceptionEventArgs e
)
{
CaughtException (e.Exception);
}


static void CatchUnhandledException(
object sender,
UnhandledExceptionEventArgs e
)
{
CaughtException (e.ExceptionObject as Exception);
}


/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
Application.ThreadException += new
System.Threading.ThreadExceptionEventHandler
(CatchThreadException);
AppDomain.CurrentDomain.UnhandledException += new
UnhandledExceptionEventHandler
(CatchUnhandledException);

Form1 form1 = new Form1();
Application.Run (form1);

}



}
}
 
Thanks Mike:

The article states "In the application configuration
file, add a system.windows.forms element under the
configuration element and set the jitDebugging attribute
to true. Now you'll get the JIT dialog instead of the
normal exception."

My trouble is that I don't get the JIT dialog; instead my
app works fine handling the exception as expected. I am
calling the offending method from fooButton_Click() and
wonder if that may be the cause. It is the nonorthogonal
nature of the problem that has me scratching my head.

Henry
 
Thanks again Mike:

This does look quite a bit like my problem. I will give
it a try tomorrow.

Henry
 
Thank you Mike. That was indeed the problem. Now I just
need to figure out why it works. One of my books alludes
to the possibility that this might be a bug in the CLR.

Henry
 
So in this example "CatchUnhandledException" is just a standard exception
class that you created? Thanks for this example.

--
William Stacey, DNS MVP

Michael Mayer said:
I don't fully understand exceptions on other threads / UI threads.. yet.
I've been looking into it for windows forms applications. I'm not sure if
this is applicable to your MessageBox.Show problem, but I had very similar
results to you where it worked / didn't work.

These are the two exception handler statements I've setup to catch unhandled
exceptions for the entire app. (See example below).

Application.ThreadException += new
System.Threading.ThreadExceptionEventHandler
(CatchThreadException);
AppDomain.CurrentDomain.UnhandledException += new
UnhandledExceptionEventHandler (CatchUnhandledException);


--
Mike Mayer
http://www.mag37.com/csharp/
(e-mail address removed)

Full test program...


using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;

namespace UnhandledExceptions
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button button1;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

public Form1()
{
//
// Required for Windows Form Designer support
//
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.button1 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(88, 64);
this.button1.Name = "button1";
this.button1.TabIndex = 0;
this.button1.Text = "button1";
this.button1.Click += new
System.EventHandler(this.button1_Click);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(292, 266);
this.Controls.AddRange(new System.Windows.Forms.Control[] {

this.button1});
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);

}
#endregion

private void button1_Click(object sender, System.EventArgs e)
{
BadMethod();
}

void BadMethod ()
{
throw new Exception ("Not a helpful message");
}

static void CaughtException (Exception e)
{
Console.WriteLine ("I caught the exception: ");
if (e != null)
{
Console.WriteLine (e.ToString());
}
Console.ReadLine();
Console.WriteLine ("Cool");
}

static void CatchThreadException (
object sender,
System.Threading.ThreadExceptionEventArgs e
)
{
CaughtException (e.Exception);
}


static void CatchUnhandledException(
object sender,
UnhandledExceptionEventArgs e
)
{
CaughtException (e.ExceptionObject as Exception);
}


/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
Application.ThreadException += new
System.Threading.ThreadExceptionEventHandler
(CatchThreadException);
AppDomain.CurrentDomain.UnhandledException += new
UnhandledExceptionEventHandler
(CatchUnhandledException);

Form1 form1 = new Form1();
Application.Run (form1);

}



}
}
 
William Stacey said:
So in this example "CatchUnhandledException" is just a standard exception
class that you created? Thanks for this example.

No, it's a method with the correct signature for the
UnhandledExceptionEventHandler delegate. The full code was listed at the
bottom of my previous message.

Unfortunately, the ThreadExceptionEventHandler and the
UnhandledExceptionEventHandler have different signatures. So I ended up
with two methods - one for each delegate. Each one simply called this
method:

CaughtException (Exception e)

which in my "real apps" would be a dialog to notify the user and/or logging
logic to store the error in the event log, a file, etc. This is where I
would plugin Microsoft's Exception Management Application Block:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnbda/html/emab-rm.asp?frame=true


Mike Mayer
http://www.mag37.com/csharp/
(e-mail address removed)
 
I just want to follow up on this adventure. After Mike so
kindly put me on the right path, I looked up
ThreadExceptionEventHandler in Applied Microsoft .NET
Framework Prgramming - Jeffrey Richter, and I found a
cogent description on Pages 432-440. In particular the
following passage summed up what I was seeing.

"As I explained, the behavior of NativeWindows internal
method is to catch all CLS-compliant exceptions and
display a dialog box or call any callback method that
you've registered with the ThreadException event.
However, some situations can change this default
behavior. First, if a debugger is attached to your
Windows Forms application, any unhandled exception is
allowed to propogate up the call stack. Second, if a JIT
debugger is installed and if the jitDebugging
configuration setting is specified in the application's
XML .config file, then again, the exception isn't caught
and the exception is allowed to propogate up the
callstack"

Now I get it. This does seem a bit arcane for a
technology which is supposed to reduce development time.
Furthermore, it would seem to be rich a source of hidden
bugs which QA or customers might find instead of the
deveopers.

Thanks again Mike.

Henry
 
Back
Top