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.
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.
Figure 3-3. The ATL COM AppWizard, which generates some of the framework code to create a COM+ component.
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.
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 Type | Implemented Interfaces | Description |
---|---|---|
Simple Object | IUnknown | A minimal COM+ object |
Add-in Object | IDSAddIn | A Visual C++ extension object |
Internet Explorer | IObjectWithSite | An object that works with Internet Object Explorer, but without a user interface |
Active Server | IDispatch | An object that can work with Component Active Server Pages in Internet |
MS Transaction Server Component | IObjectControl | An object designed to work with Server Component Microsoft Transaction Server |
MMC SnapIn | IComponent, IComponentData, ISnapinAbout | A Microsoft Management Console snap-in object |
Lite Control | IPersistStreamInit, IOleControl, IOleObject, IOleInPlaceActiveObject, IViewObjectEx, IOleInPlaceObject- Windowless | An object that supports the interfaces needed by Internet Explorer, including support for a user interface |
Full Control | All of the lite control interfaces, plus IPersistStorage, ISpecifyPropertyPages, IQuickActivate, IDataObject, IProvideClassInfo2 | An object that supports the interfaces for all ActiveX control containers |
Composite Control | Same as full control | A control that can host other controls |
HTML Control | All of the full control interfaces, plus IDispatch | A control with DHTML functionality that displays an HTML Web page in its user interface |
Lite HTML Control | Same as lite control, plus IDispatch | A 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 Control | Same as lite control | A composite control that can host other controls but supports only the interfaces needed by Internet Explorer |
Property Page | IPropertyPage | An 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.
Figure 3-5. Options for the simple object in the ATL Object Wizard.
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.
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.
You can take the following steps to build a simple COM+ object using ATL:
Figure 3-8 The ISum::Sum method shown in the Visual C++ Workspace window.
STDMETHODIMP CInsideCOM::Sum(int x, int y, int * sum) { // TODO: Add your implementation code here *sum = x + y; return S_OK; } |
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 |