The Wayback Machine - https://web.archive.org/web/20130514034855/http://www.codeguru.com/cpp/com-tech/activex/misc/article.php/c5509/Simplifying-the-Concept-of-COM.htm

Simplifying the Concept of COM

Environment: C/C++

The odd thing about COM, C++, and C...

Like most average people, I talk about COM, use COM, and program COM without knowing what it is—until I decided to go back and see what it is. If you have the same curiosity, join me for some fun.

For years, I've known that if I have a pointer to an IUnknown, I can do a lot of things. So, let's look at the mysterious IUnknown. We can find it in the header file "unknwn.h," supplied by Microsoft. Don't try to understand everything in there. In fact, let's go the reverse way: Ignore everything except the things that we are interested in. And what follows is what we want: {skip it if you don't like it}.

#if defined(__cplusplus) && !defined(CINTERFACE)
  MIDL_INTERFACE("00000000-0000-0000-C000-000000000046")
  IUnknown
  {
  public:
    BEGIN_INTERFACE
    virtual HRESULT STDMETHODCALLTYPE QueryInterface
            (REFIID riid, void **ppvObject) = 0;
    virtual ULONG STDMETHODCALLTYPE AddRef(void) = 0;
    virtual ULONG STDMETHODCALLTYPE Release(void) = 0;
    END_INTERFACE
  };
#else   /* C style interface */
  typedef struct IUnknownVtbl
  {
    BEGIN_INTERFACE
    HRESULT (STDMETHODCALLTYPE *QueryInterface)(IUnknown *This,
             REFIID riid, void **ppvObject);
    ULONG (STDMETHODCALLTYPE *AddRef)(IUnknown *This);
    ULONG (STDMETHODCALLTYPE *Release)(IUnknown *This);
    END_INTERFACE
  } IUnknownVtbl;

  interface IUnknown
  {
    CONST_VTBL struct IUnknownVtbl *lpVtbl;
  };
#endif

We further ignore !defined(CINTERFACE), MIDL_INTERFACE("00000000-0000-0000-C000-000000000046"), BEGIN_INTERFACE, and END_INTERFACE. The HRESULT and ULONG are equivalent to a 32-bit integer, so we treat them as unsigned. The STDMETHODCALLTYPE is finally resoved to __stdcall. The REFIID is resolved to a reference (or a pointer if the code is writing in C) to a structure that identifies the interface ID, so we leave it unchanged. The CONST_VTBL will resolve to const. Now what we have is:

#if defined(__cplusplus)
  IUnknown
  {
  public:
    virtual unsigned __stdcall QueryInterface(REFIID riid,
                               void **ppvObject) = 0;
    virtual unsigned __stdcall AddRef( void) = 0;
    virtual unsigned __stdcall Release( void) = 0;
  };
#else
  typedef struct IUnknownVtbl
  {
    unsigned (__stdcall *QueryInterface)(IUnknown *This, REFIID
                         riid, void **ppvObject);
    unsigned (__stdcall *AddRef)(IUnknown *This);
    unsigned (__stdcall *Release)(IUnknown *This);
  } IUnknownVtbl;

  interface IUnknown
  {
    const struct IUnknownVtbl *lpVtbl;
  };
#endif

Try to understand the preceding code; simplifying it further, we have:

#if defined(C++)
  ISomeInterface
  {
  public:
    some pure function(s)...
  };
#else
  typedef struct ISomeInterface_Vtbl
  {
    some function pointer(s)...
  } ISomeInterface_Vtbl;

  interface ISomeInterface
  {
    const struct ISomeInterface_Vtbl *lpVtbl;
  };
#endif

Now our conclusion is: In C++, ISomeInterface is just an abstract class with some pure functions and in C, ISomeInterface is simply a pointer to a struct that contains some function pointers. Drawing the equivalence between them, we have the following core knowledge about COM, C++, and C:

A C++ class/struct (or a COM interface) is simply a pointer to a table of pointers to something. Ah, ha!—How simple it is!

From now on, don't think COM, don't think C++, but C pointers. We are already familiar with C pointers. They are small, fast, and can do a lot of things. That's what I want to say. We'll then try to find some ways to play with them.

Note: The words table, array, and struct can be used interchangably with each other as long as we agree on their meaning. Also, we don't care about a class's data member yet. We'll deal with that sometime later.

A little bit about the __stdcall: It is just an agreement between the caller and what is being called, so that the item being called knows how to accept the call, and the caller knows how to make a call. The This pointer needs a little bit more description, we'll talk about it next time.

IT Offers

Comments

  • Give me a sample C implementation, please..

    Posted by Legacy on 08/29/2003 12:00am

    Originally posted by: Luci Sandor

    Although MSDN states that you can write COM objects in C (not C++), all the samples are in C. I would like a starting point, a link to a sample, an article here on CodeGuru...
    Thanks in advance.

    Reply
  • C++ to COM

    Posted by Legacy on 10/08/2002 12:00am

    Originally posted by: Richard Grimmer

    try typing "From CPP to COM" into MSDN search for an article which REALLY helps. Takes a basic CPP class and builds it up into a fully functional COM object.

    Things get really tricky though when using ATL to create COM objects, but it is obvoiusly very fast and small being templated!

    Reply
  • Read Don Box's book

    Posted by Legacy on 10/07/2002 12:00am

    Originally posted by: COM person

    This isn't bad, but read Don's Box's book too for a really good introduction...

    Reply
  • UnderStanding COM

    Posted by Legacy on 10/06/2002 12:00am

    Originally posted by: Chellam

    Though simple You provided More insight.
    
    Good work

    Reply
  • Very good explanation

    Posted by Legacy on 10/04/2002 12:00am

    Originally posted by: Alexi Jordanov

    I can't add something to this explanation. It's very good!

    Reply

Go Deeper

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds