This is a terrible practice and fundamentally wrong. The important thing is that the value for the second argument is (dwCoInit). It should be COINIT_APARTMENTTHREADED, often shortened to STA or COINIT_MULTITHREADED (MTA). This is the promise you make when you cross your heart, hoping for death. If you break a promise, the program will die. Usually by deadlocks, no expected events, or an unacceptably slow performance.
When you select STA, you promise that the thread behaves well and can support COM components that are not thread safe. Keeping this promise requires that the thread pump the message outline and never lock. The general behavior of a thread that supports a GUI, for example. The vast majority of COM components are not thread safe.
When you choose MTA, you do not promise any support whatsoever. The component must now take care of itself in order to remain thread safe. Often performed automatically when the COM infrastructure creates a thread on its own to provide the component with a secure home. Another detail that you need to take care of is marshaling the interface pointer, it requires the CoMarshalInterThreadInterfaceInStream () helper function, or the more convenient IGlobalInterfaceTable interface. This ensures the creation of a proxy server that will serve the necessary context context of the stream.
MTA sounds comfortable, but not without consequences, a simple getter request can take as much as x10000. The overhead imposed by the thread context switches and the need to copy any arguments and return value to the stack frames. And marshaling the interface pointer can easily fail, authors of COM components often do not provide the necessary proxy / stub, or they deliberately missed it because simply copying data is simply difficult or expensive.
The key point is that the choice between STA and MTA can never be made by a library. He does not know beans about the stream, he did not create this stream. And he canβt know if the thread is working on the pipeline or message blocks. All code that completely exits the library reaches. Otherwise, the exact reason the COM infrastructure needs to know this also cannot make assumptions about the flow.
The choice must be made by the code that created and initialized the thread, invariably the application itself. If the library does not create a thread to ensure call security. But then, when the code is always slow. You remind the caller of your library that he does not get it right, returning the inevitable error code CO_E_NOTINITIALIZED.
Fwiw, this is what you see in the .NET Framework. The CLR always calls CoInitializeEx () before the thread can execute any managed code. There is still a choice that the application programmer should make, or more typically, a project template executed with the [STAThread] attribute on Main () or by calling Thread.SetApartmentState () on the workflow.