Interface Definition and Identity

Every interface has a name that serves as the programmatic compile-time type in code that uses that interface (either as a client or as an object implementor). The convention is to name each interface with a capital "I" followed by some descriptive label that indicates what functionality the interface encompasses. For example, IUnknown is the label of the interface that represents the functionality of an object when all else about that object is unknown.

These programmatic types are defined in header files provided by the designer of the interface through use of the Interface Description Language (IDL, see next section). For C++, an interface is defined as an abstract base, that is, a structure containing nothing but pure virtual member functions. This specification uses C++ notation to express the declaration of an interface. For example, the IUnknown interface is declared as:


interface IUnknown
   {
   virtual HRESULT   QueryInterface(IID& iid, void** ppv) =0;
   virtual ULONG      AddRef(void) =0;
   virtual ULONG      Release(void) =0;
   };

where "virtual" and "=0" describe the attribute of a pure virtual function and where the interface keyword is defined as:


   #define    interface    struct

The programmatic name and definition of an interface defines a type such that an application can declare a pointer to an interface using standard C++ syntax as in IUnknown *.

In addition, this specification as a notation makes some use of the C++ reference mechanism in parameter passing, for example:


   QueryInterface(const IID& iid, void**ppv);

Usually "const <type>&" is written as "REF<type>" as in REFIID for convenience. As you might expect, this example would appear in a C version of the interface as a parameter of type:


   const IID * const

Input parameters passed by reference will themselves be const, as shown here. In-out or out- parameters will not.

The use of the interface keyword is more a documentation technique than any requirement for implementation. An interface, as a binary standard, is definable in any programming language as shown in the previous section. This specification's use of C++ syntax is just a convenience.3. Also, for ease of reading, this specification generally omits parameter types in code fragments such as this but does document those parameters and types fully with each member function. Types do, of course, appear in header files with interfaces.

It is very important to note that the programmatic name for an interface is only a compile-time type used in application source code. Each interface must also have a run-time identifier. This identifier enables a caller to query (via QueryInterface) an object for a desired interface. Interface identifiers are GUIDs, that is, globally-unique 16-byte values, of type IID. The person who defines the interface allocates and assigns the IID as with any other GUID, and he informs others of the choice at the same time she informs them of the interface member functions, semantics, and so forth. Use of a GUID for this purpose guarantees that the IID will be unique in all programs, on all computers, for all time, the run-time identifier for a given interface will in fact have the same 16-byte value.

Programmers who define interfaces convey the interface identifier to implementors or clients of that interface along with the other information about the interface (in the form of header files, accompanying semantic documentation, and so forth.). To make application source code independent of the representation of particular interface identifiers, it is standard practice that the header file defines a constant for each IID where the symbol is the name of the interface prefixed with "IID_" such that the name can be derived algorithmically. For example, the interface IUnknown has an identifier called IID_IUnknown.

For brevity in this specification, this definition will not be repeated with each interface, though of course it is present in the COM implementation.