⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch13.htm

📁 用VC开发activeX控件的电子书,很不错的
💻 HTM
📖 第 1 页 / 共 3 页
字号:
are derived from the <TT>IUnknown</TT> interface. In this example, a new type has
been defined, and that type is <TT>FISH_BSTR</TT>. <TT>FISH_BSTR</TT> is defined
as a wide-character string that is 255 characters in length. The wide-character string
is used so that the server can be compiled as either multibyte (default) or UNICODE.
The maximum length <I>must</I> be specified in the IDL definition. This is a requirement
of the MIDL compiler used to compile the IDL file. In order for the MIDL compiler
to produce code that handles parameter marshaling, the absolute length of the data
item passed into functions <I>must</I> be known.</P>
<P>The COM class <TT>CAltCustomBass1</TT> is a COM Object library that acts as a
container for the COM interfaces <TT>IFish</TT> and <TT>IBass</TT>. The specified
<TT>coclass</TT> identifies the definition as a COM class. As you can see from the
definition, the <TT>IFish</TT> interface is the default interface. This is the pointer
that is returned when the <TT>IID_IUnknown</TT> interface is queried.</P>
<P>The IDL file is compiled separately from the <TT>AtlCustomBass</TT> project. When
the <TT>AtlCustomBass</TT> project is built, the AtlCustomBass.idl file is compiled
with the MIDL compiler first. This step is automatically done as part of the build
process.</P>
<P>The IDL can also be compiled separately outside the IDE. The ATL COM AppWizard
generates a separate makefile for the IDL file (AtlCustomBassps.mk). The makefile
program <TT>nmake</TT> can be run from a command prompt to compile the IDL file.
The command line would look like this:</P>

<P><FONT COLOR="#0066FF"><TT>nmake -fatlcustombassps.mk </TT></FONT></P>
<H3><A NAME="Heading16"></A>Implementing the COM Interface</H3>
<P>Implementing the COM interface using the ATL library is a simple process. For
the programmer familiar with C++, this implementation is as simple as adding the
interface methods to the COM class. The ATL library takes care of handling all of
the <TT>IUnknown</TT> and <TT>IClassFactory</TT> interfaces, thus removing this burden
from the developer. Even the MFC framework requires that the <TT>IUnknown</TT> interface
must be handled by the programmer.</P>
<P>Listing 13.4 shows the COM class <TT>CAtlCustomBass</TT> definition file (AtlCustomBass.h).
The only modifications needed for the <TT>AtlCustomBass</TT> COM server is to add
the public interface methods and the variables needed by the class.
<H3><A NAME="Heading17"></A>Listing 13.4 AtlCustomBass.h--C++ Class Definition for
the AtlCustomBass COM Server</H3>
<P><FONT COLOR="#0066FF"><TT>class CAltCustomBass1 : <BR>
public IFish, <BR>
public IBass, <BR>
public CComObjectRoot, <BR>
public CComCoClass&lt;CAltCustomBass1,&amp;CLSID_CAltCustomBass1&gt; <BR>
{ <BR>
public: <BR>
CAltCustomBass1(); <BR>
BEGIN_COM_MAP(CAltCustomBass1) <BR>
COM_INTERFACE_ENTRY(IFish) <BR>
COM_INTERFACE_ENTRY(IBass) <BR>
END_COM_MAP() <BR>
//DECLARE_NOT_AGGREGATABLE(CAltCustomBass1) <BR>
// Remove the comment from the line above if you don't want your object to <BR>
// support aggregation. The default is to support it <BR>
DECLARE_REGISTRY(CAltCustomBass1, _T(&quot;AltCustomBass.AltCustomBass1.1&quot;),
_T(&quot;AltCustomBass.AltCustomBass1&quot;), IDS_ALTCUSTOMBASS1_DESC, THREADFLAGS_BOTH)
<BR>
// IFish <BR>
STDMETHOD(GetFishName)(FISH_BSTR pStr); <BR>
STDMETHOD(IsFreshwater)(BOOL* pBool); <BR>
// IBass <BR>
STDMETHOD(GetLocation)(FISH_BSTR p); <BR>
STDMETHOD(SetLocation)(FISH_BSTR p); <BR>
STDMETHOD(EatsOtherFish)(BOOL *pBool); <BR>
public: <BR>
WCHAR m_FishName[255]; <BR>
BOOL m_bFreshWater; <BR>
WCHAR m_Location[255]; <BR>
BOOL m_bEatsFish; }; </TT></FONT></P>
<P>To support the <TT>IFish</TT> and <TT>IBass</TT> interfaces, the custom methods
for each interface have been defined as standard C++ methods.</P>
<P>The ATL Template Library was developed to directly support and work with COM.
This is in contrast to the MFC framework, which does not directly use COM but has
hooks to manipulate COM. The COM class <TT>CAltCustomBass</TT> is derived from the
classes and interfaces shown in Table 13.2. 
<TABLE BORDER="1" WIDTH="100%">
	<CAPTION><B>Table 13.2 Base Classes and Interfaces for <I>CAtlCustomBass1</I></B></CAPTION>
	<TR ALIGN="LEFT" rowspan="1">
		<TD ALIGN="LEFT" VALIGN="TOP"><B>Class</B></TD>
		<TD ALIGN="LEFT" VALIGN="TOP"><B>Description</B></TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD ALIGN="LEFT" VALIGN="TOP"><TT>IFish</TT></TD>
		<TD ALIGN="LEFT" VALIGN="TOP"><TT>IFish</TT> COM interface, which is one of the custom interfaces supported by
			the class</TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD ALIGN="LEFT" VALIGN="TOP"><TT>IBass</TT></TD>
		<TD ALIGN="LEFT" VALIGN="TOP">Another custom interface specified during class construction</TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD ALIGN="LEFT" VALIGN="TOP"><TT>CComObjectRoot</TT></TD>
		<TD ALIGN="LEFT" VALIGN="TOP">ATL class that implements all reference counting and thread model-specific implementations</TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD ALIGN="LEFT" VALIGN="TOP"><TT>CComCoClass</TT></TD>
		<TD ALIGN="LEFT" VALIGN="TOP">ATL class that implements the class factory for the object, aggregation, and error
			handling</TD>
	</TR>
