Reputation: 385194
I have an event handler that runs in a socket-handling thread, which uses Invoke
to update UI state.
I have a runaway FormatException
somewhere further up the call stack and I'm trying to catch it to analyse it, but I'm finding that I cannot get the debugger to break in the UI thread — the exception seems to be bubbling up to the invoking thread no matter what I do.
Private Delegate Sub newDataDelegate(ByVal data As String)
Private Sub onNewData(ByVal data As String) Handles _server.clientHasData
If Me.InvokeRequired Then
Me.Invoke(New newDataDelegate(AddressOf onNewData), data)
Exit Sub
End If
Try
updateGuiWith(data)
Catch ex As FormatException
System.Diagnostics.Debugger.Break()
End Try
End Sub
The stack trace:
at System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous) at System.Windows.Forms.Control.Invoke(Delegate method, Object[] args) at <X>.MainForm.onNewData(String data) in <X>.vb:line 377 at <X>.Server.onProbeData(String data) in <X>:line 104
(<X>
= redacted)
The result is that the debugger breaks lower down the call stack (in code that called onNewData
in the socket thread) and the stack trace ends at the invoke site. I cannot find out what's causing the exception. (Worse, the call works most of the time for the same argument, so it's not one I can predict and hunt down without the debugger's help.)
Before I go any further extracting an isolated testcase, is this expected behaviour for exceptions raised behind delegate-driven invocations?
Upvotes: 2
Views: 832
Reputation: 385194
Replacing Catch ex As FormatException
with Catch ex As Exception
gave me the invoked-thread break I was looking for, and the actual exception in question turns out to be an InvalidCastException
. The inner-exception is the FormatException
, which is why it wasn't being caught.
My understanding of exceptions in .NET is still fairly rudimentary (being a C++ developer first and foremost), so this concept of varying levels of exception wrappers is rather alien. But, ultimately, this mechanism is as Hans explained in his answer.
Long-term, switching to BeginInvoke
will, it seems, avoid this headache altogether. For now, though, I have my stack trace and I can solve the actual problem.
The answer to the question can exceptions be handled behind a delegate-driven "Control.Invoke" call? is yes.
Upvotes: 0
Reputation: 941585
is this expected behaviour for exceptions raised behind delegate-driven invocations?
No, and that's because you don't actually use the delegate's Begin/Invoke() methods. You are using Control.Invoke(), a method of the Control class that merely takes a delegate as an argument. It behaves very differently from a delegate's Begin/Invoke methods, the naming choice was a bit unfortunate. Major differences are:
Yes, this can make it quite hard to figure out how you got from point A to B when you look at the stack trace. Very unfortunate behavior, the design choice isn't obvious. There is no simple workaround for it beyond having the exception caught and handled in the invoked code.
Or to favor BeginInvoke, in general the method you want to use because you don't want your thread to be bogged down by UI update delays. The exception will be raised on the UI thread with full stack trace diagnostics.
Upvotes: 1
Reputation: 4330
From reading this,
http://charlieflowers.wordpress.com/2005/04/26/controlinvoke-and-exception-propogation-short-form/
I'm going to say yes that this is meant to bubble up the exception. If I understand the article correctly, the exception gets swallowed and the exception information returned to the Invoke function where it is re-thrown. However, if you use BeginInvoke
to do an asynchronous call, the exception will not be bubbled up through the BeginInvoke
call.
I haven't used VS Express, but normally under Debug>Exceptions, check the 'Thrown' box next to 'Common Language Runtime Exceptions'. Then the debugger should stop where ever the first exception happens.
Although this probably isn't the case, you can check your code for attributes like System.Diagnostics.DebuggerStepThrough
which might cause the debugger to skip the code that throws the exception.
Upvotes: 0