2
votes

This thread is great at explaining STA vs MTA for COM, however it doesn't address how to code for such or when to use one or the other, and only just discusses technicalities about COM apartments being used by thread-safe objects or not. I'd be willing to bet most users just want to know how to use the Win API through COM without any COM objects shared among multiple threads.

Should you use STA always if your COM objects aren't shared among threads, and your code makes use of multiple threads or a single thread each with its own COM object instances, none of the objects shared? Does it depend on the object you are using? If you don't always use STA for such when do you use MTA? Do you ever need a message pump in this case?

In my case I use the Task Scheduler API (ITaskService) and the Shell Links/Create Shortcut API (IShellLink) from the main GUI thread (using the Qt Framework), and the File Operation API (IFileOperation) and the Volume Shadow Copy Service API from a worker thread.

I call CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); from each thread before initializing and using the COM objects and CoUninitialize(); after. Is this proper usage of COM? Would the same apply using COM objects from the main GUI thread without a worker thread?

1
In an ideal world, as a thread owner, you shouldn't care (put aside possible performance issues for cross apartment calls) if the COM servers you use are STA or MTA. That's basically the whole point of all this COM threading stuff, it's supposed to be a feature not a burden... Unfortunately, most shell object (and others...) just don't provide the necessary objects (tlb, proxies, etc.) to marshal calls between apartments (exact reasons are still obscure to me, beyond compatibility issues for Microsoft...). So you must care... For these objects, shared or not, you must create an STA thread.Simon Mourier
Selecting STA is a promise, cross your heart hope to die. Never block and pump a message loop, you know when you are going to do that. You want the okay to lie about it and hope to die when the lie turns out to cause trouble. That usually turns out okay, your program will deadlock or an event you expect to get raised doesn't trigger. No guarantee, and not easy to diagnose, it is the way they quickly get you off the phone when you call Microsoft Support. Or SO. If you are going to lie about shell interfaces then you also need to test on Win7.Hans Passant
@Simon So is it safe to always use STA?riverofwind
If you're using Shell object, it's probably the safest way. But nothing's ever guaranteed.Simon Mourier

1 Answers

1
votes

For making outbound COM calls to objects that you instantiated via CoCreateInstance, STA should be good enough, and is almost a must for your GUI thread (the one that has a GetMessage/DispatchMessage loop).

MTA starts to become relevant when hosting your own thread safe COM objects that are expected to be invoked from other processes.

The documentation for IFileOperation states this:

IFileOperation can only be applied in a single-threaded apartment (STA) situation. It cannot be used for a multithreaded apartment (MTA) situation. For MTA, you still must use SHFileOperation.

See all, this link: INFO: Calling Shell Functions and Interfaces from a Multithreaded Apartment

I suspect what the documentation is really trying to say is this:

  1. The class implementing IFileOperation is not thread safe
  2. It's ThreadingModel is declared "apartment" in the registry and will incur marhsalling overhead if accessed from an MTA thread.

On our application, have used ITaskScheduler on the main STA thread. And we use IFileOperation on a background STA thread that has its own message pump.

Some other links that I think are very useful:

https://support.microsoft.com/en-us/help/150777/info-descriptions-and-workings-of-ole-threading-models

https://devblogs.microsoft.com/oldnewthing/?p=22603