There are two ways of declaring COM interfaces, the hard way
and the easy way.
The easy way is to use an IDL file and let the MIDL compiler
generate your COM interface for you.
If you let MIDL do the work, then you also get
__uuidof support at no extra charge, which is a very nice bonus.
The hard way is to do it all by hand. If you choose this route,
your interface will look something like this:
#define INTERFACE ISample2
// *** IUnknown methods ***
STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppv) PURE;
// ** ISample methods ***
STDMETHOD_(int, Method2)(THIS) PURE;
// *** ISample2 methods ***
STDMETHOD(Method3)(THIS_ int iParameter) PURE;
STDMETHOD_(int, Method4)(THIS_ int iParameter) PURE;
What are the rules?
- You must set
INTERFACE macro to the name of the interface being
Note that you need to
#undef any previous value before you
#define the new one.
You must use the
to generate the preliminary bookkeeping for an interface.
DECLARE_INTERFACE for interfaces that have no base class
DECLARE_INTERFACE_ for interfaces that
derive from some other interface. In our example, we
ISample2 interface from
Note: In practice, you will never find
DECLARE_INTERFACE macro because all interfaces
derive from IUnknown if nothing else.
You must list all the methods of the base interfaces in exactly
the same order that they are listed by that base interface;
the methods that you are adding in the new interface must go last.
You must use the
macros to declare the
STDMETHOD if the return value is
STDMETHOD_ if the return value is some other type.
If your method has no parameters, then the argument list must
Otherwise, you must insert
THIS_ immediately after
the open-parenthesis of the parameter list.
After the parameter list and before the semicolon,
you must say
Inside the curly braces, you must say
There is a reason for each of these rules. They have to do with
being able to use the same header for both C and C++ declarations
and with interoperability with different compilers and platforms.
You must set the
INTERFACE macro because its value is used
THIS_ macros later.
You must use one of the
DECLARE_INTERFACE* macros to ensure that
the correct prologue is emitted for both C and C++.
For C, a vtable structure is declared, whereas for C++
the compiler handles the vtable automatically; on the other hand,
since C++ has inheritance, the macros need to specify the base
class so that upcasting will work.
You must list the base class methods in exactly the same order
as in the original declarations so that the C vtable structure
for your derived class matches the structure for the base class
for the extent that they overlap. This is required to preserve
the COM rule that a derived interface can be used as a base
You must use the
STDMETHOD_ macros to ensure that
the correct calling conventions are declared for the function
For C, the macro creates a function pointer in the vtable;
for C++, the macro creates a virtual function.
are used so that the C declaration
explicitly declares the "this" parameter which in C++ is implied.
Different versions are needed depending on the number of parameters
so that a spurious trailing comma
is not generated in the zero-parameter case.
PURE ensures that the C++ virtual function is pure,
because one of the defining characteristics of COM interfaces
is that all methods are pure virtual.
emit compiler-specific goo which the compiler vendor provides
in order to ensure that the generated interface matches
the COM vtable layout rules.
Different compilers have historically required different goo,
though the need for goo is gradually disappearing over time.
And you wonder why I called it "the hard way".
Similar rules apply when you are implementing an interface.
STDMETHODIMP_ macros to declare your
implementations so that they get the proper calling convention
attached to them.
We'll see examples of this