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

📄 ch16.htm

📁 用VC开发activeX控件的电子书,很不错的
💻 HTM
📖 第 1 页 / 共 5 页
字号:
m_value = 0.0;<BR>
if(pUnkOuter == NULL)<BR>
m_pUnkOuter = this;<BR>
else<BR>
m_pUnkOuter = pUnkOuter; <BR>
}</TT></FONT></P>
<H3><A NAME="Heading24"></A>Listing 16.14 <SPACER TYPE="HORIZONTAL" SIZE="10">UMBER2.CPP--CNumber2::ImpINumber::QueryInterface(),
AddRef(), and Release() Are Delegated to pThis-&gt;m_pUnkOuter, Instead of pThis</H3>
<P><FONT COLOR="#0066FF"><TT>HRESULT CNumber2::ImpINumber::QueryInterface(REFIID
riid,<BR>
LPVOID* ppvInterface)<BR>
{<BR>
GET_CNUMBER2(pThis);<BR>
return pThis-&gt;m_pUnkOuter-&gt;QueryInterface(riid,<BR>
ppvInterface);<BR>
} <BR>
ULONG CNumber2::ImpINumber::AddRef()<BR>
{<BR>
GET_CNUMBER2(pThis);<BR>
return pThis-&gt;m_pUnkOuter-&gt;AddRef();<BR>
} <BR>
ULONG CNumber2::ImpINumber::Release()<BR>
{<BR>
GET_CNUMBER2(pThis);<BR>
return pThis-&gt;m_pUnkOuter-&gt;Release(); <BR>
}</TT></FONT></P>
<P><B><I>CNumber3</I>: The Outer Object</B><SPACER TYPE="HORIZONTAL" SIZE="10"><B>
</B>Now that you've created an aggregatable object that implements <TT>INumber</TT>,
you create another object that implements <TT>IWholeNumber</TT> and uses aggregation
to provide an implementation of <TT>INumber</TT> (see Listing 16.15).
<H3><A NAME="Heading25"></A>Listing 16.15 <SPACER TYPE="HORIZONTAL" SIZE="10">INUMBER.H--The
IWholeNumber Interface</H3>
<P><FONT COLOR="#0066FF"><TT>interface IWholeNumber : public IUnknown<BR>
{<BR>
public:<BR>
// ILrsInetUnlock methods<BR>
virtual HRESULT __stdcall GetNumber(<BR>
/* [out] */ long int* pValue) = 0;<BR>
virtual HRESULT __stdcall SetNumber(<BR>
/* [in] */ long int value) = 0; <BR>
};</TT></FONT></P>
<P>For simplicity, you're not going to make <TT>CNumber3</TT> aggregatable, so declare
the class with a single vtable for both its true <TT>IUnknown</TT> and the <TT>IWholeNumber</TT>
interface. Add the member variable <TT>m_pUnkNumber</TT> to hold the true <TT>IUnknown</TT>
of the aggregated <TT>CNumber2</TT> object. You also provide an <TT>Init</TT> method
so that the aggregation can be accomplished separate from the construction of the
object (see Listing 16.16 and Listing 16.17). Modify the class factory so that it
calls <TT>Init</TT> after constructing the object (see Listing 16.18).
<H3><A NAME="Heading26"></A>Listing 16.16 <SPACER TYPE="HORIZONTAL" SIZE="10">UMBER3.H--CNumber3
Adds Init() and m_pUnkNumber</H3>
<P><FONT COLOR="#0066FF"><TT>class CNumber3 : IWholeNumber<BR>
{<BR>
public:<BR>
// IUnknown methods<BR>
HRESULT __stdcall QueryInterface(REFIID riid,<BR>
LPVOID* lpInterface);<BR>
ULONG __stdcall AddRef();<BR>
ULONG __stdcall Release(); <BR>
// IWholeNumber methods<BR>
HRESULT __stdcall GetNumber(long int* pValue);<BR>
HRESULT __stdcall SetNumber(long int value); <BR>
// Constructor and destructor<BR>
CNumber3();<BR>
~CNumber3();<BR>
BOOL Init(); <BR>
private:<BR>
ULONG m_cRef;<BR>
LPUNKNOWN m_pUnkNumber; // Aggregated number <BR>
};</TT></FONT></P>
<H3><A NAME="Heading27"></A>Listing 16.17 <SPACER TYPE="HORIZONTAL" SIZE="10">UMFACT.CPP--CNumber3ClassFactory::CreateInstance
Calls CNumber3::Init after Constructing the CNumber3 Object</H3>
<P><FONT COLOR="#0066FF"><TT>// Create the object<BR>
CNumber3* pObj = NULL;<BR>
pObj = new CNumber3();<BR>
IncrementObjectCount();<BR>
if(NULL == pObj)<BR>
{<BR>
_ASSERT(FALSE);<BR>
DecrementObjectCount();<BR>
return E_OUTOFMEMORY;<BR>
} <BR>
// Call the initializer<BR>
if(! pObj-&gt;Init())<BR>
{<BR>
_ASSERT(FALSE);<BR>
delete pObj;<BR>
return E_FAIL; <BR>
}</TT></FONT></P>
<H3><A NAME="Heading28"></A>Listing 16.18 <SPACER TYPE="HORIZONTAL" SIZE="10">UMBER3.CPP--CNumber3::Init
Creates the Aggregated Object</H3>
<P><FONT COLOR="#0066FF"><TT>BOOL CNumber3::Init()<BR>
{<BR>
_ASSERT(m_pUnkNumber == NULL);<BR>
HRESULT hr = CoCreateInstance(CLSID_Number2, this, CLSCTX_INPROC_SERVER, IID_IUnknown,
(LPVOID*)&amp;m_pUnkNumber);<BR>
if(FAILED(hr) || (m_pUnkNumber == NULL))<BR>
{<BR>
_ASSERT(FALSE);<BR>
return FALSE;<BR>
} <BR>
return TRUE; <BR>
}</TT></FONT></P>
<P><TT>CNumber3::Init</TT> creates the aggregated object by calling <TT>CoCreateInstance</TT>
and passing its true <TT>IUnknown</TT> interface as an argument. <TT>CoCreateInstance</TT>
will call the class factory's <TT>CreateInstance</TT> method, which will construct
the <TT>CNumber2</TT> object using the new constructor. <TT>CNumber2</TT> now has
the true <TT>IUnknown</TT> of the outer object (passed from <TT>CoCreateInstance</TT>
to the class factory's <TT>CreateInstance</TT> method and then to the new constructor),
which it stores as <TT>m_pUnkOuter</TT>. The true <TT>IUnknown</TT> of the <TT>CNumber2</TT>
object is returned back through <TT>CoCreateInstance</TT>, and the outer <TT>CNumber3</TT>
object has the true <TT>IUnknown</TT> of the aggregated object, which <TT>CNumber3</TT>
stores as <TT>m_pUnkNumber</TT> (see fig. 16.2). <B><BR>
<BR>
</B><A HREF="Art/16/q_fig02n.jpg"><B>FIG. 16.2</B></A> <I><TT><BR>
CNumber2</TT> and <TT>CNumber3</TT> hold pointers to each other's true <TT>IUnknown</TT>
interfaces.</I></P>
<P>Now when <TT>CNumber3</TT>'s <TT>QueryInterface</TT> is called, it will return
<TT>this</TT> for <TT>IUnknown</TT> or <TT>IWholeNumber</TT>, but when <TT>INumber</TT>
is requested, it will pass the call on to the aggregated <TT>CNumber2</TT> object
through that object's true <TT>IUnknown</TT>, <TT>m_pUnkNumber</TT> (see Listing
16.19).
<H3><A NAME="Heading29"></A>Listing 16.19 <SPACER TYPE="HORIZONTAL" SIZE="10">UMBER3.CPP--CNumber3::QueryInterface</H3>
<P><FONT COLOR="#0066FF"><TT>HRESULT CNumber3::QueryInterface(REFIID riid,<BR>
LPVOID* ppvInterface)<BR>
{<BR>
if(IsEqualIID(riid, IID_IUnknown) ||<BR>
IsEqualIID(riid, IID_IWholeNumber))<BR>
{<BR>
*ppvInterface = this;<BR>
AddRef();<BR>
return NOERROR;<BR>
}<BR>
else if(IsEqualIID(riid, IID_INumber))<BR>
{<BR>
return m_pUnkNumber-&gt;QueryInterface(riid,<BR>
ppvInterface);<BR>
}<BR>
else<BR>
{<BR>
return E_NOINTERFACE; } <BR>
}</TT></FONT></P>
<P><B>Aggregation and Tear-Off Interfaces in ATL</B><SPACER TYPE="HORIZONTAL" SIZE="10"><B>
</B>ATL provides tools to implement aggregation. It also provides tools to implement
a kind of temporary aggregation called <I>tear-off interfaces. </I>In each of these
cases, the outer object declares the aggregated object in its <TT>COM_MAP</TT> through
one of the <TT>COM_INTERFACE_ENTRY</TT> macros. <B><I><BR>
<BR>
Aggregation </I></B><SPACER TYPE="HORIZONTAL" SIZE="10">There are four steps to aggregating
an object using ATL. First you make sure that the aggregated class has not explicitly
denied aggregation. It can do this through the use of the macro <TT>DECLARE_NOT_AGGREGATABLE</TT>.
If the ATL class doesn't explicitly deny aggregation, it's aggregatable. Second declare
a member variable in the outer class to hold the true <TT>IUnknown</TT> of the aggregated
object. If you are not using one of the automatic aggregation macros (<TT>COM_INTERFACE_ENTRY_AUTOAGGREGATE</TT>
or <TT>COM_INTERFACE_ENTRY_AUTOAGGREGATEBLIND</TT>), you have to override <TT>FinalConstruct</TT>
and create the aggregated object by using <TT>CoCreateInstance</TT>, like you did
in the <TT>CNumber3</TT> sample's constructor. When using the automatic macros, simply
initialize the member variable to <TT>NULL</TT>.</P>
<P>Third override the outer class's <TT>FinalRelease</TT> to release the aggregated
object. This is true whether you use the automatic aggregation macros or one of the
other macros.</P>
<P>Finally declare the aggregation in the <TT>COM_MAP</TT>. The four macros listed
below are available for doing this. The macro arguments are described in Tables 16.1
through 16.4.</P>
<P><FONT COLOR="#0066FF"><TT>COM_INTERFACE_ENTRY_AGGREGATE(iid, pUnknown)</TT></FONT></P>
<P>This macro is used to delegate a specific interface to an aggregated object. <BR>
<BR>

