[Previous] [Contents] [Next]

The Active Template Library

The #import directive and smart interface pointers help make client-side COM+ programming easier and more enjoyable. But these extensions do not help you build COM+ components themselves. To help you build COM+ components in C++, Microsoft offers the Active Template Library (ATL), which is a part of the Microsoft Foundation Classes and Templates (MFC&T). ATL is composed of C++ template classes that support the most common COM+ programming chores, such as implementing the IUnknown, IClassFactory, and IDispatch interfaces, as well as dealing with component registration issues. (IDispatch is covered in Chapter 5.)

The design of ATL is based loosely on that of the Standard Template Library (STL), originally developed by Hewlett-Packard and now part of the ANSI/ISO standards for C++. As their names imply, both libraries heavily leverage the template functionality in C++. Template libraries differ from traditional C++ class libraries in two important ways. First, you generally access the functionality of a template library by instantiating a class from a template rather than deriving from a base class. Because of this design difference, a class hierarchy does not necessarily define the relationships among the classes in a template library. Second, template libraries are typically supplied in source code form; they are often contained in header files and require little or no run-time DLL support.

The differences between traditional C++ class libraries and template libraries can be illustrated by comparing the MFC library to ATL. MFC is a heavy-duty library containing over 100,000 lines of code that does everything from support database functionality to create ActiveX controls (with the kitchen sink thrown in for good measure). This versatility makes MFC a great choice for developers working on standard double-clickable Windows-based applications who want as much prefabricated functionality as possible. Nevertheless, the 972 KB overhead of the mfc42.dll run-time file might be unacceptable to those working on small and (hopefully) lightweight COM+ components that can be downloaded over a low-bandwidth Internet connection. ATL, on the other hand, has a 57-KB DLL (atl.dll), and even that is optional. Of course, ATL has a much more limited scope than MFC: ATL lets you easily create most types of COM+ components, including ActiveX controls.

The ATL COM AppWizard

To make working with ATL easier, Microsoft provides the ATL COM AppWizard in Visual C++, shown in Figure 3-3. This simple wizard asks you to choose one of three types of components: DLL, EXE, or Win32 service. It even lets you specify that the proxy/stub interface marshaling code be merged with the main project rather than built as a separate DLL. Based on these few decisions, the wizard generates the source code for a component. For example, if you choose an in-process component, the wizard generates code for the standard DLL entry points, including DllMain, DllGetClassObject, DllCanUnloadNow, DllRegisterServer, and DllUnregisterServer.

Click to view at full size.

Figure 3-3. The ATL COM AppWizard, which generates some of the framework code to create a COM+ component.

The ATL Object Wizard

Although the ATL COM AppWizard quickly generates the main housing for a component, it doesn't implement any coclasses. For this task, Microsoft provides the ATL Object Wizard, shown in Figure 3-4. This wizard lets you add several different types of coclasses to a component, from rudimentary COM+ objects to objects that can operate within the COM+ run-time environment. You can also create several types of ActiveX controls, such as basic controls that work with Microsoft Internet Explorer and full controls that work with almost any container, including Visual Basic.

Click to view at full size.

Figure 3-4. The ATL Object Wizard, which helps you create a COM+ object based on ATL.

The simplest type of object, aptly named simple object, does not provide automatic support of any standard COM+ interfaces besides IUnknown and IClassFactory and thus often is the best choice when you are planning to implement custom interfaces. The interfaces implemented automatically for some of the other available object types are listed in the following table.

