69 comments

[ 3.4 ms ] story [ 139 ms ] thread
Seems crazy to me to use WIL instead of ATL as your C++ COM wrapper.
WIL seems to be in more or less active development, according to its GitHub page. ATL doesn't seem to have much done to it in the last decade or so.

https://github.com/microsoft/wil

COM isn't changing. The entire point (the only point, actually) is interop.

So why is your language-specific wrapper changing? Well, for continued language support... but that does appear to be happening with ATL.

Call me skeptical, but we now have... let's see... four COM C++ API's to choose from, just considering the ones affiliated with MS. (If someone offered me an even bet there weren't more without looking it up, I'd take that bet).

Maybe, since the entire point is interop, we should settle on one at some point??

(1) raw C API IUnknown/BSTR/VARIANT/etc; (2) CComPtr/CComBSTR/CComVariant/etc; (3) _com_ptr_t/_bstr_t/_variant_t/etc; (4) WIL's baby COM API

You forgot C++/CX, WRL and C++/WinRT on your list.

Yep it is that bad.

The problem with ATL is that it is stuck in the Visual C++ 6.0 tooling experience.

The alternatives aren't much better though, although WIL seems to be the less painful to use, if we ignore all that UWP stuff.

WRL is by far the best of the bunch. Instead of

WE_ARE_THE_ATL(MACRO_POINTER$(##PLEASEREGISTER ^& CLASS))

you have

class ListenerCallback : public RuntimeClass<RuntimeClassFlags<ClassicCom>, IWhateverListenerInterface

[...]

CoCreatableClass(ListenerCallback);

I would be so happy if they ditched IDL, or at very least improved its development experience, specially with the excuse to wait for C++ reflection to give back the experience of using C++/CX with C++/WinRT, means I will probably retire before they even bother to start.
My preference is never to use _com_ptr_t et al. (instead CComPtr for a nicer RAII) since they throw exceptions, and almost none of the developers I worked with expected that, so lots of unhandled exceptions at runtime was the result.

One of the best things about the COM (previously OLE) API was actually HRESULTS, so I always encouraged their use, and IErrorInfo wherever possible.

I read about "Software ICs" in Byte Magazine in the 80's. I later thought COM was a decent try. The implementation and tooling around it was always problematic. People do buy software components off the shelf now, like special graphing controls in Excel for example, so it continues to be a useful paradigm. The Software IC concept got coopted by OOP, which isn't the way I first understood it.

Graham Lee blog post about Brad Cox's Object-Oriented Programming:

In 1714, Gottfried Leibniz published La Monadologie, in which he proposed that at the fundamental level, objects are made of indivisible entities called Monads. You can’t see inside a monad, it has an internal state that controls its actions and passions. Monads can be created or destroyed atomically, but cannot be partially built or partially annihilated because they are a “simple substance without parts”.

Cox, on the other hand, opens with the story of Eli Whitney and the industrial revolution. For Cox, the industrial revolution is not primarily about machinery and the harnessing of steam and coal power. It’s about the replacement of artisanal, cottage manufacture with scaled-up industrial processes that depend on well-specified interfaces between standardized, interchangeable parts.

https://web.archive.org/web/20191220204822/https://deprogram...

https://news.ycombinator.com/item?id=21833331

Thanks for writing about these. That "Software ICs" article has been a strong source of inspiration. It's maybe worth noting that Brad Cox was the inventor of Objective-C (which was seen as a way to allow the creation of software ICs, and was inspired also by Smalltalk).
Do people still code like this?
Yes, Windows is mostly COM nowadays, when it isn't .NET.

Then you have XPC on Apple platforms, Android IPC and Fuschia IDL on Google's, D-BUS on GNU/Linux, and the new cloud fashion gRPC.

What is fun is that so many people say "but COM is outdated"... when I look around in Windows it is everywhere. :)
Mostly because they didn't got the memo and think .NET replaced COM.

Which was kind of the original idea, but then with Longhorn WinDev wasn't happy with how things were going, so instead of doing like Google with Android, pushing the new stack no matter what, they worked against it.

So when the reboot that would become Vista started, all Longhorn ideas got redone as COM instead of .NET.

And since then all major APIs are COM based, eventually with .NET bindings as well.

COM is (IMHO) one of the great underrated technologies. Registering all the classes, interfaces etc. in the registry - not so much. But IDL's, versioned interfaces etc. etc. are all reinvented every five years or so. And it's fast as hell.

DCOM was awful.

Wasn't that awful ;) In some sense it's maybe a precursor to gRPC. DCOM let us (EDIT: us being some old project/team I worked on) take a component and make it distributed with very little work (COM -> DCOM) almost seamlessly.
Interesting, I was obviously doing something very wrong (back in the day).
It's been many years for me, but I remember it having nice interop with .NET as well. Back then I worked with several APIs that were just COM objects brought into .NET.
I worked on a project around the early 2000s that had a mixture of DCOM and Corba in it. Relatively speaking, DCOM was a dream. It reminded me a lot of the original RPC generated stubs on Solaris.

Corba reminded me that some people should never write network code: sometimes the interface would start, sometimes it wouldn't (this system was a consumer of something the Corba system was generating). The Corba guys had an elaborate startup procedure that resembled praying to the gods of Java that it would work this time, Bullwinkle pulling a rabbit out of a hat style. The DCOM stuff just worked / was able to reconnect when something failed.

Corba was possibly the worst tech I have ever had the displeasure of using and while I don't remember DCOM especially fondly, it wasn't terrible.

Corba was a spec that had a number of implementations. Some Orbs were great while others were crap. Unlike DCOM however it was an open standard. For some reason at some point it was declared highly uncool. And now is being reinvented hard yet again by the hipsters of today with grpc etc. Looks like every generation of programmers has the urge to reinvent RPC.
I wish I could remember which implementation of Corba it was, an Irish company I think...hello Google it was Iona and "Orbix". Dreadful thing.
I like COM as concept, what is awful beyond explanation is why it being so central to WinDev, it keeps having pre-historic support on Visual Studio.

IDL files still lack code completion and syntax highlighting, 25 years later, and they cannot settle on any kind of framework that makes it easier to use.

From .NET side there are still gotchas to this day, and from C++ side it seems we cannot just have nice tools.

Now as a concept it is quite cool, execution could be so much better.

I’d guess very little people are touching COM directly and more commonly using whatever various abstractions MS built on top.
The only abstractiosn that exist are .NET libraries, when they don't exist, then COM is all that there is, nothing else.
Oddly enough if you used COM in VB6 it had autocomplete and tight integration with it. Building the objects in c++ was a nightmare, but it did work for great reusable components.
From Microsoft history of programming languages, VB 6 was definitly the best COM experience so far, for a little while .NET Native and C++/CX got it back, but they are now deprecated.
> But IDL's, versioned interfaces etc. etc. are all reinvented every five years or so.

And it's happening again right now, albeit for a better reason than normal. The WebAssembly Component Model (currently in development) draws heavily on lessons from all these generations of reinvention, and especially from COM itself.

> Registering all the classes, interfaces etc. in the registry - not so much

The core idea behind COM is to allow programs expose objects that implement various interfaces in a way that would allow these objects be both implemented and used by different languages and applications without each one knowing about the other aside from the common ABI that is COM.

So with that in mind, how would an image viewer application know about the implementations of the image fileformat-agnostic IImageReader interface (that could also be used by, e.g. an offline 3D renderer, a presentation editor, a game engine texture importer, etc) if these implementations weren't registered somewhere so that it can load PNG, Jpeg, GIF, suckless' image format or basically any of the -quite limited- list of file formats shown in Wikipedia[0] without having to explicitly implement support for it and perhaps even allow for filters and generators? Similarly for IImageWriter or anything else that could be reused (not even necessarily from the same language).

I think the issue wasn't the registration (otherwise why bother with COM and not use/define some application-specific plugin API) but that it always felt kludgy to do it.

Though FWIW Microsoft added "registration-free" COM in XP SP2 but AFAIK all that it does is to look for some manifest file for the same data that would be in the registry. This feels mainly like a workaround for applications that use specific COM objects they cannot use in any other way, these COM objects aren't being provided by the OS itself and they cannot use an installer, so they're essentially like bundling them like any other DLLs with the EXE. Weird that it took them so long considering that it'd be classic VB apps that would benefit the most from this approach.

[0] https://en.wikipedia.org/wiki/Image_file_format

> I think the issue wasn't the registration but that it always felt kludgy to do it.

That, exactly. The registry was almost human readable until it became completely overrun with COM registrations. It needed a less kludgy way of doing it.

Agree. Also, while I was working with MSVC6, I made a couple of ActiveX libraries and when I saw my 3D controls actually work EVERYWHERE from C programs to word documents and HTML pages, I was amazed. The whole "custom control" ecosystem was very intriguing at that time. I remember Borlnd competing with their "components", too :) Still love the portability of COM.
I like many parts of COM, but I believe that example mostly demonstrates bad parts, with IDL, registrations, and over-engineered support libraries.

There's nothing wrong with exporting factory functions from DLLs. Microsoft does it all the time, APIs like Direct3D, DirectDraw and Media Foundation don't come with type libraries are they aren't registered anywhere.

Speaking about support libraries, I once made my own: https://github.com/Const-me/ComLightInterop/tree/master/ComL... Compare examples from that article with this one: https://github.com/Const-me/ComLightInterop/blob/master/Demo... That source file is the complete DLL which implements a minimalistic COM object.

With C++/CX and .NET Native they finally got it, after all these years Microsoft actually adopted Borland's productivity to COM, as done by C++ Builder and Delphi.

Then they just managed to sink that ship with their UWP execution and the anti-C++/CX team that managed to deprecate it in name of C++/WinRT.

It wouldn't be that bad if IDL tooling had actually improved since the ActiveX days.

Media Foundation is registered as one is supposed to use CoCreateInstance() etc. to create various codecs, for example.

But MF does not require CoInitialize() and indeed one can just use LoadLibrary() and lookup the factory function. That was handy when we needed to use MF in a sandboxed process when CoCreateInstance would fail due to sandbox restrictions on registry access.

> Media Foundation is registered

Good point, albeit I think only higher-level pluggable pieces are registered. Most of these objects (IMFTopology, IMFSample, IMFMediaBuffer) can only be created with corresponding C APIs.

