views:

53

answers:

4

When an exception happens after calling Invoke, .NET shows the stack trace as if the error happens while calling Invoke.

Example below: .NET will say the error happen in UpdateStuff instead of UpdateStuff -> BadFunction

Is there a way to catch the "real" exception and show the correct stack trace?

Private Sub UpdateStuff()

    If (Me.InvokeRequired) Then
        Me.Invoke(New UpdateStuffDelegate(AddressOf UpdateStuff))
        Return
    End If

    Badfunction()

End Sub

Private Sub BadFunction()

    Dim o As Object

    o.ToString()

End Sub
+3  A: 

Check the InnerException property of the exception.

Steven Sudit
+1 Yes that's a good one.
ChrisBD
The InnerException is set to nothing
the_lotus
No, that's not a good one.
Hans Passant
It looks like my answer, while being reasonably good advice in general, does not apply here.
Steven Sudit
+1  A: 

try ... catch block perhaps.

ChrisBD
I tought of that, I might need to store the Exception somewhere and fetch it later.
the_lotus
+1  A: 

If you look at the TargetSite on the exception itself, it will give you the name of the function that was dynamically invoked (or it gets the method that threw the current exception):
Name "BadFunction" String

The exception contains the actual exception that you have from the invocation: System.NullReferenceException {"Object reference not set to an instance of an object."} System.Exception

Here is my stack trace: at WindowsApplication1.Form1.BadFunction() in C:\Development\Test\WindowsApplication1\WindowsApplication1\Form1.vb:line 35 at WindowsApplication1.Form1.UpdateStuff() in C:\Development\Test\WindowsApplication1\WindowsApplication1\Form1.vb:line 22

chrisghardwick
Are you sure TargetSite is correct? As far as I can tell, it only reveals the name of the method being called.
Steven Sudit
TargetSite gives MarshaledInvoke, not BadFunction. Maybe InvokeRequired was false when you tried the sample.
the_lotus
+1  A: 

Yes, this is less than perfect. The exception is caught and re-thrown in the thread that called Invoke(). Necessarily, it is missing the stack frames of the code in the UI thread, they are already unwound by the time the exception is re-thrown. That it doesn't use the InnerException property is not great.

One workaround is to catch the exception in the invoked method and store it in a private field. A better one is to use BeginInvoke instead of Invoke. That will raise the exception in the UI thread directly.

Hans Passant
Thanks! I remember you from the msdn forum way back.
the_lotus
Yup, that was me.
Hans Passant