Object TypeImplemented InterfacesDescription
Simple ObjectIUnknownA minimal COM+ object
Add-in ObjectIDSAddInA Visual C++ extension object
Internet ExplorerIObjectWithSiteAn object that works with Internet Object Explorer, but without a user interface
Active ServerIDispatchAn object that can work with Component Active Server Pages in Internet
MS Transaction Server ComponentIObjectControlAn object designed to work with Server Component Microsoft Transaction Server
MMC SnapInIComponent, IComponentData, ISnapinAboutA Microsoft Management Console snap-in object
Lite ControlIPersistStreamInit, IOleControl, IOleObject, IOleInPlaceActiveObject, IViewObjectEx, IOleInPlaceObject- WindowlessAn object that supports the interfaces needed by Internet Explorer, including support for a user interface
Full ControlAll of the lite control interfaces, plus IPersistStorage, ISpecifyPropertyPages, IQuickActivate, IDataObject, IProvideClassInfo2An object that supports the interfaces for all ActiveX control containers
Composite ControlSame as full controlA control that can host other controls
HTML ControlAll of the full control interfaces, plus IDispatchA control with DHTML functionality that displays an HTML Web page in its user interface
Lite HTML ControlSame as lite control, plus IDispatchA control with DHTML functionality that displays an HTML Web page in its user interface but supports only the interfaces needed by Internet Explorer
Lite Composite ControlSame as lite controlA composite control that can host other controls but supports only the interfaces needed by Internet Explorer
Property PageIPropertyPageAn object that implements a property page

Based on the object type you choose, the ATL Object Wizard presents options that let you select the threading model supported by the object, specify whether a custom interface should include support for IDispatch, and specify whether the object supports aggregation. Figure 3-5 shows the most common options presented for a simple object.

Click to view at full size.

Figure 3-5. Options for the simple object in the ATL Object Wizard.

Adding Methods and Properties to an Interface Using ATL

The next step after adding a COM+ object to an ATL project is to add the desired methods and properties to the interface. The simplest way to do this is to use the wizard-like dialog boxes provided by Visual C++. Figure 3-6 shows the Add Method To Interface dialog box.

Figure 3-6. The Add Method To Interface dialog box.

Once you add interfaces and methods to an ATL-based component, your implementation work is complete. There is no need to mess with IUnknown, IClassFactory, or even registration functions because ATL provides all of this default functionality automatically. It provides the module definition (.def) file containing the DLL exports and the resource script (.rc) file that references the type library. MIDL even generates the IDL file and then compiles it as an automated part of the build process.

Figure 3-7 shows the fundamental ATL classes used to implement a COM+ object.

Click to view at full size.

Figure 3-7. The ATL object model.

CComObjectRootEx is the essential ATL class. It provides the default table-driven QueryInterface mechanism and is a required part of every ATL object. The CComCoClass class defines the default class factory and aggregation model for an object. For objects supporting a dual interface, you can use IDispatchImpl to provide a default implementation of the IDispatch interface. The ISupportErrorInfo interface must be supported if you use the IErrorInfo interface to report errors back to the client. This interface is easy to implement using the ISupportErrorInfoImpl template class.

Building a Simple COM+ Object Using ATL

You can take the following steps to build a simple COM+ object using ATL:

  1. Open Visual C++.
  2. Choose File/New and click the Projects tab.
  3. Select ATL COM AppWizard, enter the project name TestATL, and then click OK.
  4. When the ATL COM AppWizard appears, click Finish.
  5. The wizard will provide some information about what it is about to do. Click OK.
  6. Choose Insert/New ATL Object.
  7. When the ATL Object Wizard appears, click the Simple Object icon, and then click Next.
  8. In the Short Name text box, type InsideCOM, and in the Interface text box, type ISum. Then click OK.
  9. Right-click the ISum interface in ClassView, and select Add Method.
  10. In the Method Name text box, type Sum, and in the Parameters text box, type int x, int y, [out, retval] int* sum. Then click OK.
  11. Now expand the ISum interface within the CInsideCOM class in ClassView, as shown in Figure 3-8, and double-click the Sum method.
  12. Figure 3-8 The ISum::Sum method shown in the Visual C++ Workspace window.

  13. Add the line of code shown here in boldface:
  14. STDMETHODIMP CInsideCOM::Sum(int x, int y, int * sum)
    
    {
        // TODO: Add your implementation code here
        *sum = x + y;
        return S_OK;
    }
    

  15. Choose Build/Build TestATL.dll.

You can test this ATL-based component using any language that supports COM+. To create a test program in Visual Basic, simply create a Standard EXE project and set a reference to the TestATL 1.0 Type Library in the References dialog box, which you can open by choosing References from the Project menu. Then type the code shown here in boldface in the Form_Load procedure:

Private Sub Form_Load()
    Dim x As New InsideCOM
    MsgBox x.Sum(6, 3)
End Sub