Chapter 30
Using the Active Template Library
Most Windows programmers will tell you that learning to program with Microsoft's
Component Object Model (COM) is a difficult, error-prone process. Until
fairly recently, interest in COM was restricted to people who needed to
make use of OLE in some form or another; MFC programmers largely had no
need to use COM because MFC has provided OLE support classes for several
releases.
COM programming, however, has become increasingly important. The explosive
growth of interest in the Internet led Microsoft to restyle OLE controls
as ActiveX, and ActiveX depends entirely on the use of COM interfaces.
Furthermore, many of the new user-interface and shell features in Exchange,
Win95, and Windows NT 4.0 are only available through the use of COM interfaces.
-
Understanding ATL
-
Comparing ATL and MFC
-
Building an ATL Control
Introducing the ActiveX Template Library
With the release of Visual C++ 5.0, the ActiveX Template Library (ATL)
has matured into a complete ActiveX development solution. The 1.0 and 1.1
releases of ATL introduced ATL as an alternative to MFC for developing
ActiveX controls. These early versions of ATL, however, only supported
ActiveX COM objects and ActiveX Automation servers. Although these functions
were useful in their own right, they didn't satisfy developers' demands
for an easier way to write ActiveX controls.
There's long been an imbalance between OLE control developers and users?whereas
the users have had easy-to-use visual tools like Visual Basic and Delphi,
the control developers have been stuck writing their controls from scratch
with little automated assistance.
ATL version 2.1, the version that ships with VC++ 5.0, begins to remedy
that injustice by supporting ActiveX controls and providing an Object Wizard
that can be used to create various types of ActiveX components.
ON THE WEB
http://www.microsoft.com/visualc/prodinfo/atlinst.htm ATL 2.1 is
included with the current version of Visual C++ 5.0. If you're using an
older version of VC++, you can still get the latest version of ATL from
Microsoft's Web site; if you're using Visual C++ 4.0, 4.1, or 4.2,
however, you must also upgrade to Visual C++ 4.2b to use ATL 2.1.
How ATL Is Implemented
ATL is provided as a set of extensions to the core Visual C++ environment.
The first, and most visible, component is the new ?ATL COM AppWizard? item
that appears in the Projects tab of the New Project dialog box, as shown
in Figure 30.1. As with all of the other AppWizards that you've used throughout
this book, the ATL COM AppWizard asks questions specific to ATL projects.
We'll go into more detail about the ATL COM Wizard's questions in the section
"Creating a New ATL Project."
The first step in building an ATL project is to tell VC++ to use the
ATL COM AppWizard.
FIG. 30.1
The ATL source code is in DevStudio\VC\ATL; it's well worth a look if you're
curious about how it was implemented, because it neatly combines some advanced
C++ with familar Windows and COM concepts.
Templates for COM Objects and Interfaces
The T in ATL stands for "template." C++ templates offer
a powerful mechanism for abstracting data into classes. Instead of writing
many separate classes for similar types of operations, you can write a
template class that can be instantiated to handle many data types.
For example, suppose you are writing an e-mail application and want to
build classes to handle all of the structures shown in Listing 30.1.
Listing 30.1 Sample Structures for Template Expansion
typedef struct
{
int messageClassification;
LPTSTR senderName;
LPTSTR subject;
. . .
} incomingMessageS;
typedef struct
{
int messageClassification;
CFileArray attachedFiles;
LPTSTR subject;
Recipient *toRecipients;
. . .
} outgoingMessageS;
typedef struct
{
LPTSTR mailboxPath;
LPTSTR mailboxName;
long messageCount;
. . .
} mailboxS;
Without templates, you'd have three separate array classes?even though
their implementations would be very similar. You could work around the
problem by using an array of void pointers or handles, but then you'd lose
the benefits of type safety and argument checking. With templates, you
can use the template class like this (this example uses MFC's CList class):
CList<incomingMessageS, incomingMessageS&> incomingMessageArr;
CList<outgoingMessageS, outgoingMessageS&> outgoingMessageArr;
CList<mailboxS, mailboxS&> mailboxArr;
Here, you're creating three new instances of CList. The template's two
arguments are the type of data to store in the array and the type of data
that the new array class's member functions should use as arguments, where
appropriate. You can then use the template-based classes in your code;
the compiler takes care of expanding your template definitions into three
new classes, each with a full set of functions to handle your class.
ATL's more than just templates, though; the L in ATL is for the
library code found in \Program Files\DevStudio\VC\ATL\Include. This code
serves a purpose similar to MFC: It implements all the complex behavior
that ATL supports. The templates wrap the libraries so that they're easy
to reuse, but the libraries take care of all the sticky COM- and OLE-oriented
details for you.
ATL Object Wizard
MFC provides the AppWizard and ClassWizard for building application functionality.
When you want to add new methods or members to an MFC class, you use the
ClassWizard. However, there's no ClassWizard support for the ATL; instead,
you use the ATL Object Wizard dialog box, as shown in Figure 30.2, to create
new ATL-based classes.
The ATL Object Wizard dialog box enables you to add new ATL-based objects
to your project.
FIG.
30.2
In MFC, you use the ClassWizard to add new members or functions. In ATL,
you use the right-button context menu on objects in the ClassView tab of
the Workspace window. As shown in Figure 30.3, the context menu enables
you to add properties and methods to the control's class.
To add properties or methods to an ATL control, use the right mouse
button.
FIG.
30.3
Automatic IDL Generation
The Interface Definition Language, or IDL, provides a way for you to tell
Windows what interfaces, properties, and classes your controls expose to
the outside world, as well as what classes they depend on. IDL has a primarily
C-like syntax, but writing IDL from scratch is a fearsomely complex task.
One of Microsoft's key objectives in building ATL was to speed the ActiveX
control development process by reducing the amount of IDL hacking required
to produce ActiveX controls. Note that (as you'll see in the next chapter)
you still have to manually edit the IDL file to support control events,
but the ATL COM AppWizard provides a usable skeleton from the start.
What ATL Is
ATL is a lightweight library of templates designed to make it easy to build
small, fast ActiveX controls. Of course, if you read Chapter 29, ?Creating
ActiveX Controls,? you might be asking why you'd even want to bother with
ATL; the MFC ControlWizard does a good job of simplifying the process.
One good reason: most users will accept software that includes several
hundred KB of MFC DLLs if it comes on floppy or CD, but that baggage that
large is excessive for controls designed to be downloaded over the Internet.
Performance is another area where ATL shines; the MFC message-passing architecture
imposes overhead that ATL controls avoid. Because ATL is implemented as
a set of templates, there's very little runtime overhead for interface
queries and passing.
The ATL Object Wizard hides most of the complexity of adding new properties
and methods to your controls. In addition, the Object Wizard supports the
full set of ambient and stock properties available to ActiveX controls.
What ATL Isn't
From the discussion thus far, you might think ATL is the biggest boon to
Windows programming since #define STRICT. However, ATL's not intended to
be a general-purpose solution for writing any kind of programs; it has
some limitations that you need to be aware of.
Despite what you might be led to think from its close association with
MFC, ATL's not an application framework. It doesn't directly support menus,
toolbars, document windows, printing, sockets, or most of the other MFC
features that you've used in preceding chapters.
ATL is optimized for use with COM. Although you can accomplish a lot without
a deep understanding of COM, real mastery of ATL will require you to spend
some time getting your hands dirty with the COM interfaces implemented
by ATL. This is of course no different from the learning process involved
with MFC?you can get a lot done without knowing anything about the Win32
API, but at some point you have to move beyond the framework and call API
routines directly.
If you want to learn more about COM, Kraig Brockschmidt?s Inside OLE
is the standard reference work. It?s a thick, imposing book, but Brockschmidt
clearly explains how COM works in great detail.
Furthermore, as you'll see in Chapter 31, there's still a good bit of manual
labor involved in customizing ATL-based controls. Microsoft has largely
succeeded in reducing the amount of IDL tweaking and hand-customization
of COM interfaces needed to make ActiveX controls, but they haven't done
away with it entirely. (Good news, though?you can take a working control
like the one used in Chapters 31 and 32 and reuse it over and over!)
When to Use ATL
If you want to build COM interfaces and COM objects, ATL offers some significant
advantages. With ATL, you can build fast, lightweight COM servers in a
reasonable amount of time.
ATL is designed entirely to help you implement small, fast COM servers
in C++. These servers can expose custom COM or IDispatch-based interfaces;
however, ATL doesn't include support for more complex COM-based architectures,
such as ActiveX documents.
ATL is best used for the following types of projects:
-
ActiveX controls.
-
Internet Explorer-only controls (like ActiveX controls, but without
some of the general-purpose ActiveX interfaces).
-
Generic COM or Distributed COM objects; you can use these to distribute
processing over a network, or to encapsulate code that doesn't need a user
interface.
-
COM objects that need to support both IDispatch and custom COM interfaces.
-
COM objects, where you want to use free threading (only available in
Windows NT 4.0 as of this writing).
If your project meets any of these criteria and doesn't have a significant
user interface, then ATL is probably the best choice for producing the
smallest, fastest code.
On the other hand, if you want to create complex servers that need to support
user-interface items, embedded ActiveX controls, or full-blown ActiveX
documents, you should use a more robust framework like MFC instead of ATL.
ATL versus MFC
At first glance, ATL and MFC might seem very different. After all, MFC
is a large and complex web of classes built to offer every imaginable application
service, from printing to ODBC database access to providing a standard
Windows user interface; by contrast, ATL is a small, highly focused set
of services targeted at producing COM objects.
However, there's one critical area of agreement between the two: They were
both designed to shift the burden of programming Windows from your shoulders
onto their own. In this light, MFC and ATL are partners, not competitors.
You can see from the preceding sections that MFC and ATL both have their
own niches. MFC's broad range of services and excellent integration with
the Developer Studio make it easy to produce full-featured applications?but
those applications can be bulky. ATL produces small, fast code, but it
can't easily be made to do many things that MFC completely automates.
The good news, though, is that MFC and ATL can productively be used together.
The first route is to use MFC classes in your ATL controls. Although this
can simplify your programming job, it bogs down your controls with a lot
of unneeded baggage. A better approach is to use MFC-based applications
to host your controls. By using the techniques described in Chapter 26,
"Creating an ActiveX Container Application," you can use MFC
where it makes sense while still gaining the benefits of ATL for building
controls and extension objects.
Creating Your First ATL Project
The basic steps needed to create a new ATL project are similar to those
needed to create any other kind of project in VC++. Because the ATL Object
Wizard is a new addition, though, it's worth looking at its features to
understand how, and when, to use them.
Using the ATL COM AppWizard
As with normal MFC projects, the first step in creating a new ATL project
is to choose File, New, click the Projects
tab on the New dialog box, and choose "ATL COM Wizard" from the
list of projects. Fill in your project's name, and then click OK to start
the AppWizard. Refer to Figure 30.1, which shows the AppWizard dialog box.
It's tempting to give the project the same name as the control, but later
you'll need to insert the actual ATL controls. To avoid confusing either
yourself or the compiler, name the project by appending Control to the
control name.
The ATL COM AppWizard has only one step, as shown in Figure 30.4. The Server
Type group has three choices that govern what type of project you'll end
up with:
-
Dynamic Link Library specifies that you want a COM DLL that can act
as an in-process server.
-
Executable builds a .EXE file that can act as an out-of-process server.
-
Service builds an executable that can run as a Windows NT service.
NT services run as background processes, even when no one?s logged in.
A service control can process events and data requests from remote sources
only.
The ATL COM AppWizard starts your ATL project; you'll still have to
insert the actual ATL objects.
FIG.
30.4
The Allow merging of proxy/stub files check box controls
whether the marshaler for your control is merged into the control's DLL
or is kept in its own DLL. Finally, the Support MFC check
box controls whether or not the AppWizard will include header files and
links to MFC; if you're not using MFC routines in your control, leave it
the box unchecked.
Click Finish when you've set the options appropriately (the defaults of
Dynamic Link Library, no MFC support, and no proxy merging
is usually correct for most projects.) VC++ displays a confirmation dialog
box; when you click its OK button, the AppWizard generates the required
C++ class definitions and implementations, plus an IDL file and a proxy/stub
makefile, for your project.
Using the ATL Object Wizard
As soon as you're done with the AppWizard, you'll have a nice, but useless,
skeleton. Although the files that the AppWizard generates are necessary,
they don't do anything by themselves. You still need to actually
insert a new ATL control into your project by choosing the New ATL
Object command from the Insert menu. This command invokes
the ATL Object Wizard, pictured earlier in Figure 30.2. This Wizard enables
you to tell VC++ what type of object you want to create. The left-hand
pane lists the three types of ATL objects the Wizard supports:
-
Ordinary COM objects are just that; they can be used by programs that
understand their custom interfaces, but they don?t support the full range
of ActiveX interfaces;
-
Full-blown ActiveX controls (usable in any container), Internet Explorer
controls (like ActiveX controls minus the non-Internet Explorer COM interfaces),
or property pages (used to set the properties of other controls or objects);
-
Miscellaneous
After you select the type of object you want to create, you'll see the
ATL Object Wizard Properties dialog box, as shown in Figure 30.5. The Names
tab enables you to name your new object's C++ class, its COM interface
and COM generator (CoClass), and its implementation files. One nice feature
of VC++ 5.0 is that you can use long file names when naming files in the
Wizards, and this one is no exception.
The Names tab of the ATL Object Wizard Properties dialog box enables
you to specify the class and file names for your new object.
FIG.
30.5
Setting the Object's COM Attributes
The Attributes tab, pictured in Figure 30.6, lets you get down to business
by specifying the COM properties of your new object. The Threading Model
group controls how?and whether or not?your object handles threads. For
example:
-
Single-threaded controls do not have any threading capability. To be
certain that no two functions of such a control are running at the same
time, all calls to methods of this control must be marshaled through
a proxy, which slows execution significantly. Avoid this setting
even if your control does not use threading: the Apartment setting is a
better choice if you have few or no globals and statics.
-
Apartment model threading (also called STA, for Single-Threaded
Apartment) bottlenecks access to any global or static resources shared
by multiple instances of an object through serialization. Instance data?local
automatic variables and objects dynamically allocated on the heap?does
not need this protection. Serialization is faster than marshaling, so STA
controls are faster than single-threaded controls. Internet Explorer exploits
STA in the controls that it contains.
-
The Free threading model (also called multithreaded apartment, or MTA)
builds controls that are threaded and that already include protection against
thread collisions. Although it might seem like a great idea to write a
multithreaded control, using such a control in a single-threaded or STA
container will result in marshaling again, this time to protect the container
against having two functions called at once. This, too, introduces inefficiencies,
and because many containers are still single-threaded, this option is best
used when you're building objects for a specific container that you know
is multithreaded.
-
The Both option in the threading column asks the wizard to make a control
that can be STA or MTA, avoiding inefficiencies when used in a container
that is single-threaded or STA and exploiting the power of MTA models when
available.
The Attributes tab enables you to specify what COM features your object
supports.
FIG.
30.6
Controls for Internet Explorer 3.x should be STA. DOOM controls that might
be accessed by several connections at once can benefit from being MTA.
In general, the best setting for most uses is Apartment.
As you learned in Chapter 25, ?An Introduction to ActiveX,? COM objects
communicate through interfaces, a collection of function names that
describe the possible behavior of a COM object. To use an interface, you
get a pointer to it and then call a member function of the interface. All
ActiveX Automation servers and controls have an IDispatch interface in
addition to their custom COM interfaces. To call a control method of a
control, you can use the IDispatch::Invoke() method of the interface (passing
in the dispid of the method you want to invoke), or you can look up the
COM interface and call it directly. IDispatch was developed so that COM
methods could be called from Visual Basic and other languages that don't
support pointers; it's now used by Delphi, VBScript, and a host of others.
A dual-interface control lets you call methods both ways: by using
a member function of a custom interface or by using IDispatch. MFC controls
and Automation clients only use IDispatch, but this is slower than using
a custom interface. Select Dual if you want your object
to be usable from Visual Basic or other Automation controllers; select
Custom if you know it will only need to talk to other
COM objects.
The third group, Aggregation, governs whether or not another COM class
can use this COM class by containing a reference to an instance of it.
Choosing Yes means that other COM objects can use this
class by including it as part of their own interfaces; No
means they cannot, and Only means they must: This object
cannot stand alone.
Finally, the check boxes at the bottom of the Properties dialog box do
the following:
-
Support
ISupportErrorInfo means that your control
will be able to return richer error information to the container, including
text error messages, instead of just a single numeric error code.
-
Support Connection
Points tells the Wizard that your
object needs to support the IConnectionPoint interface. Connection points
are vital for controls that need to send notification events back to their
containers. You'll see an example of event usage in the next chapter.
-
Free Threaded
Marshaler tells the Wizard whether you
want the marshaler for this control to be free-threaded or not. This setting
is recommended for an MTA control but is not required for STA, MTA, or
single-threaded controls.
Setting the Object's Miscellaneous Properties
The Miscellaneous tab of the ATL Object Wizard Properties dialog box is
shown in Figure 30.7. For most controls, you won't need to change any of
these settings, but it's good to know what they're for in case you do
need them.
The Miscellaneous tab enables you to set some lesser-used flags that
govern how your ATL control appears and behaves.
FIG.
30.7
The View Status group's check boxes are pretty straightforward: Opaque
controls whether or not the control's background completely covers what's
behind it, and Solid Background specifies whether you
want an opaque control to use a solid background color instead of a mixed
pattern. Opaque drawing is more efficient because the container doesn't
ever have to redraw anything underneath an opaque control.
The Misc Status group is equally simple. The Invisible
at runtime check box governs whether or not your control can appear in
a container. Invisible controls can still do useful things?fetch data over
the network, fire events, and so on; they don't appear in the container.
The Acts like button and Acts like label
check boxes enable you to set flags that tell the container how to treat
your control.
The Add control based on combo box enables you to start
your control as a subclass of one of the standard Windows controls, enabling
you, for example, to build an ATL control that looks like a combo box when
it's embedded in a container.
Finally, the Other group holds three settings that didn't belong anywhere
else. Normalize DC tells ATL that you want the device
context (DC) used for your control to be normalized each time it's used.
Although this ensures consistent drawing, it imposes a small performance
penalty. The Insertable check box, when enabled, makes
your control appear in the standard Insert Object dialog used in OLE-compatible
programs; this makes it possible for users to insert your control in almost
any OLE container. The Windowed Only checkbox tells ATL
whether or not you want the control to be drawn sans window in containers
that support it; as you'll see in Chapter 32, windowless drawing isn't
supported in all containers.
Setting the Object's Stock Properties
Every individual control can have its own custom properties; Windows, however,
defines a set of stock properties that are common to all controls.
This standardization provides a consistent way for any control to enable
users to customize some aspects of its appearance and behavior.
When creating a new control with the ATL Object Wizard, you can define
which stock properties you want to support by specifying them in the Stock
Properties tab. As you can see in Figure 30.8, the tab has two lists: one
for stock properties supported by the control, and one for unsupported
properties. To enable support for a particular property, use the buttons
between the two columns to move the desired property into the Supported
column. The Object Wizard automatically generates the required code and
IDL to use the property.
The Stock Properties tab enables you to quickly add support for common
properties.
FIG.
30.8
Generating Code with the Object Wizard
Like the MFC AppWizard and ClassWizard, the ATL Object Wizard generates
some code for you. When you insert a new control into your project, the
Object Wizard generates a number of files automatically. (In the sections
that follow, classname is replaced by whatever you named your class in
the Names tab.)
The listings in this chapter are excerpts from the complete source code
for the ATLControlWin control. The source is located in the Chap31\ATLControlWin
folder on the book's CD-ROM.
The Control Class Definition
classname.h contains the class definition for your ATL control. The definition
makes heavy use of C++ multiple inheritance. A COM class that implements
or uses an interface does so by inheriting from a class representing that
interface. Because ATL-based classes implement many interfaces, they inherit
from many classes. Listing 30.2 shows all the classes that ATLControlWin's
main class inherits from.
Listing 30.2 ATLCONTROLWIN.H?CATLControlWin Inherits from Many Other
ATL and COM Classes
class ATL_NO_VTABLE CATLControlWin :
public CComObjectRootEx<CComObjectThreadModel>,
public CComCoClass<CATLControlWin, &CLSID_ATLControlWin>,
public CComControl<CATLControlWin>,
public IDispatchImpl<IATLControlWin, &IID_IATLControlWin,
&LIBID_ATLCONTROLLib>,
public IProvideClassInfo2Impl<&CLSID_ATLControlWin,
&DIID__DATLControlWin, &LIBID_ATLCONTROLLib>,
public IPersistStreamInitImpl<CATLControlWin>,
public IPersistStorageImpl<CATLControlWin>,
public IQuickActivateImpl<CATLControlWin>,
public IOleControlImpl<CATLControlWin>,
public IOleObjectImpl<CATLControlWin>,
public IOleInPlaceActiveObjectImpl<CATLControlWin>,
public IViewObjectExImpl<CATLControlWin>,
public IOleInPlaceObjectWindowlessImpl<CATLControlWin>,
public IDataObjectImpl<CATLControlWin>,
public ISupportErrorInfo,
public IConnectionPointContainerImpl<CATLControlWin>,
public ISpecifyPropertyPagesImpl<CATLControlWin>,
public CProxy_DATLControlWin<CATLControlWin>,
public IPerPropertyBrowsingImpl<CATLControlWin>,
public IEnumFORMATETC,
public IDropSource,
public IDropTarget
Now you can see where the T in ATL comes in: All of these classes are template
classes. You add support for an interface to a control by adding another
entry to this list of interface classes from which it inherits; the compiler
takes care of merging the parent class's interfaces with your control.
Notice that the interface names follow the pattern IxxxImpl: This means
that the class implements the Ixxx interface. Classes inheriting from IxxxImpl
inherit code as well as function names. For example, CATLControlWin inherits
from ISupportErrorInfo, not ISupportErrorInfoImpl<CATLControlWin>,
even though such a template does exist. That's because the code in the
ISupportErrorInfoImpl template implementation class isn't appropriate for
an ATL control, so the control inherits from the interface instead of from
the implementation.
There are also four maps in the class header file. The COM map, as shown
in Listing 30.3, connects IUnknown::QueryInterface() and all interfaces
supported by the control. All COM objects must implement IUnknown, and
QueryInterface() is used to determine what other interfaces the control
supports and obtain a pointer to them. The macros connect the Ixxx interfaces
to the IxxxImpl classes from which CATLControlWin inherits.
Listing 30.3 ATLCONTROLWIN.H?Using the COM Map to Tie IUnknown to the
Control's Interfaces
BEGIN_COM_MAP(CATLControlWin)
COM_INTERFACE_ENTRY(IATLControlWin)
COM_INTERFACE_ENTRY(IDispatch)
. . .
COM_INTERFACE_ENTRY(IEnumFORMATETC)
COM_INTERFACE_ENTRY(IDropSource)
COM_INTERFACE_ENTRY(IDropTarget)
END_COM_MAP()
The property map, as shown in Listing 30.4, links the control with the
properties it can support. Because each property will have a unique class
ID, this map is necessary so that the OLE subsystem can keep track of the
two. In addition, if your control has properties that can be stored and
reused, you use the property map to define which properties should persist.
Listing 30.4 ATLCONTROLWIN.H?Telling VC++ which Properties this Control
Supports
BEGIN_PROPERTY_MAP(CATLControlWin)
PROP_ENTRY("TextDataPath", dispidTextDataPath,
CLSID_ATLControlWinPPG)
PROP_ENTRY("Alignment", dispidAlignment,
CLSID_ATLControlWinPPG)
PROP_ENTRY("BackColor", DISPID_BACKCOLOR,
CLSID_ATLControlWinPPG)
PROP_PAGE(CLSID_CColorPropPage)
END_PROPERTY_MAP()
The connection point and message maps, shown in Listing 30.5, work together
to let the control interact with the user and with other programs. The
IConnectionPoint interface enables your control to send events to other
applications, and the connection point map specifies which connection point
subclasses your control implements. The message map is heavily used in
MFC; as in MFC applications, it enables an ATL control to respond to external
events.
Listing 30.5 ATLCONTROLWIN.H?Activating the Control with the Connection
Point and Message Maps
BEGIN_CONNECTION_POINT_MAP(CATLControlWin)
CONNECTION_POINT_ENTRY(DIID__DATLControlWin)
END_CONNECTION_POINT_MAP()
BEGIN_MSG_MAP(CATLControlWin)
MESSAGE_HANDLER(WM_PAINT, OnPaint)
MESSAGE_HANDLER(WM_GETDLGCODE, OnGetDlgCode)
. . .
MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown);
MESSAGE_HANDLER(WM_CREATE, OnCreate);
END_MSG_MAP()
The Control Class Implementation
The classname.cpp file contains the actual class implementation. The Object
Wizard generates a very small file; it originally contains only an OnDraw
method that draws "ATL 2.0" in the middle of your control. This
file is where you'll do the bulk of your customization because it's where
you'll add the member functions that make your control perform.
The Class Interface Definition
classname.idl holds the Interface Definition Language (IDL) representation
of your control's interfaces. IDL is compiled to produce automation type
libraries and Registry entries that tell other parts of the system what
interfaces your controls support. The Add Method to Interface and Add Property
to Interface dialog boxes enable you to largely avoid customizing the provided
IDL file; you'll still need to edit it by hand to add support for events,
stock properties, or enumerated properties.
Everything Else
The Object Wizard also generates some other files not listed here; these
files include a .def file that defines the control's DLL entry points,
a registration script that registers the control in the Registry, an ActiveX
Automation type library, and a resource file. With the exception of the
resource file (which you edit using the standard DevStudio resource editor),
you won't need to modify any of these files.
In this chapter, you learned how ATL is implemented in C++, what its relative
strengths and weaknesses are as compared to MFC, and when it makes sense
to use ATL. The next chapter covers the actual process of building a live
ActiveX control by using only the ATL. You'll learn how to support property
sheets, persistent properties, and a host of other cool features.