Simplifying the Concept of COM
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.
Comments
Give me a sample C implementation, please..
Posted by Legacy on 08/29/2003 12:00amOriginally 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.
C++ to COM
Posted by Legacy on 10/08/2002 12:00amOriginally 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!
ReplyRead Don Box's book
Posted by Legacy on 10/07/2002 12:00amOriginally 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:00amOriginally posted by: Chellam
Very good explanation
Posted by Legacy on 10/04/2002 12:00amOriginally posted by: Alexi Jordanov
I can't add something to this explanation. It's very good!
Reply