While developing tests, a developer observed erratic behavior with respect to Co­Create­Instance:

In my test, I call Co­Create­Instance and it fails with CO_E_NOT­INITIALIZED. Fair enough, because my test forgot to call Co­Initialize.

But then I went and checked the production code: In response to a client request, the production code creates a brand new thread to service the request. The brand new thread does not call Co­Initialize, yet its call to Co­Create­Instance succeeds. How is that possible? I would expect the production code to also get a CO_E_NOT­INITIALIZED error.

I was able to debug this psychically, but only because I knew about the implicit MTA.

The implicit MTA is not something I can find very much documentation on, except in the documentation for the APP­TYPE­QUALIFIER enumeration, where it mentions:

[The APT­TYPE­QUALIFIER_IMPLICIT_MTA] qualifier is only valid when the pAptType parameter of the Co­Get­Apartment­Type function specifies APT­TYPE_MTA on return. A thread has an implicit MTA apartment type if it does not initialize the COM apartment itself, and if another thread has already initialized the MTA in the process. This qualifier informs the API caller that the MTA of the thread is implicitly inherited from other threads and is not initialized directly.

Did you get that? If any thread in the process calls Co­Initialize­[Ex] with the COINIT_MULTI­THREADED flag, then that not only initializes the current thread as a member of the multi-threaded apartment, but it also says, "Any thread which has never called Co­Initialize­[Ex] is also part of the multi-threaded apartment."

Further investigation revealed that yes, some other thread in the process called Co­Initialize­Ex(0, COINIT_MULTI­THREADED), which means that the thread which forgot to call Co­Initialize was implicitly (and probably unwittingly) placed in the MTA.

The danger of this implicit MTA, of course, is that since you didn't know you were getting it, you also don't know if you're going to lose it. If that other thread which called Co­Initialize­Ex(0, COINIT_MULTI­THREADED) finally gets around to calling Co­Un­initialize, then it will tear down the MTA, and your thread will have the MTA rug ripped out from under it.

Moral of the story: If you want the MTA, make sure you ask for it explicitly. And if you forget, you may end up in the implicit MTA, whether you wanted it or not. (Therefore, conversely, if you don't want the MTA, make sure to deny it explicitly!)

Exercise: Use your psychic debugging skills to diagnose the following problem. "When my code calls Get­Open­File­Name, it behaves erratically. I saw a Knowledge Base article that says that this can happen if I initialize my thread in the multi-threaded apartment, but my thread does not do that."