Unhandled Exception Handling

R

Rob Lorimer

My AddIn is multi threaded, Office2003 Excel.

Questions

1) I already know that Unhandled exceptions in dot Net are caught by adding
handlers as follows:

//Forms App
Application.ThreadException += new ThreadExceptionEventHandler(
Application_ThreadException);

//Console App
AppDomain.CurrentDomain.UnhandledException += new
UnhandledExceptionEventHandler(MyHandler)

I've read information about this extensively but I can't find how this
relates to add-ins. I'm guessing I should use the Console App approach for
my add-in. Is this correct?

2) I create a toolbar in the office App with buttons. I set up event
handlers for click events for each button. Does each button click event run
on the same single thread? or is a new thread created for each event
procedure?

3) Will my unhandled exception handler respond to all unhandled exceptions
that occur during the button event procedures in '2)'?

4) Because my app is multi-threaded, unhandled exceptions from my worker
threads silently exit without running any global unhandled exception handler.
This is documented in numerous articles but no advice is given on how to
address the issue. How do I address this in a shared add-in?

Rob Lorimer
Extreme Systems Ltd (NZ)
 
P

Peter Huang [MSFT]

Hi

Comments in line.

Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.
--------------------
Thread-Topic: Unhandled Exception Handling
thread-index: AcVCGMftSi1zfJHdSFKvo1JLHYkQ3g==
X-WBNR-Posting-Host: 222.152.47.238
From: "=?Utf-8?B?Um9iIExvcmltZXI=?=" <[email protected]>
Subject: Unhandled Exception Handling
Date: Fri, 15 Apr 2005 17:11:05 -0700
Lines: 34
Message-ID: <[email protected]>
MIME-Version: 1.0
Content-Type: text/plain;
charset="Utf-8"
Content-Transfer-Encoding: 7bit
X-Newsreader: Microsoft CDO for Windows 2000
Content-Class: urn:content-classes:message
Importance: normal
Priority: normal
X-MimeOLE: Produced By Microsoft MimeOLE V6.00.3790.0
Newsgroups: microsoft.public.office.developer.com.add_ins
NNTP-Posting-Host: TK2MSFTNGXA03.phx.gbl 10.40.2.250
Path: TK2MSFTNGXA02.phx.gbl!TK2MSFTNGXA01.phx.gbl!TK2MSFTNGXA03.phx.gbl
Xref: TK2MSFTNGXA02.phx.gbl microsoft.public.office.developer.com.add_ins:8264
X-Tomcat-NG: microsoft.public.office.developer.com.add_ins

My AddIn is multi threaded, Office2003 Excel.

Questions

1) I already know that Unhandled exceptions in dot Net are caught by adding
handlers as follows:

//Forms App
Application.ThreadException += new ThreadExceptionEventHandler(
Application_ThreadException);

//Console App
AppDomain.CurrentDomain.UnhandledException += new
UnhandledExceptionEventHandler(MyHandler)

I've read information about this extensively but I can't find how this
relates to add-ins. I'm guessing I should use the Console App approach for
my add-in. Is this correct?

Yes.

2) I create a toolbar in the office App with buttons. I set up event
handlers for click events for each button. Does each button click event run
on the same single thread? or is a new thread created for each event
procedure?

Yes, they are in the same thread.
3) Will my unhandled exception handler respond to all unhandled exceptions
that occur during the button event procedures in '2)'?

Yes, as long as all the codes are in the same thread.
4) Because my app is multi-threaded, unhandled exceptions from my worker
threads silently exit without running any global unhandled exception handler.
This is documented in numerous articles but no advice is given on how to
address the issue. How do I address this in a shared add-in?

Because of the Win32 Exception mechanism, the exception is thread based,
that is to say, the exception in one thread will go up through of the call
stack of the thread until it is handled. But we can not catch one thread's
exception in another thread.

From your scenario, I suggest you make some try...catch blocks to enbrace
all the code in the Onconnection, OnDisconnection .... method. So that we
can guarantee all the exception will be handled.
 
R

Rob Lorimer

I've now set up a method to hook the unhandled event handler...it works well
when the exception occurs within any of my toolbar button events.

But if one of my button click events opens a non modal form, the exception
event handler doesn't catch exceptions from the form! This may be because
the click event method has finished and the form will be on a new thread?

How do I add an unhandled event handler to the form so that any unhandled
exceptions in any of it's events will be caught?

Rob
 
P

Peter Huang [MSFT]

