0

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

Community
  • 1
  • 1
obiwanjacobi
  • 2,413
  • 17
  • 27

2 Answers2

1

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.

noseratio
  • 59,932
  • 34
  • 208
  • 486
  • Here is the DllExport attribute that I use to export a managed function. https://sites.google.com/site/robertgiesecke/ It rewrites the assembly with some extra IL-flags for the exported methods. No unmanaged interop/thunking code comes into play. Yes, I am absolutely 100% sure the host does not and will not ever use COM. I understand you cannot change the apartment after the fact - that is why I am looking for a way to tell the CLR what to do... – obiwanjacobi Dec 31 '13 at 09:28
  • @obiwanjacobi, so have you tried calling `CoInitializeEx(NULL, COINIT_MULTITHREADED)` explicitly via p/invoke at the beginning of your entry point? – noseratio Dec 31 '13 at 23:32
0

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.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • As I tried to describe in the post ONLY the interfaces are COM compatible. For the rest its not COM, CoInitialize is not called in the host app! Furthermore there are no (managed) COM components - its just passing interface (pointers) around. Entry point into the Managed plugin is an exported function. When that is called, it's already an STA. I understand it cannot be changed afterwards - so my question is how to change it before hand... – obiwanjacobi Dec 29 '13 at 14:38
  • Hmm, the first sentence ought to leave little doubt. You will have to get in touch with the programmer of the host program and ask him to change his code. He'll treat your request much the same as I treat your downvote, raspberry to you. – Hans Passant Dec 29 '13 at 14:40
  • I am sorry if I have got your feelings hurt, but as your answer stands now - it is not useful nor is the suggestion to contact the original programmer. Thanks for your help. – obiwanjacobi Dec 29 '13 at 14:48
  • 1
    @obiwanjacobi The answer may not be helpful, but it is correct. If you need your code to be called only under certain conditions, then you need to work with your callers to ensure those conditions are met. Since you say that you are not using COM, there is nothing COM can do to help you. – Raymond Chen Dec 29 '13 at 15:33
  • The host is not using COM, but I AM using COM interop for doing interop. It works because the Interfaces are COM compatible. The only thing is that the CLR auto-stamps the (threads) calls into my managed plugin as STA. My question is if that can be altered? So its not a plain vanilla COM-interop scenario. No one calls CoInitialize (excepct perhaps the CLR itself?) and no-one is using CoCreateInstance etc. – obiwanjacobi Dec 29 '13 at 16:17