views:

184

answers:

1

I have a C# application which uses a COM component. This COM component require a message pump (Application.Run()) to do its processing. This means it's been stuck on the main thread. But I recently discovered that it's possible to start another Application.Run on another thread which gets its own ApplicationContext.

So I want to host the COM component on its own thread inside it's own Application.Run(), but I can't figure out how to get things started on the new thread without creating a UI form.

The WindowsFormsSynchronizationContext I need to communicate with the thread doesn't get created until Application.Run(). But once Application.Run() is called, I can't figure out how to get at the SynchronizationContext. If I could just raise a single event on that thread, I could use that to bootstrap the whole thing (create the COM object, etc.), but there doesn't seem to be anywhere to hook into the new event loop without a form.

I've tried all kinds of convoluted things, like installing a message filter (no messages get raised on the new thread), copying the execution context into another thread and trying to retrieve the SynchronizationContext from there (it refuses to copy the ExecutionContext of an already running thread), retrieving Thread.CurrentContext before starting Application.Run() and then calling DoCallbBack() (the DoCallback ends up on the original thread), etc. Nothing I've tried works.

+2  A: 

Bryce,

You might be able to adapt this snippet from Anders Hejlsberg's talk about "The Future of C#". It's a little class that adds a message pump to a thread so that he can open windows using a REPL loop, and they will have a message pump attached to them.

The code looks like this:

using System.Windows.Forms;
using System.Threading;
class UserInterfaceThread()
{
    static Form window;

    public UserInterfaceThread() 
    {
        var thread = new Thread(() => {
            window = new Form();
            var handle = window.Handle;
            Application.Run();
            });
        thread.Start();
    }
    public void Run(Action action)
    {
        window.Invoke(action);
    }
}

The discussion relating to this code occurs at 1 hour 5 minutes into Anders' talk, if you want to review it.

Robert Harvey
So it turns out that creating a Window handle is what instantiates the SynchronizationContext and not the Application.Run(). So simply calling "IntPtr handle = new Form().Handle;" creates the required WindowsFormsSynchronizationContext before calling Application.Run(). Thanks much.
Bryce Wagner