</TABLE>
<BR>
<BR>
The ATL library supports multiple interfaces through inheritance rather than through
nested classes. MFC uses nested classes for the support of multiple interfaces.</P>
<P>For a more thorough discussion of techniques used for supporting multiple interfaces,
refer to <A HREF="ch14.htm">Chapter 14</A>, which demonstrates the difference between
direct inheritance and nested classes.</P>
<P>Implementing the C++ method that will support the COM interface is a straightforward
matter. Listing 13.5 shows the implementation of the <TT>IFish</TT> and <TT>IBass</TT>
COM interfaces used in the <TT>CAltCustomBass1</TT> class.
<H3><A NAME="Heading18"></A>Listing 13.5 CAltCustomBass1.cpp--Listing of CAltCustomBass1.cpp,
Which Implements the COM Interfaces for IFish and IBass</H3>
<P><FONT COLOR="#0066FF"><TT>CAltCustomBass1::CAltCustomBass1(void) <BR>
{ <BR>
wcscpy( m_FishName, L&quot;Large Mouth Bass&quot;); <BR>
wcscpy( m_Location, L&quot;Under Lily Pads&quot;); <BR>
m_bEatsFish = TRUE; <BR>
m_bFreshWater = TRUE; <BR>
} <BR>
STDMETHODIMP CAltCustomBass1::GetFishName( FISH_BSTR pStr) <BR>
{ <BR>
// TRACE(&quot;CAltCustomBass1::GetFishName\n&quot;); <BR>
if (pStr) <BR>
wcscpy(pStr, m_FishName); <BR>
return (HRESULT)NOERROR; <BR>
} <BR>
STDMETHODIMP CAltCustomBass1::IsFreshwater( BOOL *pBool ) <BR>
{ <BR>
// TRACE(&quot;CAltCustomBass1::IsFreshwater\n&quot;); <BR>
if (pBool) <BR>
{ <BR>
*pBool = m_bFreshWater; <BR>
return S_OK; <BR>
} <BR>
return (HRESULT)NOERROR; <BR>
} <BR>
// CBass:Fish implementation of IFish STDMETHODIMP CAltCustomBass1::GetLocation(
FISH_BSTR pStr) <BR>
{ <BR>
// TRACE(&quot;CAltCustomBass1::GetLocation\n&quot;); <BR>
if (pStr) <BR>
wcscpy(pStr, m_Location); <BR>
return (HRESULT)NOERROR; <BR>
} <BR>
STDMETHODIMP CAltCustomBass1::SetLocation( FISH_BSTR pStr) <BR>
{ <BR>
// TRACE(&quot;CAltCustomBass1::SetLocation\n&quot;); <BR>
if (pStr) <BR>
wcscpy(m_Location, pStr); <BR>
return (HRESULT)NOERROR; <BR>
} <BR>
STDMETHODIMP CAltCustomBass1::EatsOtherFish( BOOL *pBool ) <BR>
{ <BR>
// TRACE(&quot;CAltCustomBass1::EatsOtherFish\n&quot;); <BR>
if (pBool) <BR>
{ <BR>
*pBool = m_bEatsFish; <BR>
return S_OK; <BR>
} <BR>
// return E_BADPOINTER; <BR>
return (HRESULT)NOERROR; <BR>
}</TT></FONT></P>
<P>Again, note that the ATL Template Library implements the <TT>IUnknown</TT> interface
for you, resulting in much fewer coding requirements for the developer. Now that
the method implementation is complete, the COM server can be compiled and built.
<H3><A NAME="Heading19"></A>Using Object Maps to Specify COM Objects</H3>
<P>The ATL library uses object maps to specify the COM objects that make up a particular
ATL server. <I>Object maps </I>are arrays of structures that tell ATL about the objects
implemented in a server. The members of an object map include the <TT>CLSID</TT>
of the object and the class of the object.</P>
<P>When a specific interface is requested through the <TT>QueryInterface</TT> method,
ATL uses COM maps to map interface IDs (<TT>IID</TT>s) to offsets in the interface.
COM maps are used by the class <TT>CComObjectRoot</TT>. When a user calls <TT>QueryInterface()</TT>,
the ATL library internally calls <TT>InternalQueryInterface()</TT> to return an interface
pointer based on an <TT>IID</TT> passed in.</P>
<P>Thirteen different types of entries can reside in a COM map (see Table 13.3).
<BR>

<TABLE BORDER="1" WIDTH="100%">
	<CAPTION><B>Table 13.3</B><SPACER TYPE="HORIZONTAL" SIZE="10"><B> Types of Entries</B></CAPTION>
	<TR ALIGN="LEFT" rowspan="1">
		<TD WIDTH="238" ALIGN="LEFT" VALIGN="TOP"><B>COM Entry Type</B></TD>
		<TD ALIGN="LEFT" VALIGN="TOP"><B>Description</B></TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD WIDTH="238" ALIGN="LEFT" VALIGN="TOP"><TT>COM_INTERFACE_ENTRY</TT></TD>
		<TD ALIGN="LEFT" VALIGN="TOP">Interface where only the class name needs to be in. The <TT>IID</TT> is synthesized
			by prepending <TT>IID_</TT> to the class name. This is the basic and popular form
			of COM interfaces.</TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD WIDTH="238" ALIGN="LEFT" VALIGN="TOP"><TT>COM_INTERFACE_ENTRY_IID</TT></TD>
		<TD ALIGN="LEFT" VALIGN="TOP">Interface where the <TT>IID</TT> and the class name need to be passed in, for example,
			<TT>COM_INTERFACE_ENTRY_IID </TT>(<TT>IID_IFish</TT>, <TT>IFish</TT>).</TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD WIDTH="238" ALIGN="LEFT" VALIGN="TOP"><TT>COM_INTERFACE_ENTRY2</TT></TD>
		<TD ALIGN="LEFT" VALIGN="TOP">Interface where it is necessary to distinguish conflicting interfaces. For example,
			if you have dual interfaces (<TT>IFoo</TT> and <TT>IBar</TT>) in an object, specifying
			<TT>COM_INTERFACE_ENTRY </TT>(<TT>IDispatch</TT>) would be ambiguous because both
			<TT>IFoo</TT> and <TT>IBar</TT> derive from <TT>Idispatch</TT>. However, by specifying
			<TT>COM_INTERFACE_ENTRY2</TT> (<TT>IDispatch</TT>, <TT>IFoo</TT>), you can control
			which interface is returned.</TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD WIDTH="238" ALIGN="LEFT" VALIGN="TOP"><TT>COM INTERFACE_ENTRY2_IID</TT></TD>
		<TD ALIGN="LEFT" VALIGN="TOP">Interface where the <TT>IID</TT> and the class name need to be passed in and you
			need to disambiguate interfaces.</TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD WIDTH="238" ALIGN="LEFT" VALIGN="TOP"><TT>COM_INTERFACE_ENTRY_TEAR_OFF</TT></TD>
		<TD ALIGN="LEFT" VALIGN="TOP">Interface is a tear-off interface. Tear-off interfaces are generally created each
			time a client calls <TT>QueryInterface</TT> for a particular interface, even if a
			tear-off for that interface is already instantiated.</TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD WIDTH="238" ALIGN="LEFT" VALIGN="TOP"><TT>COM_INTERFACE_ENTRY_CACHED_TEAR_OFF</TT></TD>
		<TD ALIGN="LEFT" VALIGN="TOP">Interface is a tear-off interface; however, ATL creates an object implementing the
			tear-off interface only the first time the interface is requested. Subsequent <TT>QueryInterface</TT>
			calls will reuse the object previously instantiated.</TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD WIDTH="238" ALIGN="LEFT" VALIGN="TOP"><TT>COM_INTERFACE_ENTRY_AGGREGATE</TT></TD>
		<TD ALIGN="LEFT" VALIGN="TOP">Indicates that a <TT>QueryInterface</TT> call for a particular interface should go
			through the aggregate.</TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD WIDTH="238" ALIGN="LEFT" VALIGN="TOP"><TT>COM_INTERFACE_ENTRY_AGGREGATE</TT></TD>
		<TD ALIGN="LEFT" VALIGN="TOP">Indicates that a <TT>QueryInterface</TT> call for an interface <TT>_BLIND</TT> should
			be blindly forwarded to the aggregate.</TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD WIDTH="238" ALIGN="LEFT" VALIGN="TOP"><TT>COM_INTERFACE_ENTRY_AUTOAGGREGATE</TT></TD>
		<TD ALIGN="LEFT" VALIGN="TOP">Automatically creates the aggregate when a client performs a <TT>QueryInterface</TT>
			for a particular interface on the aggregate.</TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD WIDTH="238" ALIGN="LEFT" VALIGN="TOP"><TT>COM_INTERFACE_ENTRY_AUTOAGGREGATE_BLIND</TT></TD>
		<TD ALIGN="LEFT" VALIGN="TOP">Automatically creates the aggregate when a client calls <TT>QueryInterface</TT> for
			an interface that cannot be found on the outer object.</TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD WIDTH="238" ALIGN="LEFT" VALIGN="TOP"><TT>COM_INTERFACE_ENTRY_CHAIN</TT></TD>
		<TD ALIGN="LEFT" VALIGN="TOP">Chains to the COM map of a base class.</TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD WIDTH="238" ALIGN="LEFT" VALIGN="TOP"><TT>COM_INTERFACE_ENTRY_FUNC</TT></TD>
		<TD ALIGN="LEFT" VALIGN="TOP">Allows you to programmatically hook the creation of a particular interface pointer.</TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD WIDTH="238" ALIGN="LEFT" VALIGN="TOP"><TT>COM_INTERFACE_ENTRY_FUNC_BLIND</TT></TD>
		<TD ALIGN="LEFT" VALIGN="TOP">Allows you to programmatically hook the creation of a pointer to any interface, thus
			not found.</TD>
	</TR>