> one is supposed to use CoCreateInstance() etc. to create various codecs

I’m not sure about that, I think one is supposed to use APIs like MFTEnumEx to find and create these codecs. These things are also in registry, but in different key; CoCreateInstance normally looks under HKCR\CLSID but MF has another one, HKCR\MediaFoundation\Transforms. See also MFTRegister function, a quote from the documentation: This function does not register the CLSID of the MFT for the CoCreateInstance or CoGetClassObject functions

I always wondered if COM+, the new version of COM, was originally going to be named COM2 ... until somebody tried to create a new visual studio project in a directory named COM2...
I spent a couple of years (while working a full-time job) writing my master's thesis on "component technology" -- COM, CORBA, .NET assemblies, OSGi and the COM-inspired object model developed at Ericsson and Sony Ericsson for use in cell phones. This was back in 2009.

I tried to make sense of how all these disparate technologies fit together. Give it a read if you like (CC-licensed):

http://www.polberger.se/components/

http://www.polberger.se/components/read/

http://www.polberger.se/components/thesis.pdf

This is really interesting, thank you for sharing. I downloaded the PDF of your thesis and put it in my to-read library.
Nice, let me know if you have any questions or feedback! (Email in profile.)
you are the expert so please correct me if I oversimplify> to me .net assemblies and Java JAR files are just a portable DLL (because they use bytecode and support reflexion).

OSGi seem to push the concept further and try to define how plugin should integrate in a hosting application (ex: eclipse ID plugin, web browser extension ...) The way OSGi try to achieve this is by defining protocol for dependency injection (Services Registry, Modules, Life-Cycle inteface ..)