<TABLE BORDER="1" WIDTH="100%">
	<CAPTION><B>Table 16.1 </B><SPACER TYPE="HORIZONTAL" SIZE="10"><B><I>COM_INTERFACE_ENTRY_AGGREGATE</I>
		Arguments</B></CAPTION>
	<TR ALIGN="LEFT" rowspan="1">
		<TD ALIGN="LEFT" VALIGN="TOP"><B>Argument</B></TD>
		<TD ALIGN="LEFT" VALIGN="TOP"><B>Meaning</B></TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD ALIGN="LEFT" VALIGN="TOP"><TT>iid</TT></TD>
		<TD ALIGN="LEFT" VALIGN="TOP">The ID of the interface that is to be delegated to the aggregated object.</TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD ALIGN="LEFT" VALIGN="TOP"><TT>pUnknown</TT></TD>
		<TD ALIGN="LEFT" VALIGN="TOP">The aggregated object's true <TT>IUnknown</TT> interface. The aggregated object is
			created in the outer object's <TT>FinalConstruct</TT> method</TD>
	</TR>
</TABLE>
</P>
<P><FONT COLOR="#0066FF"><TT>COM_INTERFACE_ENTRY_AGGREGATE_BLIND(pUnknown)</TT></FONT></P>
<P>This macro is used to expose all of an aggregated object's interfaces from the
outer object.<BR>
<BR>

