Home : COM / OLE / ActiveX notes : Interfaces
All interfaces are derived from IUnknown. Given one COM object, the client can call the QueryInterface function of any interface to obtain any of the objects interfaces.
An interface never has a version number: once defined, it can never be changed. If the COM object is updated, it can provide a new interface but must retain the old interface for compatibility with old client code.
Interfaces are generally derived from IUnknown, only. In other words, an interface provides as small a set of functions as possible. A client uses lots of interfaces, rather than one interface which does everything. The reason for this policy is that if an interface is updated (e.g. from IName to IName2), the client can be modified to take advantage of the new interface but there arent any derived interfaces which also have to be updated to allow the client to use the new features.
By convention, the C++ constant IID_IName contains the IID for the interface called IName.
An interface can be defined like a C++ abstract base class (i.e. a class with nothing but pure virtual functions). Note that an interface contains no code: it is purely an interface to the COM object which contains the implementation of these functions. For example (omitting some modifiers for clarity):
interface IUnknown
{
public:
virtual HRESULT QueryInterface(const IID* refiid, void** ppvObject) = 0;
virtual ULONG AddRef(void) = 0;
virtual ULONG Release(void) = 0;
};
This is implemented as a table of function pointers, and an interface structure which starts with a pointer to the function table see the following example, which uses C notation (again omitting some modifiers for clarity):
struct IUnknownVtbl
{
HRESULT (*QueryInterface)(IUnknown* This, const IID* refiid, void** ppvObject);
ULONG (*AddRef )(IUnknown* This);
ULONG (*Release )(IUnknown* This);
};
interface IUnknown
{
const struct IUnknownVtbl* lpVtbl;
};
Another example, showing the physical layout in memory:
0x00010000 pOne = 0x00020000 Client's IOne* for object A 0x00020000 IOne = 0x00030000 Pointer to VTable Instance A of class CExample 0x00020004 ITwo = 0x00040000 Pointer to VTable 0x00020008 m_iValue = 13 Member variables 0x00030000 &QueryInterface Pointer to method VTable of methods for IOne 0x00030004 &AddRef Pointer to method 0x00030008 &Release Pointer to method 0x0003000C &CustomMethod Pointer to method
Note:
All interfaces derive from IUnknown, so the first three methods in the interfaces VTable are QueryInterface, etc.
An IUnknown* pointer will point to one of the classs interfaces, e.g. IOne (pUnknown = 0x00020000).
Every instance of CExample will have the same VTable pointers (0x00030000 and 0x00040000); only one copy of the IOne VTable is required for all instances of this class.
The interface is normally defined in a Interface Definition Language (IDL) script. This can then be compiled by the Microsoft IDL compiler (MIDL.EXE, part of the Win32 SDK), which produces a C++ header file containing the interface definition, which can be used by both the client code and the object implementation code. It can also produce source code for a proxy and stub that can marshal the interface across a process boundary.
IUnknown: Provided by all COM objects. All other interfaces are derived from this interface. Provides the functions:
QueryInterface: returns other interface pointers, when passed their IID, and increments the objects reference count.
Release: tells the COM object that this interface is no longer required, and decrements the objects reference count. When the reference count falls to zero, the object is freed from memory and hence can no longer be accessed.
AddRef: tells the COM object that an additional reference is being made to this interface, and increments the objects reference count.
IDispatch: Provided by "programmable", or automation, objects. Provides an Invoke function, which gives access to the objects Methods (function calls, which tell the object to do something) and Properties (internal variables, so you can Get or Set their value). The Method or Property being called is identified via a DISPID number (unique within this object only), which can be obtained from the name of the Method or Property using the GetIDsOfNames function.
IEnumXXX: A family of enumerator interfaces, for returning a list of items of type XXX. Each provide the functions:
Reset: resets the list index to zero.
Next: returns a pointer to the next n items.
Skip: skips past the next n items.
Clone: returns another IEnumXXX interface with an independent list index.
IMalloc: Interface returned by the CoGetMalloc function. Used to allocate and free memory passed as interface function arguments.
IOleObject: Provides a DoVerb function, which allows Verbs to be issued the object a verb is a function (without any arguments nor return value), which is typically commanded by selecting an option from an object-specific menu list. The Verb is identified by a number. One Verb that most OLE objects support is the OLEIVERB_PROPERTIES verb, which commands the object to display a Properties dialogue box.