0

I'm running a long task in a BackgroundWorker, updating the UI via ReportProgress. However, in the middle of the process, I need to make a COM-call to get some data, and I think I need to do it on the UI thread. I tried doing this via Control.Invoke. However, I'm getting a deadlock. Can't one use Control.Invoke in a BackgroundWorker (with ShowDialog)?

I've tried to simplify the code:

        var log = new LogWindowForm();
        worker.DoWork += (sender, args) =>
        {
                creator.LogProgress = (s, i) => worker.ReportProgress(i,s);
                creator.GetMoreDataFunc = (s) => InvokeGetMoreDataOnGuiThread(log, s);
                ...
                var data = GetMoreDataFunc("id:"+id)
        };
        worker.RunWorkerAsync();
        log.ShowDialog();


    private Dictionary<string, string> InvokeGetMoreDataOnGuiThread(Control invokeControl, string id)
    {
        var data = new Dictionary<string, string>();
        Action action = () => data = GetMoreDataFromComObject(mainComObject, id);
        invokeControl.Invoke(action); // deadlock!
        return data;
    }

Edit:

There are no exceptions, the UI keeps updating but it stops progressing. Break All shows the worker thread in the Control.Invoke call and the GUI thread somewhere in the ShowDialog call.

The GUI thread seems to be in the message loop:

System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoop(int reason, System.Windows.Forms.ApplicationContext context) + 0x65 bytes

I guess that's why the UI keeps updating. Is there some locking inside the BackgroundWorker?

johv
  • 4,424
  • 3
  • 26
  • 42
  • What do you mean by deadlock? What happens? Any exceptions? – Emond Jan 23 '13 at 09:23
  • What do you do in `GetMoreDataFromComObject()`? – Moriya Jan 23 '13 at 09:25
  • @Animal I do some calls on a com object, nothing to do with the GUI directly. It's a plugin in a larger application. – johv Jan 23 '13 at 09:26
  • @Erno No exceptions, the UI keeps updating but it stops progressing. Break All shows the worker thread in the Control.Invoke call and the GUI thread somewhere in the ShowDialog call. – johv Jan 23 '13 at 09:27
  • Have you tried `BeginInvoke` instead of `Invoke`? – Daniel Kelley Jan 23 '13 at 09:30
  • 1
    @johv, Why do you need to run `GetMoreDataFromComObject()` on the GUI thread if it's just calling COM objects? – Moriya Jan 23 '13 at 09:32
  • @Animal Then I got something like "Context 0x3c71a38 is disconnected. No proxy will be used to service the request on the COM component" – johv Jan 23 '13 at 09:34
  • @johv, ok. Did you try to change the invoke to BeginInvoke? – Moriya Jan 23 '13 at 09:38
  • I do need the data synchronously. Do you mean something like invokeControl.EndInvoke(invokeControl.BeginInvoke(action)) ? – johv Jan 23 '13 at 09:40

1 Answers1

0

A guess, because I don't know what the COM object does or requires:

The reason for the COM Object requiring the UI htread might be because (in most cases) the UI thread is marked as an STA thread.

If the COM Object requires a Single Threaded Appartment you could use a non-UI thread which is marked as an STA thread. That way you are no longer claiming the UI thread.

See: Could you explain STA and MTA?

and: an explanation of STA in .NET

and How to make a .NET thread STA or MTA or by using an attribute

Community
  • 1
  • 1
Emond
  • 50,210
  • 11
  • 84
  • 115