The motivation behind COM

79

and what problem it addresses.

Sure. This is probably more than you are asking for, but it's been a topic I've wanted to write a blog article on for a while.

The Component Object Mode, COM, has some good things going for it. It also has gets a bad rap from years of marginal documentation, complexities in implementation, and developer frustration.

COM is essentially a set of design patterns:

  • At it's core, it encourages design by interfaces (C++ classes with pure virtual methods only).

  • Reference counting. When reference counting was introduced to C/C++ developers at the time, it was akin to the ancient Romans getting informed about the number zero.

  • Encourages loose coupling

  • It's an implementation of the factory pattern.

  • It can be used as an object oriented abstraction for local and remote procedure calls (aka "out of process COM" and "DCOM")

  • Location transparency for explicit linking. Applications don't necessarily need to know "where" a particular code module (DLL) is on disk in order to instantiate objects out of it.

  • Implementation and language transparency. The calling code of a COM object and the implementation of that object need not be written in the same language.

What it enables:

  • For native C++ development, it's a very effective way of instantiating a concrete C++ class implemented in a DLL, but have it returned as an abstract base class of pure virtual methods. It enables you (a developer) to consume my C++ class from my DLL in your code without you having to include a bunch of messy implementation specific header files. I can literally give you a simple header file that reveals none of the member variables of my class and COM guids. Then you just invoke CoCreateInstance with the class id and interface ID. I can also completely re-write the DLL and it's concrete implementations of classes completely differently - but as long as I expose the same interface, it won't break your usage.

  • Different cross language scenarios. Managed C# code calling into native C++ code. Or native code projecting objects into a scripting language environment.

  • Plugin models. Let's say your application is photo renderer and you want to support 3rd party code to be able to integrate with your app, add a button to the toolbar, and have code that does some image processing. By standardizing an interface such as the following:

    class ImageProcessor : public IUnknown
    {
    public:
         void ApplyEffect(BitmapData* pBitmap) = 0;
    };
    

    vendors just need to ship new DLLs that register with COM (registry keys) and register their COM class guid with your application.

  • A sane way to do cross-process communication (in C++) between processes (local procedure calls).

  • Microsoft has done a great job allowing the higher level languages (C# and Javascript) to consume COM objects written in lower level languages (C++).

Where it is difficult to use:

  • The GUID + registry thing was a design mistake. (There, I said it, come at me bro!).

  • Out-of-proc COM calls should have inherently been an async calling pattern, but COM defaults to making it synchronous.

  • Adding COM object registrations to application setup is a chore.

  • Microsoft's IDL file format is non-standard, MIDL tool isn't fun to use, and documentation is terse.

  • "Marshalling" and proxy/stub DLLs. That's usually an entire chapter in a book. These days, there are some standard marshallers that help eliminate the confusion.

  • A lot of overhead to get a basic C++ object exported out of a DLL. In some cases, it's easier to stick with and IUnkown based implementation, but just export your own factory function out of your DLL instead of loading it via CoCreateInstance. ATL template classes make this easier.

  • Threading models for out of process. I'm on a the fence here. They couldn't have picked a worse metaphor than "apartment" to introduce a threading model into COM. Most all books do a terrible job explaining the differences between STA and MTA. But once you understand the differences and read enough of Raymond Chen's blog articles, you can actually appreciate it and know how to design with it. It only took me 20 years to get my head around this.

  • Out of proc COM calls pump window messages and introduces random bugs in applications that weren't expecting it. This one of the reasons why location transparency between in-proc vs out-of-proc COM objects is somewhat a myth.

Share:
79

Related videos on Youtube

YoavKlein
Author by

YoavKlein

Updated on December 22, 2022

Comments

  • YoavKlein
    YoavKlein over 1 year

    I'm trying to learn about COM.
    I think i got more or less the basic understanding of the architecture of COM,
    but i feel that i don't fully comprehend the motivation behind it.

    Wikipedia says this:

    For well-authored components, COM allows reuse of objects with no knowledge of their internal implementation, as it forces component implementers to provide well-defined interfaces that are separated from the implementation.

    and my question is this: When i create some .dll file,
    the client of this dll is also not exposed to the implementation,
    only to the interface, meaning, what functions he can use and their signatures.

    I'll be glad if someone could explain to me what exactly is the motivation behind COM
    and what problem it addresses.

    • Thalys
      Thalys over 10 years
      Rather specific to the significantly newer ivy bridge series, but superuser.com/questions/523928/… might be of interest.
    • Hans Passant
      Hans Passant almost 4 years
      Microsoft uses C++ for their libraries, a language that has notoriously poor interop support. And yet they want to make those libraries usable not just to another C++ compiler implementation but to any language. COM nails down the minimal rules required to make that work. No exceptions, no implementation inheritance, standard calling convention, well defined string and array types and threading model. There is a cost, few programmers enjoy using it, especially so in C++. The consequence of minimal.
    • Igor Tandetnik
      Igor Tandetnik almost 4 years
      With COM, you can have multiple implementations of the same interface; e.g. multiple objects, in the same or different DLLs, all implementing IPersistStream to allow the client to save and restore their state. That would be difficult with a plain C-style interface you envision: any given DLL can only export one function with a given name, so you can only have one implementation per DLL.
    • Simon Mourier
      Simon Mourier almost 4 years
      I suggest you read "Essential COM" by Don Box. First chapter is "COM as a better C++" which says it all: books.google.fr/…
  • Bon Gart
    Bon Gart over 10 years
    Incorrect. You typically can use both the integrated video as well as an additional video card.
  • SLaG
    SLaG over 10 years
    Really? How do you do it? All my experiences say that typically you can't. The mobo seems to always want to get the load off the CPU if it can.
  • Bon Gart
    Bon Gart over 10 years
    Typically by default the onboard graphics are enabled out of the box. if you add a second video card, Windows will want to install the drivers for it after it is detected on that first boot, but the onboard graphics chipset is still active in device manager. At that point, it is typically just a matter of enabling specific dual monitor settings within Windows (cloned or extended desktop, etc). Normally, you have to specifically disable onboard graphics within the BIOS to use one or the other.