Hi Rob,

Thanks for your quick response.
Winform has a different exception handle mechanism in .NET, the AppDomain
UnhandledException will not catch the winform thrown exception, this is by
design.
For winform application, we need to handle the ThreadException.

private void button1_Click(object sender, System.EventArgs e)
{
Application.ThreadException+=new
System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
throw new Exception();
}
private void Application_ThreadException(object sender,
System.Threading.ThreadExceptionEventArgs e)
{
System.Diagnostics.Debug.WriteLine(((Exception)e.Exception).ToString());
}

If you still have any concern, please feel free to post here.


Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.
 
A

Alex

Hello Peter,
I am also interested in this topic.

"Peter Huang" said:
Winform has a different exception handle mechanism in .NET, the AppDomain
UnhandledException will not catch the winform thrown exception, this is by
design.
For winform application, we need to handle the ThreadException.

private void button1_Click(object sender, System.EventArgs e)
{
Application.ThreadException+=new
System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
throw new Exception();
}
private void Application_ThreadException(object sender,
System.Threading.ThreadExceptionEventArgs e)
{
System.Diagnostics.Debug.WriteLine(((Exception)e.Exception).ToString());
}

I understood from Rob's post that he needs it to work in an Extensibility add-in.
I am not sure that Application.ThreadException will work in that scenario.
 
R

Rob Lorimer

This is the exact problem ... this is not a winforms 'application' it is an
add-in.

Try this yourself:

Make a shared add-in that creates a toolbar button.
In the event handler for the click event of this button open a form.
The form should have a button on it.
In the event handler for the forms button, throw an unhandled exception.

Using either of the following hooks in the add-in does not work.

//Forms App
Application.ThreadException += new ThreadExceptionEventHandler(
Application_ThreadException);

//Console App
AppDomain.CurrentDomain.UnhandledException += new
UnhandledExceptionEventHandler(MyHandler)

I'm desparate to catch this unhandled exception in some form of global
handler so I can send an email, event log it, alert user and clean up.

How do I hook any unhandled exception in form events when the form is opened
from my add-in?

Rob
 
P

Peter Huang [MSFT]

Hi Rob,

I am sorry if I did not make it more clear.
Since the winform has differenct mechanism.
Since the AppDomain.UnhandledException will not catch the winform's
UnhandledException.
We need to use Application.ThreadException to handle the UnhandledException
from winform.

We need to Add Handler to the Application.ThreadException in the Winform's
form_load or other method, because the Application is in the winform's
context.
(private void button1_Click(object sender, System.EventArgs e) in my last
post is the winform's button_click while not the addin's)
That is to say we need to handle the AppDomain.UnhandledException in the
addin wide, and handle the Application.ThreadException in all the winform
wide.


We have a similar case, and confirmed that this behavior is by design.
If you still have any concern, I think you may try to contact MSPSS to see
if they have any further idea about the issue.
http://support.microsoft.com

Thanks for your understanding!

Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.
 
R

Rob Lorimer

I still don't think you understand the problem.

There is no Application object accessible in the form_load event for a form
that is opened from an addin ie the form is not started from Application.Run?

