Interfaces are at the heart of any COM component. Interfaces are described in the definition file of a component. They consist of a group of semantically related functions that can be accessed by the clients of the component. Although they are a specification, they also have a physical representation. A client can request a pointer on an interface and access the component functions through that pointer. Interfaces are the only possible way to access functions from a component. They enforce information hiding by ensuring that clients can access only the component's public functions.
Interfaces also define the type of a component. Each interface corresponds to a specific view of the component. In a way, this can be compared to polymorphism in the object-oriented world. Whenever an interface from a component is requested, only the functions defined on that interface are accessible, as if the component were polymorphically cast into an object of that type.
The COM specification requires that any interface provide access to all interfaces on the same component. All interfaces should include a specific function called QueryInterface that will provide a pointer on any other interface of the component. Interfaces are identified with a globally unique identifier (GUID) guaranteed to be unique in time and space. Since this function has to be on every interface, it has been abstracted into a specific interface called IUnknown from which all other interfaces must inherit.
The two other functions exposed by IUnknown are AddRef and Release. These functions should be called when a client gets a reference to an interface and when it discards that reference, respectively. These two functions define the life-cycle of a component at runtime by implementing reference counting—a common way of determining when a component can be removed from memory: when the reference count reaches zero, this signifies that there are no more clients are using that component. You might worry that this business of reference counting will the source of problems such as memory leaks. You would be right, should you choose a low-level language in which to implement your components, since it requires strict discipline on the part of the programmers. Fortunately, you will never have to implement or use these functions in Eiffel: all the processing related to IUnknown is provided by the EiffelCOM runtime. Calls to QueryInterface are done "behind the scene" and only when needed. The component life-cycle (i.e. calls to AddRef and Release) is also taken care of by the EiffelCOM runtime.
- Parent <COM and Eiffel>