?? ch21.htm
字號:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
<HEAD>
<SCRIPT LANGUAGE="JavaScript">
<!--
function popUp(pPage) {
var fullURL = document.location;
var textURL = fullURL.toString();
var URLlen = textURL.length;
var lenMinusPage = textURL.lastIndexOf("/");
lenMinusPage += 1;
var fullPath = textURL.substring(0,lenMinusPage);
popUpWin = window.open('','popWin','resizable=yes,scrollbars=no,width=525,height=394');
figDoc= popUpWin.document;
zhtm= '<HTML><HEAD><TITLE>' + pPage + '</TITLE>';
zhtm += '<link rel="stylesheet" href="/includes/stylesheets/ebooks.css"></head>';
zhtm += '<BODY bgcolor="#FFFFFF">';
zhtm += '<IMG SRC="' + fullPath + pPage + '">';
zhtm += '<P><B>' + pPage + '</B>';
zhtm += '</BODY></HTML>';
window.popUpWin.document.write(zhtm);
window.popUpWin.document.close();
// Johnny Jackson 4/28/98
}
//-->
</SCRIPT>
<link rel="stylesheet" href="/includes/stylesheets/ebooks.css">
<TITLE>Special Edition Using Visual C++ 6 -- Ch 21 -- The Active Template Library</TITLE>
</HEAD>
<BODY TEXT="#000000" BGCOLOR="#FFFFFF">
<CENTER>
<H1><IMG SRC="../button/que.gif" WIDTH="171" HEIGHT="66" ALIGN="BOTTOM" BORDER="0"><BR>
Special Edition Using Visual C++ 6</H1>
</CENTER>
<CENTER>
<P><A HREF="../ch20/ch20.htm"><IMG SRC="../button/previous.gif" WIDTH="128" HEIGHT="28"
ALIGN="BOTTOM" ALT="Previous chapter" BORDER="0"></A><A HREF="../ch22/ch22.htm"><IMG
SRC="../button/next.gif" WIDTH="128" HEIGHT="28" ALIGN="BOTTOM" ALT="Next chapter"
BORDER="0"></A><A HREF="../index.htm"><IMG SRC="../button/contents.gif" WIDTH="128"
HEIGHT="28" ALIGN="BOTTOM" ALT="Contents" BORDER="0"></A>
<HR>
</CENTER>
<CENTER>
<H1>- 21 -</H1>
</CENTER>
<CENTER>
<H1>The Active Template Library</H1>
</CENTER>
<UL>
<LI><A HREF="#Heading1">Why Use the ATL?</A>
<LI><A HREF="#Heading2">Using AppWizard to Get Started</A>
<LI><A HREF="#Heading3">Using the Object Wizard</A>
<UL>
<LI><A HREF="#Heading4">Adding a Control to the Project</A>
<LI><A HREF="#Heading5">Naming the Control</A>
<LI><A HREF="#Heading6">Setting Control Attributes</A>
<LI><A HREF="#Heading7">Supporting Stock Properties</A>
</UL>
<LI><A HREF="#Heading8">Adding Properties to the Control</A>
<UL>
<LI><A HREF="#Heading9">Code from the Object Wizard</A>
<LI><A HREF="#Heading10">Adding the ReadyState Stock Property</A>
<LI><A HREF="#Heading11">Adding Custom Properties</A>
<LI><A HREF="#Heading12">Initializing the Properties</A>
<LI><A HREF="#Heading13">Adding the Asynchronous Property</A>
</UL>
<LI><A HREF="#Heading14">Drawing the Control</A>
<LI><A HREF="#Heading15">Persistence and a Property Page</A>
<UL>
<LI><A HREF="#Heading16">Adding a Property Page</A>
<LI><A HREF="#Heading17">Connecting the Property Page to CDieRoll</A>
<LI><A HREF="#Heading18">Persistence in a Property Bag</A>
</UL>
<LI><A HREF="#Heading19">Using the Control in Control Pad</A>
<LI><A HREF="#Heading20">Adding Events</A>
<UL>
<LI><A HREF="#Heading21">Adding Methods to the Event Interface</A>
<LI><A HREF="#Heading22">Implementing the IConnectionPoint Interface</A>
<LI><A HREF="#Heading23">Firing the Click Event</A>
<LI><A HREF="#Heading24">Firing the ReadyStateChange Event</A>
</UL>
<LI><A HREF="#Heading25">Exposing the DoRoll() Function</A>
<LI><A HREF="#Heading26">Registering as init Safe and script Safe</A>
<LI><A HREF="#Heading27">Preparing the Control for Use in Design Mode</A>
<LI><A HREF="#Heading28">Minimizing Executable Size</A>
<LI><A HREF="#Heading29">Using the Control in a Web Page</A>
</UL>
<P>
<HR SIZE="4">
<CENTER>
<H1></H1>
</CENTER>
<P>The Active Template Library (ATL) is a collection of C++ class templates that
you can use to build ActiveX controls. These small controls generally don't use MFC,
the Microsoft Foundation Classes, at all. Writing an ActiveX control with ATL requires
a lot more knowledge of COM and interfaces than writing an MFC ActiveX control, because
MFC protects you from a lot of low-level COM concepts. Using ATL is not for the timid,
but it pays dividends in smaller, tighter controls. This chapter rewrites the Dieroll
control of Chapter 17, "Building an ActiveX Control," and Chapter 20, "Building
an Internet ActiveX Control," by using ATL rather than MFC as in those chapters.
You will learn the important COM/ActiveX concepts that were skimmed over while you
were using MFC.</P>
<P>
<H2><A NAME="Heading1"></A>Why Use the ATL?</H2>
<P>Building an ActiveX Control with MFC is simple, as you saw in Chapters 17 and
20. You can get by without knowing what a COM interface is or how to use a type library.
Your control can use all sorts of handy MFC classes, such as CString and CWnd, can
draw itself by using CDC member functions, and more. The only downside is that users
of your control need the MFC DLLs, and if those DLLs aren't on their system already,
the delay while 600KB or so of CAB file downloads will be significant.</P>
<P>The alternative to MFC is to obtain the ActiveX functionality from the ATL and
to call Win32 SDK functions, just as C programmers did when writing for Windows in
the days before Visual C++ and MFC. The Win32 SDK is a lot to learn and won't be
fully covered in this chapter. The good news is that if you're familiar with major
MFC classes, such as CWnd and CDC, you will recognize a lot of these SDK functions,
even if you've never seen them before. Many MFC member functions are merely wrappers
for SDK functions.</P>
<P>How much download time can you save? The MFC control from Chapter 20 is nearly
30KB plus, of course, the MFC DLLs. The ATL control built in this chapter is, at
most, 100KB and is fully self-contained. With a few tricks, you could reduce it to
50KB of control and 20KB for the ATL DLL--one-tenth the size of the total control
and DLL from Chapter 20!</P>
<P>
<H2><A NAME="Heading2"></A>Using AppWizard to Get Started</H2>
<P>There's an AppWizard that knows how to make ATL controls, and it makes your job
much simpler than it would be without the wizard. As always, choose File, New and
click the Projects tab on the New dialog. Fill in an appropriate directory and name
the project <B>DieRollControl</B>, as shown in Figure 21.1. Click OK.</P>
<BLOCKQUOTE>
<P>
<HR>
<strong>NOTE:</strong> It's tempting to name the project <I>DieRoll</I>, but later in this
process you will be inserting a control into the project--that control will be called
<I>DieRoll</I>, so to avoid name conflicts, choose a longer name for the project. 
<HR>
</BLOCKQUOTE>
<P><A HREF="javascript:popUp('21uvc01.gif')"><B>FIG. 21.1</B></A><B> </B><I>AppWizard
makes creating an ATL control simple.</I></P>
<P>There is only one step in the ATL COM AppWizard, and it is shown in Figure 21.2.
The default choices--DLL control, no merging proxy/stub code, no MFC support, no
MTS support--are the right ones for this project. The file extension will be DLL
rather than OCX, as it was for MFC controls, but that's not an important difference.
Click Finish.</P>
<P><A HREF="javascript:popUp('21uvc02.gif')"><B>FIG. 21.2</B></A><B> </B><I>Create
a DLL control.</I></P>
<P>The New Project Information dialog box, shown in Figure 21.3, confirms the choices
you have made. Click OK to create the project.</P>
<P>
<H2><A NAME="Heading3"></A>Using the Object Wizard</H2>
<P>The ATL COM AppWizard created 13 files, but you don't have a skeleton control
yet. First, you have to follow the instructions included in the Step 1 dialog box
and insert an ATL object into the project.</P>
<P>
<H3><A NAME="Heading4"></A>Adding a Control to the Project</H3>
<P>Choose Insert, New ATL Object from the menu bar. This opens the ATL Object Wizard,
shown in Figure 21.4.</P>
<P><A HREF="javascript:popUp('21uvc03.gif')"><B>FIG. 21.3</B></A><B> </B><I>Your
ATL choices are summarized before you create the project.</I></P>
<P><A HREF="javascript:popUp('21uvc04.gif')"><B>FIG. 21.4</B></A><B> </B><I>Add an
ATL control to your project.</I></P>
<P>You can add several kinds of ATL objects to your project, but at the moment you
are interested only in controls, so select Controls in the list box on the left.
The choices in the list box on the left include Full Control, Lite Control, and Property
Page. If you know for certain that this control will be used only in Internet Explorer,
perhaps as part of an intranet project, you could choose Lite Control and save a
little space. This DieRoll control might end up in any browser, a Visual Basic application,
or anywhere else for that matter, so a Full Control is the way to go. You will add
a property page later in this chapter. Select Full Control and click Next.</P>
<P>
<H3><A NAME="Heading5"></A>Naming the Control</H3>
<P>Now the ATL Object Wizard Properties dialog box appears. The first tab is the
Names tab. Here you can customize all the names used for this control. Enter <B>DieRoll</B>
for the Short Name of DieRoll, and the rest will default to names based on it, as
shown in Figure 21.5. You could change these names if you want, but there is no need.
Note that the Type, DieRoll Class, is the name that will appear in the Insert Object
dialog box of most containers. Because the MFC version of DieRoll is probably already
in your Registry, having a different name for this version is a good thing. On other
projects, you might consider changing the type name.</P>
<P><A HREF="javascript:popUp('21uvc05.gif')"><B>FIG. 21.5</B></A><B> </B><I>Set the
names of the files and the control.</I></P>
<H3><I></I></H3>
<H3><A NAME="Heading6"></A>Setting Control Attributes</H3>
<P>Click the Attributes tab. Leave the default values: Apartment Threading Model,
Dual Interface, and Yes for Aggregation. Select the check boxes Support ISupportErrorInfo
and Support Connection Points. Leave Free Threaded Marshaler deselected, as shown
in Figure 21.6. Each of these choices is discussed in the paragraphs that follow.</P>
<P><A HREF="javascript:popUp('21uvc06.gif')"><B>FIG. 21.6</B></A><B> </B><I>Set the
COM properties of your control.</I></P>
<P><B>Threading Models  </B>Avoid selecting the Single Threading Model,
even if your controls don't have any threading. To be sure that no two functions
of such a control are running at the same time, all calls to methods of a single-threaded
control must be marshalled through a proxy, which significantly slows execution.
The Apartment setting is a better choice for new controls.</P>
<P>The Apartment model refers to STA (Single-Threaded Apartment model). This means
that access to any resources shared by instances of the control (globals and statics)
is through serialization. Instance data--local automatic variables and objects dynamically
allocated on the heap--doesn't need this protection. This makes STA controls faster
than single-threaded controls. Internet Explorer exploits STA in controls it contains.</P>
<BLOCKQUOTE>
<P>
<HR>
<strong>TIP:</strong> If the design for your control includes a lot of globals and statics,
it might be a great deal of work to use the Apartment model. This isn't a good reason
to write a single-threaded control; it's a good reason to redesign your control as
a more object-oriented system.
<HR>
</BLOCKQUOTE>
<P>The Free Threading (Multithreaded Apartment or MTA) Model refers to controls that
are threaded and that already include protection against thread collisions. Although
writing a multithreaded control might seem like a great idea, using such a control
in a nonthreaded or STA container will result in marshalling again, this time to
protect the container against having two functions called at once. This, too, introduces
inefficiencies. Also, you, the developer, will do a significant amount of extra work
to create a free-threaded control, because you must add the thread collision protection.</P>
<P>The Both option in the Threading Model column asks the wizard to make a control
that can be STA or MTA, avoiding inefficiences when used in a container that is single-threaded
or STA, and exploiting the power of MTA models when available. You will have to add
the threading-protection work, just as when you write an MTA control.</P>
<P>At the moment, controls for Internet Explorer should be STA. DCOM controls that
might be accessed by several connections at once can benefit from being MTA.</P>
<P><B>Dual and Custom Interfaces  </B>COM objects communicate through <I>interfaces</I>,
which are collections of function names that describe the possible behavior of a
COM object. To use an interface, you obtain a pointer to it and then call a member
function of the interface. All Automation servers and ActiveX controls have an IDispatch
interface in addition to any other interfaces that might be specific to what the
server or control is for. To call a method of a control, you can use the Invoke()
method of the IDispatch interface, passing in the dispid of the method you want to
invoke. (This technique was developed so that methods could be called from Visual
Basic and other pointerless languages.)</P>
<P>Simply put, a <I>dual-interface</I> control lets you call methods both ways: by
using a member function of a custom interface or by using IDispatch. MFC controls
use only IDispatch, but this is slower than using a custom interface. The Interface
column on this dialog box lets you choose Dual or Custom: Custom leaves IDispatch
out of the picture. Select Dual so that the control can be used from Visual Basic,
if necessary.</P>
<P><B>Aggregation  </B>The third column, Aggregation, governs whether 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, No means they can't,
and Only means they must--this object can't stand alone.</P>
<P><B>Other Control Settings  </B>Selecting support for ISupportErrorInfo
means that your control will be able to return richer error information to the container.
Selecting support for Connection Points is vital for a control, like this one, that
will fire events. Selecting Free-Threaded Marshaler isn't required for an STA control.</P>
<P>Click the Miscellaneous tab and examine all the settings, which can be left at
their default values (see Figure 21.7). The control should be Opaque with a Solid
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -