How to force MTA on all threads calling from 3rd party unmanaged process into managed plugin?

615 views Asked by At

I am trying to write a managed plugin to an unmanaged host application using COM interop. The unmanaged plugin interfaces are all COM compatible although no COM is used (no registry etc). I have come a long way to get it to work there is just one thing I would like to change.

The calls that are made from the unmanaged host app into the managed plugin assembly are all made on a STA-(managed) thread. I would like it to be MTA so there is no sync/pumping overhead.

I cannot find a way to to achieve this.

Any help or suggestions is most apprecicated.

EDIT: It is NOT a common COM-interop scenario: The host is not COM and no one calls CoInitialize/CoCreateInstance etc. It seems the CLR does assign the apartment to the unmanaged thread that calls into the managed plugin. THAT is what I want to change (it now defaults to STA instead of MTA).

Related questions I have asked may provide more context: Interop COM(-isch) interface marshaling results in AccessViotlationException on simple call Returned managed object method not called from C++ in COM interop

2

There are 2 answers

2
noseratio On

You mentioned there is no COM involved in the host app and the entry point into your managed plugin is an exported function.

How is that exported function implemented? I imagine there is a piece of unmanaged C++ code inside your plugin to bootstrap the managed code. If so, that's where you can do CoInitializeEx(NULL, COINIT_MULTITHREADED), in theory. That is, you should do it before creating any .NET objects from C++ via COM interop.

However, doing so may be very irresponsible and dangerous in respect to the host app. Are you absolutely sure the host doesn't use COM on this thread (and so do not any of its other plugins)? Are you sure it will not try to initialize COM at some later stage?

Also, if the host has already initialized COM on this thread as STA, your call to CoInitializeEx will most likely fail with RPC_E_CHANGED_MODE error.

5
Hans Passant On

You have no say in the matter, it is the unmanaged host app that created the thread(s) and called CoInitializeEx(), selecting the apartment type. It cannot be changed afterwards.

This cannot be much of an issue since you suggest you support free threading if you are okay with calls from the MTA. And the default ThreadingModel for .NET ComVisible classes is Both. So no marshaling occurs when the host calls you from its STA thread, it using the wrong STA thread would be very unusual.

It only matters when you make callbacks into the unmanaged host, events being the most common case. You can use threading in your own code but you must honor the contract demanded by the host. Any callbacks you make must execute on the thread on which your class was created. Simple to do with Control.BeginInvoke(), the host promised support it since it selected STA. Compare to the WebBrowser.DocumentCompleted event for example.