[Previous] [Contents] [Next]

Chapter Two

The IUnknown Interface

This chapter focuses on the fundamentals of the COM+ programming model: defining custom interfaces in the Interface Definition Language (IDL) and then implementing those interfaces using any programming language. Our example in this chapter will develop a complete in-process component and a matching client. Creating this sample component requires an in-depth understanding of the two most fundamental COM+ interfaces: 00000000-0000-0000-C000-000000000046 and 00000001-0000-0000-C000-000000000046, otherwise known as IUnknown and IClassFactory. Along the way, we'll encounter IDL, the starting point for programming with COM+.

Let's begin by defining a custom interface, ISum, that our in-process component will implement. Interfaces defined by Microsoft, such as IUnknown and IClassFactory, are called standard interfaces; interfaces that you define yourself are known as custom interfaces. In this chapter, the C++ declaration of the ISum interface is defined as follows:

class ISum : public IUnknown
{
public:
    virtual HRESULT __stdcall Sum(int x, int y, int* retval)=0;
}

As you can see, the class ISum has only one public member function, Sum, which is declared as a pure virtual function. The virtual keyword indicates that the member function can be redefined in a derived class. When you refer to a derived class using a pointer of the type of the base class, a call to one of the base class's virtual functions executes the derived class's version of that function. (An object's ability to exhibit multiple behaviors is called polymorphism, as discussed in Chapter 1.) The C++ compiler inserts the address of each virtual function into a special table called a virtual function table, or v-table (sometimes abbreviated as vtbl). This binary structure implements polymorphism in C++; it also forms the basis of COM+ interfaces. At run time, every interface actually exists in memory as a v-table, as demonstrated by the following equation:

COM+ interface = C++ virtual function table

We specify the pure attribute of our Sum function by placing =0 at the end of the function declaration. The pure attribute tells the compiler that no implementation for this function is provided. A class containing one or more pure virtual functions is known as an abstract base class. An abstract base class cannot be instantiated; it can be used as a base class only when you declare other classes that will derive from it and implement its methods. Normally, an abstract base class is used to enforce a certain protocol of methods. For example, IUnknown is defined in C++ as an abstract base class; it ensures that all its methods are implemented before any classes deriving from it are instantiated.

The Sum method in this interface is also declared as __stdcall, replacing the Pascal1 calling convention used in bygone days of traditional Windows programming. These days, __stdcall is used by the Win32 API functions as well as COM+ interfaces. It pushes parameters onto the stack from right to left, but as in the Pascal calling convention, the called function pops its own arguments from the stack before returning. Functions that pop their own arguments from the stack cannot support a variable number of arguments, so the compiler automatically switches to the __cdecl calling convention (the default for C and C++ programs) for any functions with variable argument lists. The __cdecl calling convention is similar to __stdcall in that parameters are passed from right to left, but instead of the called function popping its own arguments from the stack, the calling function cleans up the stack after the function call returns. Because the function call must include stack cleanup code, the __cdecl calling convention creates larger executables than __stdcall.

The Sum function takes two integer arguments and returns their sum. To be exact, the function's return value is an HRESULT value indicating the success or failure of the call. The actual summation is returned as the function's third parameter, a pointer to an integer. Most interface methods return HRESULT values and provide their return values as pointer arguments. All COM+ errors are handled in the form of a 32-bit HRESULT value beginning with 0x8000xxxx. To interpret HRESULT values, you can either consult the winerror.h system header file or call the Win32 API function FormatMessage, which provides a string that explains the error value. (Chapter 6 discusses HRESULTs and COM+ exception handling mechanisms.)

Finally, notice that ISum publicly inherits the IUnknown interface. As you know, all COM+ objects must implement the IUnknown interface, so any object that implements the ISum interface must implement IUnknown as well. The following equation clarifies the relationship between a C++ object and a COM+ object:

C++ object + IUnknown = COM+ object

From this examination of ISum, you can see that a COM+ interface is simply a contract that requires all implementations of an interface to adhere to the defined specifications. A COM+ interface does not contain any code. A COM+ class (coclass) is a named implementation of one or more interfaces. In C++, a coclass is usually implemented as a C++ class, although the two are not synonymous. In Microsoft Visual Basic, a coclass is implemented as a Visual Basic class module. One or more coclasses are contained in a component. A component is a sort of housing for coclasses that can be built as either a DLL or an EXE.