I never really understood COM, I built some OCX module for visual basic 6. I have been told OCX are ActiveX control and that ActiveX control are based on COM but this is all confusing.

It all depends on how you define a software component. I use one definition in my thesis, and I argue that .NET assemblies satisfy that definition, as do OSGi bundles (but not plain JAR files). (There have been many, many attempts at defining a software component, and they tend to be incompatible with one another.)

In the end, it doesn't much matter. I chose a topic for my thesis way back in 2005, and at that time, there was some academic interest in what was called Component-Based Software Engineering (CBSE). That interest, as far as I can tell, evaporated pretty quickly.

As for your thesis, i.e., components in embedded system, I think a critical missing piece is C/C++ dependency manager like conan/vcpkg, which IMO is the primary reason why such technology is not popular in embedded world.
What's your opinion about Mozilla XPCOM regarding the others?
(Sorry about the late reply, I suppose I stopped monitoring the thread after a while.)

If memory serves, XPCOM was fairly derivative of COM, but fully cross-platform. (It had to be, as Netscape's browser and its open source successor ran on Windows, Mac OS and lots of different Unix flavors.) For this reason, I didn't include a full section on it in my thesis, but I do mention it in passing.

XPCOM saw overuse in the codebase, which led to bloat and a years-long effort to cut down on its use[1]. However, when I studied XPCOM, it seemed like an excellent way to bring the core ideas of COM to a cross-platform codebase, with C++ and JavaScript language bindings.

[1] https://wiki.mozilla.org/Gecko:DeCOMtamination

A few years back, I wanted to see what you could do if you really used modern C++ with the COM principles. This is what I came up with:

https://github.com/jbandela/cppcomponents

* There is no code generation or IDL files

* Components implement IUnknown

* You can have Constructors and static functions for C++ classes.

* You can take std::vector, std::string, std::tuple as parameters and return them (even if you are using different compilers and standard libraries)

* Cross-platform

How do you address ABI issues with standard C++ library types?
By using template meta-programming to have thunks that translate between the types.
COM has always felt like one of those "OOP and architecture astronautism gone off the deep end" technologies. A ton of boilerplate and indirection to do very little, with the associated bloat at both development and runtime. All the times I've used it, it was not because I wanted to, but because I was forced to.

Here's a fun contrast/example:

https://docs.microsoft.com/en-us/windows/win32/dlgbox/using-...

https://docs.microsoft.com/en-us/windows/win32/shell/common-...

Non-COM: fill in a structure and call a function.

COM: make a dozen (doubly-)indirect function calls.

lol #1 ... looks straightforward

... #2 brain shuts off instantly

#2 is horrid, but could be solved by inverted if conditions and a single “cleanup:” label with goto:

    if (!SUCCEEDED(hr))
        goto cleanup;
Or:

      if (SUCCEEDED(pfd->Advise(pfde, &dwCookie))
      && SUCCEEDED(pfd->GetOptions(&dwFlags))
      && SUCCEEDED(pfd->SetOptions(dwFlags | FOS_FORCEFILESYSTEM))
      && SUCCEEDED(pfd->SetFileTypes(ARRAYSIZE(c_rgSaveTypes), c_rgSaveTypes))
      && ...
      )
The point is that all those function calls aren't necessary, nor could the majority of them ever fail. Assigning to a field in a structure doesn't fail nor result in a function call.
Non-COM: The function needs to be in your process. Unless you're committing deep heresy, it'll have to be written in the same language as the code you're writing right now

COM: The function can be in the same process. It can be in another process. That process might be written in a different language, or running on a different computer.

The best we've come up with to actually mimic the COM feature set is doing HTTP. For some reason, a large subset of programmers seem to think "complex=slow", and truly believe that JSON is faster than binary-packed structures.

The performance of COM is incredible. In-process servers are practically just as fast as calling native functions. Out-of-process servers are still plenty fast, because you don't have to go opening TCP sockets, doing HTTP request parsing, etc.

> Unless you're committing deep heresy, it'll have to be written in the same language as the code you're writing right now

Calling a C ABI function is deep heresy but calling a COM (subset of C++ ABI) function isn't? I bet more languages can do the former than the latter, since C functions like CreateFileW are required for file I/O in Windows.

Maybe remoting makes COM worth it, but the vast majority of ordinary Windows APIs, the parent comment's GetOpenFileName/IFileDialog example included, don't need remoting or any of the other benefits of COM. I feel relieved every time I come across a Windows API implemented as a simple flat C API (like XInput!) instead of COM.

>The performance of COM is incredible. Agreed, the performance of COM is pretty good in-process, and can even be extended to allow other applications to script your objects (via the IDispatch interface). So it's a pretty versatile technology, but it seems to be yesterdays' news after .net came out.

To experience DCOM in your windows box now is pretty easy. Simply: Start -> Run -> 'mmc'

File -> Add Remove Snapin

Add 'component Services'

And enjoy the spinning COM+ balls to see running COM servers.

It's all still there.

I remember reading Don Box's book, he had a clear and reasonable sounding justification for every part of COM. The trouble was when you put it all together it was a nightmare to work with. I'm still doubtful anybody really understands all of it.

To some extent .Net is an acknowledgement of that, if COM hadn't been so difficult we wouldn't have got .Net.

I remember using the OLE COM viewer and seeing all the 1000s of APIs I could call. Some of them even had embedded docs. I always thought "wow! if I only I had an idea I could use all these apps and libraries together".... but I never did

https://flylib.com/books/en/3.294.1.109/1/

I noticed IGameObject in the post. I've been playing with both Unity3D and COM for several years, and kept thinking about the similarities. COM has been considered bad constantly, but base on the popularity of Unity3D, IMHO COM theory shows its advantages in building an open system(plugin-friendly).
Wow, haven't heard about COM/DCOM for over twenty years (though i had some flashbacks, when starting with gRPC). I remember they had an evangelist named Don Box, i think he even had a tattoo on his body that had to do with COM; Now wikipedia says that he worked at microsoft until last year, i wonder what he is doing now. https://en.wikipedia.org/wiki/Don_Box

I mean, if one would tattoo some software architecture, then one would have to change the tattoo every ten years, as the subject inevitably becomes obsolete; bother!

well, almost everything becomes obsolete, with the exception of Unix; that fact could serve as an indication for the alien origin of this operating system ;-)

Another flashback from working with Windows: the MSDN CDs had the best documentation that i ever saw; no one comes even close...

Except COM isn't obsolete and since Vista is the main delivery mechanism for native APIs on Windows, UWP is basically COM with TLB replaced by .NET metadata and some ABI improvements.
But .NET isn't relying on COM as an RPC mechanism, isn't it? They had something else, last time that i checked.

I think that one would be better off with gRPC, if one isn't a windows only shop, and if one is working with some kind of mixed deployment.

You mean remoteing, then WCF, now replaced by gRPC.

However the RPC stuff you are thinking about is DCOM.

COM by itself is an OOP ABI, for dynamic libraries that can either be consumed in-proc, or out of process for safety reasons and easier cross language interoperability.

I think that DCOM can be used for communication between threads, when used in-proc with the appartment model, if memory serves me well. However in this case they are sending windows messages between the communicating threads, i think that this mechanism isn't very lightweight, as opposed to how it was advertised back then.
DCOM is for networking it should never be used in-proc, other than for the coincidence that client and server were installed on the same computer, which then begs the question why not just use COM out-of-proc anyway.

Or are you mixing it up with the workarond that allows out-of-proc COM to be configured as DCOM, which kind of works, but opens a can of worms, given that the original COM isn't network aware?

yes, was referring to DCOM being used to marshall calls between appartments, within the same process. (because gRPC is better for out of process call, on grounds of better portability between systems)
I can recall how easy it was to write and compile a COM dll and have it running instantly in IIS. Everyone running Windows Server 2nnx had IIS. It was a time to be alive.