</TABLE>

<H2><A NAME="Heading20"></A>When to Use the ActiveX Template Librarys</H2>
<P>The ActiveX template library offers many advantages to builders of COM interfaces
and COM objects. The ATL library offers the advantage of building fast, lightweight
COM servers. However, using ATL may not be the best method of implementation depending
on the situation.</P>
<P>ATL is focused entirely on the creation of small, fast COM servers in C++. ATL
is optimized for the creation of objects that expose custom or dual-interfaces and
has absolutely no inherent support for more complex COM-based architectures, such
as ActiveX documents.</P>
<P>If you want to create generic COM objects or OLE automation objects with dual-interface
support or you want to support COM's free-threading model (available with Windows
NT 4.0 and later versions of Windows) and you don't have a significant user interface
in your object, ATL is the choice for producing the smallest, fastest code.</P>
<P>If you want to create complex servers that need to support user-interface items,
ActiveX controls, or ActiveX documents, then a more robust framework such as MFC
should be used.
<H2><A NAME="Heading21"></A>From Here...</H2>
<P>This chapter has illustrated some of the many benefits gained when using the ActiveX
Template Library. The ATL COM AppWizard was used to create a framework for a COM
server. The New Class dialog was used to create a COM object with multiple custom
interfaces. All that the user must implement is the custom functionality of the server.
<A HREF="ch12.htm">Chapter 12</A> uses the MFC framework to create COM servers. MFC
is a feature-rich application framework that can be used for building COM servers.
<A HREF="ch14.htm">Chapter 14</A> illustrates a custom COM architecture for building
COM servers. The custom architecture is not derived from ATL or MFC.
</p>

<p><hr></p>
<center>
<p><font size=-2>
&copy; 1997, QUE Corporation, an imprint of Macmillan Publishing USA, a
Simon and Schuster Company.</font></p>
</center>


</BODY>

</HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -