I want to run an operation on a background thread. When it has completed I want to check for any errors that occurred and re-throw them on my original thread.
I am using a backgroundworker. Throwing an exception in the RunWorkerCompleted event handler results in an unhandled exception – this makes sense if the eventhandler is running on the background thread. If I had a winform control I could call Invoke or BeginInvoke but I do not have a winform control in this object, although it is a winform project.
How can I re-throw an exception that occurred in the backgroundworker?
private void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
// I want to throw an exception here, without causing an unhandled exception and without being able to call Invoke or BeginInvoke on a WinForm control.
}
else if (e.Cancelled)
{
// Do something useful
}
else
{
if (e.Result != null)
{
// Do something with the result
}
}
}
I would have assumed that the RunWorkerCompleted event handler would be running on the original calling thread. Perhaps the backgroundworker is not what I need in this case.
It’s not possible to inject code into another running thread. Not even the operating system can do this.
Control.BeginInvoke works by putting the delegate reference in a queue and then using PostMessage to post a user-message into the UI thread’s message queue. The Application.Run message loop looks for this message and when it finds it pops the delegate off the queue and executes it.
The point is that there is no other way to do what you need without your main thread being coded to look for a some kind of signal (or message) from the other thread.
Added
You stated that this is a WinForm application but you do not have a Control to use BeginInvoke with.
Edit: I suggested a lazy-load without thinking it through. The Control might end up getting created on the wrong thread.
Pre-create a Control prior to
Application.Runthat lives for the lifetime of the app. You can use this to BeginInvoke from.Edit #3
So then I try this to make certain it works and of course it doesn’t. You can’t simply create a generic Control, it must have an HWND handle. Simple fix: create it like this:
That will allow you to BeginInvoke from it, even if there are no open Form objects to invoke from.