Ask Learn
Preview
Ask Learn is an AI assistant that can answer questions, clarify concepts, and define terms using trusted Microsoft documentation.
Please sign in to use Ask Learn.
Sign inThis browser is no longer supported.
Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.
Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
When a Dll’s executing code on an application’s behalf, the Dll can NEVER call CoInitalizeEx on the application’s thread.
Why? Because you can’t know the application’s threading model, so you can’t get it right. If the app’s initialized COM in a single-threaded apartment and you attempt to put the thread into the multi-threaded apartment, the CoInitializeEx call will fail. Similarly, if the app’s called CoInitializeEx put the thread in the MTA, you can’t reinitialize in the STA. You could add code to allow the RPC_E_CHANGED_MODE error return that CoInitializeEx returns, but there are sometimes COM objects that require a particular threading model.
This is especially true if your DLL allocates some object that contains pointers to other COM objects and returns a pointer to that object. A good example of an API that uses this pattern is CryptAcquireContext – I’m not saying that it uses COM, it probably doesn’t, but it COULD.
An API written using the XxxAcquireContext/XxxReleaseContext design pattern could be tempted to call CoInitializeEx() in the XxxAcquireContext routine and call CoUnitialize in the XxxReleaseContext routine. And that would be utterly wrong. The problem is that in this case, if you initialized COM in the MTA during the XxxAcquireContext routine, and then the application attempted to create an STA for the thread, the app’s call will fail. And the app is entirely likely to be quite unhappy with its call to CoInitialize failing.
Even if the application ignored the error, then the application would potentially get callbacks on other threads, which is likely to break the application. So you say “Ok, I can deal with this, I’ll just initialize myself in an STA. But then if the app attempted to put the thread in the MTA, you’ve once again messed up the application.
You just can’t win.
In addition, this rule has some interesting corollaries: You either need to rely on the application to call CoInitialize for you, and add this to your documentation, or you need to do all your COM interactions on a separate worker thread. If you’re dealing with a legacy component however, you have no choice but to move your COM interactions to a separate worker thread. I first ran into this issue when I made some modifications to winmm.dll to add support that required interacting with a COM component. The good news is that it’s pretty easy to set up a worker thread to do the work – just create the thread and use PostQueuedCompletionStatus to post work items to the queue.
Ask Learn is an AI assistant that can answer questions, clarify concepts, and define terms using trusted Microsoft documentation.
Please sign in to use Ask Learn.
Sign in