I have moved!

I've moved my blog

Thursday, 17 January 2008

COM/CLR interop and threading

Say you've written a big complicated application in C++, composed of a large number of COM objects that chat to each other through custom interfaces declared in IDL.

After a decade or so of this, you're not getting any younger and you don't want to spend another decade looking at such ugly code. Or maybe you want to open up your product for extension by third parties but you want them to be able to use "modern" (.NET) languages. Either way, the interop support of the CLR is just what you need.

However, when you start reading about it, a question might occur to you. Well, it ought to, even if it doesn't. How does garbage collection interact with COM reference counting?

The short answer seems to satisfy most people: COM pointers are wrapped in a Runtime Callable Wrapper (RCW) which has a finalizer that calls Release on the pointer. This answer scared the bejesus out of me, because of the way finalizers work. They are executed on a dedicated thread, separate from the thread where you allocated your COM objects. This suggests that you would need to make AddRef and Release threadsafe - not a very practical notion in most cases.

There is a straightforward complete answer to this, but I seem to remember it was quite hard to track down. In the CLR, every thread must be in one of a number of modes, which control how it treats COM objects. As long as your thread is in STA (single threaded apartment) mode, any RCWs created in your thread will finalize themselves by posting a message to a hidden window on the thread that created them. The hidden window receives the message and calls Release. That way, no unpleasant calls to your COM objects from foreign threads are ever necessary.

The one thing you must ensure is that your thread pumps messages "frequently". Otherwise it will not succeed in clearing up abandoned COM objects.