Handling CoInitialize (and CoUninitialize!)

I'm covering this topic because I've seen a couple of drivers now that are calling CoUninitialize a few too many times and causing subsequent app failures, but the topic is probably useful for anyone doing anything related to COM.

CoInitialize initializes COM on a per-thread basis.  That is, for each thread on which you want to use COM objects, you need to call CoInitialize.  CoInitialize also reference counts.  Each time it succeeds, it needs to have a corresponding CoUninitialize called.  The key word there is succeeds, and this is where I see the errors.  CoInitializeEx allows you to specify the mode that you want, but if COM is already initialized, you can't change modes.  So this code:


... causes one too many CoUninitialize calls to occur, because the second CoInitializeEx returns RPC_E_CHANGED_MODE, and does not increment the thread's COM reference count.  If you're at the top of the application, that might go un-noticed, since the second CoUninitialize will silently fail.  However, if you're a component running deep within an application, you may have just caused COM to shut-down on the thread while the caller is still holding COM objects.

The way to fix this is to check the return value on CoInitialize / CoInitializeEx, and make sure it succeeded before calling CoUninitialize.  RPC_E_CHANGED_MODE is a failure code that means COM is already initialized in another mode.  Depending on your application, that may be a failure that you can, for the most part, ignore if you don't really require one mode or the other.  However, if you ignore the RPC_E_CHANGED_MODE, you still need to make certain that you don't call the CoUninitialize that pairs with that call.

If you're writing exception based code, you need to either use a catch() clause, or use an object whose constructor calls CoInitialize(Ex) and, whose destructor calls CoUninitialize if needed.


Oh, and Zune is coming, and looking very, very good.