While researching which COM apartment threading models are supported by Direct2D, I discovered that despite appearances and the fact that one can use the API from .NET using COM interoperability, Direct2D (like other DirectX APIs) is not actually a COM API at all.(1) Both the Wikipedia article on Direct2D(2) as well as a MSDN blog post by Thomas Olsen(3) refer to these APIs using a "lightweight COM" approach.
However, I haven't found any official definition of what exactly this "lightweight COM" is. Is there any such definition (possibly by Microsoft)?
Mike Danes' answer to the MSDN forum question, 'CoInitialize/CoUninitialize, are they really needed for Direct2D and DirectWrite?'. Here's the interesting bit:
"DirectWrite/Direct2D/Direct3D are COM like APIs but they don't use COM. They are not registered in registry like normal COM components, they do not following COM threading models, they don't support any sort of marshaling etc. They're not COM."
Wikipedia article on Direct2D (Overview section):
"Direct2D is a native code API based on C++ that can be called by managed code and uses a "lightweight COM" approach just like Direct3D, with minimal amount of abstraction."
Thomas Olsen's MSDN blog post mentions the following as a design goal of Direct2D:
"Lightweight COM – Should use C++ style interfaces which model Direct3D usage. No support for proxies, cross-process remoting, BSTRs, VARIANTs, COM registration (e.g. the heavyweight stuff)."
You do lightweight COM when you use VTable binding (also used to be called "early binding") + the IUnknown definition. That's about it. You'll never find a definition of that in ancient Microsoft publication, because it never existed with this name.
As an API developer, when you declare you do "lightweight COM" (also called "nano COM"), you basically declare that you don't care about the following:
Many Windows Graphics & Gaming technology use nano/lighweight COM: DirectX, DXGI, Direct2D, DirectWrite, etc.
Note that does not mean you won't have it, in fact, you will have it for free depending on the tooling you use (namely Visual Studio tooling, for example, it's somehow easier to rely on (M)IDL for the abstractions it provides), it's just that you like the idea of having an extensible API (with COM, you can "cast" objects between binary components) without the burden of supporting all these services.
Note also that "lightweight COM" is very very very portable across any platform and any language (call it "open") which is today more interesting.