Please post a solution (prefer c#) of an addin that provides unhandled
exception handling for (or within) a form opened from the addin.

Rob
 
A

Alex

Rob Lorimer said:
I still don't think you understand the problem.

There is no Application object accessible in the form_load event for a form
that is opened from an addin ie the form is not started from Application.Run?

Please post a solution (prefer c#) of an addin that provides unhandled
exception handling for (or within) a form opened from the addin.

Peter,

I second the request for a working sample code.

Also, if there are multiple forms, should a handler be set up for each one?
 
P

Peter Huang [MSFT]

Hi Rob,Alex,

Based on my discussion with a Office Team Senior Engineer, here is the
result.
First off, this is a addin and methods that through exception back to
Office can be caught by Office and therfore not be "unhandled" to start
with. Second, if you are using the COM Shim Wizard to generate security
context for the managed Com Addin, then yes you are in a new (non-default)
appdomain. Third, the documentation talks about WinForm applications, which
I presume to mean host applications where the CLR controls the message loop
and app startup (etc.), not simply a WinForm shown from DLL in an unmanaged
host. I don't think there is a way to set just a filter for managed code. I
think this applied to entire application, which is problematic since Office
has its own filter (for watson reporting and document recovery) which you
don't want to mess with.

Based on my test, we just need to set the filter to the
Application.ThreadException one time even if there are more than one form.
Also according to the document
AppDomain.UnhandledException Event [C#]
This event occurs only for the application domain that is created by the
system when an application is started. If an application creates additional
application domains, specifying a delegate for this event in those
applications domains has no effect.

So the AppDomain.UnhandledException is not available in the Addin. But
even if we throw Exceptoin in the Addin(Except winform), the exception
will not propagate to the OS, and it will be caught by the Office own
filter.

So I think the best practice is to enbrace the "problem" in a try..catch
block everywhere.

Anyway, here I post the C# code per your request.
[Addin]
namespace MyAddin7
{
using System;
using Office = Microsoft.Office.Core;
using Extensibility;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Excel = Microsoft.Office.Interop.Excel;
using System.Diagnostics;
[GuidAttribute("5B4E30C3-0E48-4749-8342-F097935ADB0A"),
ProgId("MyAddin7.Connect")]
public class Connect : Object, Extensibility.IDTExtensibility2
{
public Connect()
{
}
public void OnConnection(object application,
Extensibility.ext_ConnectMode connectMode, object addInInst, ref
System.Array custom)
{
Debug.WriteLine("OnConnection");
exApp = application as Excel.Application;
addInInstance = addInInst;
}
public void OnDisconnection(Extensibility.ext_DisconnectMode
disconnectMode, ref System.Array custom)
{
cbb.Delete(true);
cb.Delete();
}
public void OnAddInsUpdate(ref System.Array custom)
{
}
Office.CommandBar cb=null;
Office.CommandBarButton cbb=null;
Office.CommandBarButton cbbt=null;
public void OnStartupComplete(ref System.Array custom)
{
object oMissing = System.Reflection.Missing.Value;

cb=exApp.CommandBars.Add("Test",Office.MsoBarPosition.msoBarFloating,oMissin
g,oMissing);

cbb =
(Office.CommandBarButton)cb.Controls.Add(Office.MsoControlType.msoControlBut
ton,oMissing,oMissing,oMissing,oMissing);
cbb.Caption = "ShowForm";
cbb.Style = Office.MsoButtonStyle.msoButtonCaption;
cbb.Click+=new
Microsoft.Office.Core._CommandBarButtonEvents_ClickEventHandler(cbb_Click);
}
public void OnBeginShutdown(ref System.Array custom)
{

}

private Excel.Application exApp=null;
private object addInInstance;
private void curAppDomain_UnhandledException(object sender,
UnhandledExceptionEventArgs e)
{
Debug.WriteLine("curAppDomain_UnhandledException: Catch Exception " +
((Exception)e.ExceptionObject).ToString());
}

private void cbb_Click(Microsoft.Office.Core.CommandBarButton Ctrl, ref
bool CancelDefault)
{
Form1 fm = new Form1();
fm.Show();
Form2 fm2 = new Form2();
fm2.Show();
}
}
}


[Form1]
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Diagnostics;
namespace MyAddin7
{
public class Form1 : System.Windows.Forms.Form
{
//.........................................
//.........................................

private void button1_Click(object sender, System.EventArgs e)
{
throw new Exception("My Test Exception from winform");
}

private void Form1_Load(object sender, System.EventArgs e)
{
Application.ThreadException+=new
System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
}

private void Application_ThreadException(object sender,
System.Threading.ThreadExceptionEventArgs e)
{
Debug.WriteLine("Application_ThreadException: Catch Exception:" +
e.Exception.ToString());
}
}
}
[Form2]
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;

namespace MyAddin7
{
//.................................................................
//.................................................................
private void button1_Click(object sender, System.EventArgs e)
{
throw new Exception("From winform 2");
}
}
}

Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Y

Yan-Hong Huang[MSFT]

Hi Rob,

I was reviewing the issue thread. Do you have any more concerns on this
issue? If there are any question on Peter's last reply, please feel free to
post here and we will follow up.

Thanks very much.

Best regards,
Yanhong Huang
Microsoft Community Support

Get Secure! ¨C www.microsoft.com/security
Register to Access MSDN Managed Newsgroups!
-http://support.microsoft.com/default.aspx?scid=/servicedesks/msdn/nospam.as
p&SD=msdn

This posting is provided "AS IS" with no warranties, and confers no rights.
 
R

Rob Lorimer

Thanks very much for this...works well!


"Peter Huang" said:
Hi Rob,Alex,

Based on my discussion with a Office Team Senior Engineer, here is the
result.
First off, this is a addin and methods that through exception back to
Office can be caught by Office and therfore not be "unhandled" to start
with. Second, if you are using the COM Shim Wizard to generate security
context for the managed Com Addin, then yes you are in a new (non-default)
appdomain. Third, the documentation talks about WinForm applications, which
I presume to mean host applications where the CLR controls the message loop
and app startup (etc.), not simply a WinForm shown from DLL in an unmanaged
host. I don't think there is a way to set just a filter for managed code. I
think this applied to entire application, which is problematic since Office
has its own filter (for watson reporting and document recovery) which you
don't want to mess with.

Based on my test, we just need to set the filter to the
Application.ThreadException one time even if there are more than one form.
Also according to the document
AppDomain.UnhandledException Event [C#]
This event occurs only for the application domain that is created by the
system when an application is started. If an application creates additional
application domains, specifying a delegate for this event in those
applications domains has no effect.

So the AppDomain.UnhandledException is not available in the Addin. But
even if we throw Exceptoin in the Addin(Except winform), the exception
will not propagate to the OS, and it will be caught by the Office own
filter.

So I think the best practice is to enbrace the "problem" in a try..catch
block everywhere.

Anyway, here I post the C# code per your request.
[Addin]
namespace MyAddin7
{
using System;
using Office = Microsoft.Office.Core;
using Extensibility;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Excel = Microsoft.Office.Interop.Excel;
using System.Diagnostics;
[GuidAttribute("5B4E30C3-0E48-4749-8342-F097935ADB0A"),
ProgId("MyAddin7.Connect")]
public class Connect : Object, Extensibility.IDTExtensibility2
{
public Connect()
{
}
public void OnConnection(object application,
Extensibility.ext_ConnectMode connectMode, object addInInst, ref
System.Array custom)
{
Debug.WriteLine("OnConnection");
exApp = application as Excel.Application;
addInInstance = addInInst;
}
public void OnDisconnection(Extensibility.ext_DisconnectMode
disconnectMode, ref System.Array custom)
{
cbb.Delete(true);
cb.Delete();
}
public void OnAddInsUpdate(ref System.Array custom)
{
}
Office.CommandBar cb=null;
Office.CommandBarButton cbb=null;
Office.CommandBarButton cbbt=null;
public void OnStartupComplete(ref System.Array custom)
{
object oMissing = System.Reflection.Missing.Value;

cb=exApp.CommandBars.Add("Test",Office.MsoBarPosition.msoBarFloating,oMissin
g,oMissing);

cbb =
(Office.CommandBarButton)cb.Controls.Add(Office.MsoControlType.msoControlBut
ton,oMissing,oMissing,oMissing,oMissing);
cbb.Caption = "ShowForm";
cbb.Style = Office.MsoButtonStyle.msoButtonCaption;
cbb.Click+=new
Microsoft.Office.Core._CommandBarButtonEvents_ClickEventHandler(cbb_Click);
}
public void OnBeginShutdown(ref System.Array custom)
{

}

private Excel.Application exApp=null;
private object addInInstance;
private void curAppDomain_UnhandledException(object sender,
UnhandledExceptionEventArgs e)
{
Debug.WriteLine("curAppDomain_UnhandledException: Catch Exception " +
((Exception)e.ExceptionObject).ToString());
}

private void cbb_Click(Microsoft.Office.Core.CommandBarButton Ctrl, ref
bool CancelDefault)
{
Form1 fm = new Form1();
fm.Show();
Form2 fm2 = new Form2();
fm2.Show();
}
}
}


[Form1]
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Diagnostics;
namespace MyAddin7
{
public class Form1 : System.Windows.Forms.Form
{
//.........................................
//.........................................

private void button1_Click(object sender, System.EventArgs e)
{
throw new Exception("My Test Exception from winform");
}

private void Form1_Load(object sender, System.EventArgs e)
{
Application.ThreadException+=new
System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
}

private void Application_ThreadException(object sender,
System.Threading.ThreadExceptionEventArgs e)
{
Debug.WriteLine("Application_ThreadException: Catch Exception:" +
e.Exception.ToString());
}
}
}
[Form2]
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;

namespace MyAddin7
{
//.................................................................
//.................................................................
private void button1_Click(object sender, System.EventArgs e)
{
throw new Exception("From winform 2");
}
}
}

Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.
 
P

Peter Huang [MSFT]

Hi

I am glad that my sugestion helps you.

Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.
 

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