The COM Infrastructure

Once you get your mind around the concept of interface-based programming, quite a few details need implementation in order to get the class to mix in with the rest of the system. These details often overshadow the fundamental beauty of COM.

To start off with, COM classes need a place to live, so you must package them in either an EXE or a DLL. In addition, each COM class you write needs an accompanying class object (often referred to as a class factory). The way in which a COM server's class object is exposed differs depending upon how you package the COM class (in a DLL or an EXE). The server lifetime also needs to be considered. The server should stay in memory for as long as it's needed, and it should go away when it's not needed. To accomplish this, servers maintain global lock counts indicating the number of objects with extant interface pointers. Finally, well-behaved servers insert the necessary values in the Windows Registry so that client software can easily activate them.

You've spent a lot of time looking at MFC while reading this book. As you saw in Chapter 24, MFC takes care of most of the COM-based details for you. For example, CCmdTarget has an implementation of IUnknown. MFC has even created C++ classes and macros to implement class objects (such as COleObjectFactory, COleTemplateServer, DECLARE_OLE_CREATE, and IMPLEMENT_OLE_CREATE) that will put most of the correct entries into the Registry. MFC has the easiest-to-implement, zippiest version of IDispatch around—all you need is a CCmdTarget object and ClassWizard. If you decide OLE Documents or ActiveX Documents are your thing, MFC provides standard implementations of the Object Linking and Embedding and ActiveX Document protocols. Finally, MFC remains hands-down the easiest way to write fast, powerful ActiveX controls. (You can write ActiveX controls in Microsoft Visual Basic, but you don't have quite as much flexibility). These are all great features. However, using MFC has a downside.

To get these features, you need to buy into MFC 100%. Now, that's not necessarily a bad idea. However, you should be aware of the cost of entry when you decide to use MFC. MFC is big. It has to be—it's a C++ framework with many capabilities.

A New Framework

As you can see from the examples we've looked at so far, implementing COM classes and making them available to clients involves writing a great deal of code—code that remains the same from one class implementation to another. IUnknown implementations are generally the same for every COM class you encounter—the main difference between them is the interfaces exposed by each class.

But just as you no longer need to understand assembly language to get software working these days, pretty soon you'll no longer need to understand all the nuances of IUnknown and COM's relationship to C++ to get your COM-based software up and running. You're not quite at that stage, but the Active Template Library (ATL) from Microsoft is a great first step in that direction. (However, ATL does not absolve you from learning the important concepts behind COM, such as apartments and remoting.)

Before diving into ATL, let's take a quick peek at where COM and ATL fit into the big picture.

ActiveX, OLE, and COM

COM is simply the plumbing for a series of higher-level application integration technologies consisting of such items as ActiveX Controls and OLE Documents. These technologies define protocols based on COM interfaces. For example, for a COM object to qualify as a minimal OLE Document object, that COM object has to implement at least three interfaces—IPersistStorage, IOleObject, and IDataObject. You might choose to implement the higher-level features of OLE Documents and controls. However, it makes more sense to let some sort of application framework do the grunt work. Of course, that's why there's MFC.

For more information about how to implement higher-level features in raw C++, see Kraig Brockschmidt's Inside OLE, 2d. ed. (Microsoft Press, 1995).

ActiveX, MFC, and COM

While the pure plumbing of COM is quite interesting by itself (it's simply amazing to see how COM remoting works), the higher-level features are what sell applications. MFC is a huge framework geared toward creating entire Windows applications. Inside MFC, you'll find tons of utility classes, a data management/rendering mechanism (the Document-View architecture), as well as support for OLE Documents, drag and drop, Automation, and ActiveX Controls. You probably don't want to develop an OLE Document application from scratch; you're much better off using MFC. However, if you need to create a small or medium-size COM-based service, you might want to turn away from MFC so you don't have to include all the baggage MFC maintains for the higher-level features.

You can use raw C++ to create COM components, but doing so forces you to spend a good portion of your time hacking out the boilerplate code (IUnknown and class objects, for example). Using MFC to write COM-based applications turns out to be a less painful way of adding the big-ticket items to your application, but it's difficult to write lightweight COM classes in MFC. ATL sits between pure C++ and MFC as a way to implement COM-based software without having to type in the boilerplate code or buy into all of MFC's architecture. ATL is basically a set of C++ templates and other kinds of support for writing COM classes.