InnerException > BackgroundWorker > MyApplication.UnhandledExcepti

G

Guest

I'm trying to understand why the MyApplication.UnhandledException event
handler behaves differently when the exception originates from the background
thread of a BackgroundWorker component.

e.g.

The event handler displays the message from the exception and from the inner
exception:

Partial Friend Class MyApplication
Private Sub MyApplication_UnhandledException(ByVal sender As Object, ByVal
e As Microsoft.VisualBasic.ApplicationServices.UnhandledExceptionEventArgs)
Handles Me.UnhandledException
If e.Exception.InnerException Is Nothing Then
MsgBox(e.Exception.Message & " Nothing")
Else
MsgBox(e.Exception.Message & " " & e.Exception.InnerException.Message)
End If
e.ExitApplication = False
End Sub
End Class

The following code behaves as expected, the event handler displaying “Blah
Fooâ€.

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
Try
Throw New Exception("Foo")
Catch ex As Exception
Throw New Exception("Blah", ex)
End Try
End Sub

But the following code behaves unexpectedly, the event handler displaying
“Foo Nothingâ€, which, I guess, comes as a result of the base exception being
passed to the event handler.

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button2.Click
Me.BackgroundWorker1.RunWorkerAsync()
End Sub

Private Sub BackgroundWorker1_DoWork(ByVal sender As Object, ByVal e As
System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Try
Throw New Exception("Foo")
Catch ex As Exception
Throw New Exception("Blah", ex)
End Try
End Sub

Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As Object,
ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles
BackgroundWorker1.RunWorkerCompleted
Throw e.Error
End Sub

I’d appreciate an explanation as to why and also an indication as to how I
can get the complete exception tree.
 
J

Jeffrey Tan[MSFT]

Hi Dick,

Yes, I can reproduce the problem with the code snippet you provided. Below
is my detailed analysis process for this problem, for your information:

VB2005 MyApplication.UnhandledException internally leverages
Application.ThreadException to implement the magic, I have proved this in
the link below:
http://groups.google.com/group/microsoft.public.dotnet.framework.windowsform
s/msg/5422486e68eddae7?hl=zh-CN&

So I tried to disable "Application Framework" in my testing VB2005 project
and used Application.ThreadException directly to handle this exceptoin,
like this:
Public Class Form1
<STAThread()> _
Shared Sub Main()
AddHandler Application.ThreadException, AddressOf OnThreadException
Application.Run(New Form1())
End Sub

Public Shared Sub OnThreadException(ByVal sender As Object, ByVal t As
ThreadExceptionEventArgs)
If t.Exception.InnerException Is Nothing Then
MsgBox(t.Exception.Message & " Nothing")
Else
MsgBox(t.Exception.Message & " " &
t.Exception.InnerException.Message)
End If
End Sub
....
End Class

Oh, I find the problem still exist, Application.ThreadException will also
only report the inner-most exception "Foo".

However, if we catch the exception in BackgroundWorker1_RunWorkerCompleted
with code snippet below, we will get the 2 exceptions without any problem:
Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As
System.Object, ByVal e As
System.ComponentModel.RunWorkerCompletedEventArgs) Handles
BackgroundWorker1.RunWorkerCompleted
Try
Throw e.Error
Catch ex As Exception
If ex.InnerException Is Nothing Then
MsgBox(ex.Message & " Nothing")
Else
MsgBox(ex.Message & " " & ex.InnerException.Message)
End If
End Try
End Sub

This reveals that there is some magic happen during the unwinding of the
stack for exception.

By comparing the call stack of BackgroundWorker1_RunWorkerCompleted()
method and OnThreadException() method, I find that the exception handling
unwinding stops at "System.Windows.Forms.Control.InvokeMarshaledCallbacks"
internal method.

Then I launched Reflector to examine
"System.Windows.Forms.Control.InvokeMarshaledCallbacks" source code. My
eyes stop on the following code snippet:

Private Sub InvokeMarshaledCallbacks()
.....
Try
If (NativeWindow.WndProcShouldBeDebuggable AndAlso Not
entry1.synchronous) Then
Me.InvokeMarshaledCallback(entry1)
Else
Try
Me.InvokeMarshaledCallback(entry1)
Catch exception1 As Exception
entry1.exception = exception1.GetBaseException
End Try
End If
Finally
entry1.Complete
If ((Not NativeWindow.WndProcShouldBeDebuggable AndAlso
(Not entry1.exception Is Nothing)) AndAlso Not entry1.synchronous) Then
Application.OnThreadException(entry1.exception)
End If
End Try
.....
End Sub

Yes, InvokeMarshaledCallbacks() method catches the exception we throw and
then calls "exception1.GetBaseException" method to get the inner-most
exception object and pass it to the Application.OnThreadException() method.
We finally find the root cause now!

Then I want to understand why Winform InvokeMarshaledCallbacks() method
will translate the exception into inner-most exception(Foo) for
Application.OnThreadException() method. I performed some search in our
internal database with one existing record regarding our problem.

Based on the winform comfirmation in the record, our analysis is correct of
the root cause and this behavior is intended. The reason was to prevent the
user from seeing too much of the Windows.Forms internal mechanisms. This is
because the winform's default error dialog also leverages
Application.ThreadException to show the exception details. .Net Winform
team trims the other exceptions information so that the default error
dialog will not display all the details to the end user.

Also, some MSFTs have sugguested to change this behavior. However, .Net
Winform team thinks that changing the exception to throw is a breaking
change and for this reason WinForms will keep sending the innermost
exception to the Application.ThreadException handler.

Hope this helps.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
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