<TABLE BORDER="1" WIDTH="100%">
	<CAPTION><B>Table 16.2 </B><SPACER TYPE="HORIZONTAL" SIZE="10"><B><I>COM_INTERFACE_ENTRY_AGGREGATE_BLIND</I>
		Arguments</B></CAPTION>
	<TR ALIGN="LEFT" rowspan="1">
		<TD ALIGN="LEFT" VALIGN="TOP"><B>Argument</B></TD>
		<TD ALIGN="LEFT" VALIGN="TOP"><B>Meaning</B></TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD ALIGN="LEFT" VALIGN="TOP"><TT>pUnknown</TT></TD>
		<TD ALIGN="LEFT" VALIGN="TOP">The aggregated object's true <TT>IUnknown</TT> interface. The aggregated object is
			created in the outer object's <TT>FinalConstruct</TT> method.</TD>
	</TR>
</TABLE>
</P>
<P><FONT COLOR="#0066FF"><TT>COM_INTERFACE_ENTRY_AUTOAGGREGATE(iid, pUnknown, clsid,
cs)</TT></FONT></P>
<P>This macro is used to aggregate an object on demand, delegating the specified
interface to that object. 
<TABLE BORDER="1" WIDTH="100%">
	<CAPTION><B>Table 16.3 </B><SPACER TYPE="HORIZONTAL" SIZE="10"><B><I>COM_INTERFACE_ENTRY_AUTOAGGREGATE</I>
		Arguments</B></CAPTION>
	<TR ALIGN="LEFT" rowspan="1">
		<TD ALIGN="LEFT" VALIGN="TOP"><B>Argument</B></TD>
		<TD ALIGN="LEFT" VALIGN="TOP"><B>Meaning</B></TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD ALIGN="LEFT" VALIGN="TOP"><TT>iid</TT></TD>
		<TD ALIGN="LEFT" VALIGN="TOP">The ID of the interface that is to be delegated to the aggregated object.</TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD ALIGN="LEFT" VALIGN="TOP"><TT>pUnknown</TT></TD>
		<TD ALIGN="LEFT" VALIGN="TOP">The aggregated object's true <TT>IUnknown</TT> interface. The outer object initializes
			this to <TT>NULL</TT>, and the first query for this interface creates the aggregated
			object.</TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD ALIGN="LEFT" VALIGN="TOP"><TT>clsid</TT></TD>
		<TD ALIGN="LEFT" VALIGN="TOP">The ID of the class that is to be aggregated.</TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD ALIGN="LEFT" VALIGN="TOP"><TT>cs</TT></TD>
		<TD ALIGN="LEFT" VALIGN="TOP">A critical section used for synchronization.</TD>
	</TR>
</TABLE>
</P>
<P><FONT COLOR="#0066FF"><TT>COM_INTERFACE_ENTRY_AUTOAGGREGATE_BLIND(pUnknown, clsid,
cs)</TT></FONT></P>
<P>This macro is used to aggregate an object on demand, exposing all of the interfaces
of that object. <BR>
<BR>

<TABLE BORDER="1" WIDTH="100%">
	<CAPTION><B>Table 16.4</B><SPACER TYPE="HORIZONTAL" SIZE="10"><B> <I>COM_INTERFACE_ENTRY_AUTOAGGREGATE_BLIND</I>
		Arguments</B></CAPTION>
	<TR ALIGN="LEFT" rowspan="1">
		<TD ALIGN="LEFT" VALIGN="TOP"><B>Argument</B></TD>
		<TD ALIGN="LEFT" VALIGN="TOP"><B>Meaning</B></TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">

⌨️ 快捷键说明

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