📄 ch12.htm
字号:
Class hierarchy and supported interfaces of the CBass class.</I></P>
<P><B>Supporting the <I>IUnknown</I> Interface </B><SPACER TYPE="HORIZONTAL" SIZE="10">While
the MFC class <TT>CCmdTarget</TT> provides built-in support for the <TT>IUnknown</TT>
interface, the COM class derived from <TT>CCmdTarget</TT> must still provide methods
that enable the MFC Interface maps to call these routines. Since <TT>IUnknown</TT>
is a standard COM interface, the functions that must be called from the COM class
have been implemented through a series of support macros. The advantage of the set
of macros is that they can be used for the <TT>IUnknown</TT> implementation of any
MFC derived class. The file commacros.h implements a set of macros that are used
for calling the <TT>IUnknown</TT> implementation within the <TT>CCmdTarget</TT> class.
Listing 12.10 shows the COM support macros for MFC. <BR>
<BR>
<IMG SRC="bar.gif" WIDTH="480" HEIGHT="6" ALIGN="BOTTOM" BORDER="0"></P>
<BLOCKQUOTE>
<P><B>NOTE:</B> The file commacros.h is not a part of MFC and must be added to the
project manually.
</BLOCKQUOTE>
<P><IMG SRC="bar.gif" WIDTH="480" HEIGHT="6" ALIGN="BOTTOM" BORDER="0">
<H3><A NAME="Heading29"></A>Listing 12.10 <SPACER TYPE="HORIZONTAL" SIZE="10">COMMACROS.H--COM
Macros Used for Accessing the IUnknown Implementation of CCmdTarget</H3>
<P><FONT COLOR="#0066FF"><TT>#ifndef _COMMACROS_H <BR>
#define _COMMACROS_H <BR>
#ifndef IMPLEMENT_IUNKNOWN <BR>
#define IMPLEMENT_IUNKNOWN_ADDREF(ObjectClass, InterfaceClass)\ <BR>
STDMETHODIMP_(ULONG)ObjectClass::X##InterfaceClass::AddRef(void)\ <BR>
{ \ <BR>
METHOD_PROLOGUE(ObjectClass, InterfaceClass); \ <BR>
return pThis->ExternalAddRef(); \ <BR>
} <BR>
#define IMPLEMENT_IUNKNOWN_RELEASE(ObjectClass, InterfaceClass)\ <BR>
STDMETHODIMP_(ULONG)ObjectClass::X##InterfaceClass::Release(void)\ <BR>
{ \ <BR>
METHOD_PROLOGUE(ObjectClass, InterfaceClass); \ <BR>
return pThis->ExternalRelease(); \ <BR>
} <BR>
#define IMPLEMENT_IUNKNOWN_QUERYINTERFACE(ObjectClass, InterfaceClass)\ <BR>
STDMETHODIMP ObjectClass::X##InterfaceClass::QueryInterface(REFIID riid, LPVOID *pVoid)\
<BR>
{ \ <BR>
METHOD_PROLOGUE(ObjectClass, InterfaceClass); \ <BR>
return (HRESULT)pThis->ExternalQueryInterface(&riid ,ppVoid); \ <BR>
} <BR>
#define IMPLEMENT_IUNKNOWN(ObjectClass, InterfaceClass)\ <BR>
IMPLEMENT_IUNKNOWN_ADDREF(ObjectClass, InterfaceClass)\ <BR>
IMPLEMENT_IUNKNOWN_RELEASE(ObjectClass, InterfaceClass)\ <BR>
IMPLEMENT_IUNKNOWN_QUERYINTERFACE(ObjectClass, InterfaceClass) <BR>
#endif #endif </TT></FONT></P>
<P><B>Adding a Class ID</B><SPACER TYPE="HORIZONTAL" SIZE="10">Now that the class
that will support the COM interfaces is defined, a unique class ID (<TT>CLSID</TT>)
must be created for the class. The <TT>CLSID</TT> allows the operating system to
distinguish which application to load when a client program wants to invoke an instance
of the object. To create a unique <TT>CLSID</TT>, the program GUIDGEN must once again
be run. <BR>
<BR>
<IMG SRC="bar.gif" WIDTH="480" HEIGHT="6" ALIGN="BOTTOM" BORDER="0"></P>
<BLOCKQUOTE>
<P><B>NOTE:</B> To create a unique ID using <TT>GUIDGEN</TT>, refer to the steps
outlined in the section " Creating the Interface Definition."
</BLOCKQUOTE>
<P><IMG SRC="bar.gif" WIDTH="480" HEIGHT="6" ALIGN="BOTTOM" BORDER="0"><BR>
<BR>
After the <TT>CLSID</TT> is created, it must be placed in a header file that acts
as a define for the class implementation. For the <TT>CBass</TT> object, the file
bassid.h is created. The <TT>CLSID</TT> is then pasted into the file and added to
the macro <TT>DEFINE_GUID</TT> (see Listing 12.11).
<H3><A NAME="Heading30"></A>Listing 12.11 <SPACER TYPE="HORIZONTAL" SIZE="10">BASSID.H--Header
File bassid.h that Contains the Implementation of CLSID for the CBass Class</H3>
<P><FONT COLOR="#0066FF"><TT>#ifndef _CLSID_Bass <BR>
#define _CLSID_Bass <BR>
//{AFA853E0-5B50-11d0-ABE6-D07900C10000} <BR>
DEFINE_GUID(CLSID_Bass,0xAFA853E0,0x5B50,0x11d0, <BR>
0xAB,0xE6,0xD0,0x79,0x00,0xC1,0x00,0x00); #endif </TT></FONT></P>
<P>The macro <TT>DEFINE_GUID</TT> assigns the name <TT>CLSID_Bass</TT> to the class
ID that was created via GUIDGEN. This macro is placed in a header file that is used
by all clients that need to invoke an instance of <TT>CLSID_Bass</TT>. This file
is <I>not </I>used by the server that implements the COM Object. <B><BR>
<BR>
Using Interface Maps to Support COM Interfaces </B><SPACER TYPE="HORIZONTAL" SIZE="10">MFC
supports COM interfaces through a technique known as <I>interface maps. </I>This
technique is similar to the message maps used to route Windows messages to message
handlers (functions) within the target class. Interface maps are basically a set
of macros that provide support for the COM interfaces embedded within the MFC-derived
class. Interface maps determine which interface methods will be handled by the particular
MFC derived class. Only methods placed in the interface maps are supported by the
COM Object. Only interface functions declared within the interface map are supported
by the COM Object. <BR>
<BR>
<IMG SRC="bar.gif" WIDTH="480" HEIGHT="6" ALIGN="BOTTOM" BORDER="0"></P>
<BLOCKQUOTE>
<P><B>NOTE:</B> Even though the <TT>IUnknown</TT> interface functions are <I>not
</I>included within the interface map for the class, they <I>must </I>be supported
by the class. All derived methods of the interface <I>must</I> be supported, although
not explicitly defined.
</BLOCKQUOTE>
<P><IMG SRC="bar.gif" WIDTH="480" HEIGHT="6" ALIGN="BOTTOM" BORDER="0"><BR>
<BR>
Adding Interface maps to a class is an easy procedure. To add interface maps to a
class, perform the following steps:
<OL>
<LI>Add the header files that define the interfaces to your class. In the BASS project,
<TT>includes</TT> for the interface files Ifish.h and Ibass.h were added to the header
file bass.h. The interface files ifish.h and ibass.h were generated by the MIDL compiler
when the IFISH.DLL project was built. These files define the respective interface
classes.
<P>
<LI>Add the macro <TT>DECLARE_OLECREATE()</TT><B> </B>to the class. This macro adds
public data members to the class including <TT>COleObjectFactory</TT>, which is the
primary interface needed for creating an object of the specified class.
<P>
<LI>The COM specification dictates that interfaces simply define the interface and
that they do not implement the methods for the interface or contain data members.
This concept means that the class implementing the interface must contain the methods
for the interface and contain any data variables needed to keep track of information
about the interface. For the class <TT>CBass</TT>, Table 12.3 illustrates the data
members needed for the interface implementation and the interface method that retrieves
or sets the data member.
<P>
<LI>Now that the data members are added to the class, some MFC macros must be added
to the class in order for MFC to support the interfaces. The first macro is <TT>DECLARE_INTERFACE_MAP</TT>,
which is added to a protected section of the class. This define is analogous to the
<TT>DECLARE_MESSAGE_MAP</TT> macro that is needed for support of Windows message
maps. <TT>DECLARE_INTERFACE_MAP</TT> is a macro that adds member variables needed
for the support of COM interfaces.
<P>
<LI>For each of the supported primary interfaces, there must be an interface map.
An interface map is added to a class through the macros <TT>BEGIN_INTERFACE_PART
(Class Name, Interface Name)</TT> and <TT>END_INTERFACE_PART (Class Name)</TT>. Between
these sections are the methods that implement the interface in the class. Again,
the <TT>IUnknown</TT> interface methods do not need to be added.
</OL>
<P><IMG SRC="bar.gif" WIDTH="480" HEIGHT="6" ALIGN="BOTTOM" BORDER="0"></P>
<BLOCKQUOTE>
<P><B>NOTE:</B> Upon inspection of the macro <TT>BEGIN_INTERFACE_PART</TT>, you can
see that the methods for the <TT>IUnknown</TT> interface are automatically added
to the class. This eliminates the need to manually add them to the class.
</BLOCKQUOTE>
<P><IMG SRC="bar.gif" WIDTH="480" HEIGHT="6" ALIGN="BOTTOM" BORDER="0"><BR>
<BR>
<TABLE BORDER="1" WIDTH="100%">
<CAPTION><B>Table 12.3</B><SPACER TYPE="HORIZONTAL" SIZE="10"><B> Data Members Needed in <I>CBass</I>
Class to Implement Supported Interfaces</B></CAPTION>
<TR ALIGN="LEFT" rowspan="1">
<TD ALIGN="LEFT" VALIGN="TOP"><B>Data Member</B></TD>
<TD ALIGN="LEFT" VALIGN="TOP"><B>Interface Method</B></TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD ALIGN="LEFT" VALIGN="TOP"><TT>BOOL m_bFreshwater</TT></TD>
<TD ALIGN="LEFT" VALIGN="TOP"><TT>IFish::IsFreshwater</TT></TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD ALIGN="LEFT" VALIGN="TOP"><TT>CString m_zFishName</TT></TD>
<TD ALIGN="LEFT" VALIGN="TOP"><TT>IFish::GetFishName</TT></TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD ALIGN="LEFT" VALIGN="TOP"><TT>CString m_zLocation</TT></TD>
<TD ALIGN="LEFT" VALIGN="TOP"><TT>IBass::GetLocation</TT> <TT>IBass::SetLocation</TT></TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD ALIGN="LEFT" VALIGN="TOP"><TT>BOOL m_bEatsOtherFish</TT></TD>
<TD ALIGN="LEFT" VALIGN="TOP"><TT>IBass::EatsOtherFish</TT></TD>
</TR>
</TABLE>
<BR>
<BR>
The header file for the <TT>CBass</TT> class (BASS.H) has been modified to include
all of the changes listed in Table 12.3. The resultant file is shown in Listing 12.12.
<H3><A NAME="Heading31"></A>Listing 12.12 <SPACER TYPE="HORIZONTAL" SIZE="10">BASS.H--Header
File for the CBass Class (bass.h)</H3>
<P><FONT COLOR="#0066FF"><TT>#ifndef __AFXWIN_H__ <BR>
#error include `stdafx.h' before including this file for PCH <BR>
#endif <BR>
#include "resource.h" // main symbols <BR>
#include "..\ifish\ifish.h" <BR>
#include "..\ifish\ibass.h" ////////////////////////////////////////////////////
/////////////////////////// CBass command target <BR>
class CBass : public CCmdTarget <BR>
{ <BR>
DECLARE_DYNCREATE(CBass) <BR>
CBass(); // protected constructor used by dynamic creation <BR>
// Attributes <BR>
public: <BR>
CString m_zFishName; <BR>
CString m_zLocation; <BR>
BOOL m_bEatsOtherFish; <BR>
BOOL m_bFreshwater; <BR>
// Operations <BR>
public: <BR>
// Overrides <BR>
// ClassWizard generated virtual function overrides <BR>
//{{AFX_VIRTUAL(CBass) <BR>
//}}AFX_VIRTUAL <BR>
// Implementation <BR>
protected: <BR>
virtual ~CBass(); <BR>
// Generated message map functions <BR>
//{{AFX_MSG(CBass) <BR>
// NOTE - the ClassWizard will add and remove member functions here. <BR>
//}}AFX_MSG <BR>
DECLARE_MESSAGE_MAP() <BR>
DECLARE_OLECREATE(CBass) <BR>
DECLARE_INTERFACE_MAP() <BR>
BEGIN_INTERFACE_PART(Fish, IFish) <BR>
STDMETHOD(GetFishName)(char *pStr); <BR>
STDMETHOD(IsFreshWater)(BOOL *pBool); <BR>
END_INTERFACE_PART(Fish) <BR>
BEGIN_INTERFACE_PART(Bass, IBass) <BR>
STDMETHOD(GetLocation)(char *pStr); <BR>
STDMETHOD(SetLocation)(char *pStr); <BR>
STDMETHOD(EatsOtherFish)(BOOL *pBool); <BR>
END_INTERFACE_PART(Bass) }; </TT></FONT></P>
<P><B>Implementing MFC Interface Maps</B><SPACER TYPE="HORIZONTAL" SIZE="10"><B>
</B>In the previous section, interface maps were added to the class header file.
The actual interface maps must now be implemented in order for the interfaces to
be supported. These changes are made to the source implementation file for the class.
For the <TT>CBass</TT> class, this file is bass.cpp.
<OL>
<LI>Add the COM support macros to the implementation file. Add the line <TT>#include
"commacros.h"</TT> to your class implementation file. Commacros.h is the
common include file that implements the <TT>IUnknown</TT> interface for your MFC
class.
<P>
<LI>Add the macro <TT>IMPLEMENT_OLECREATE()</TT> to the source file as shown here.
This macro links the MFC class, in this case <TT>CBass</TT>, with the <I>friendly
</I>or callable name for the class (<TT>Bass</TT>). The <TT>CLSID</TT> for this class
is also passed into the macro. The <TT>IMPLEMENT_OLECREATE</TT> is needed for implementation
of the <TT>COleClassFactory</TT> object that instantiates instances of the <TT>CBass</TT>
object.
<P><FONT COLOR="#0066FF"><TT>//{AFA853E0-5B50-11d0-ABE6-D07900C10000}<BR>
IMPLEMENT_OLECREATE(CBass, "Bass", <BR>
0xAFA853E0,0x5B50,0x11d0,0xAB,0xE6,0xD0,0x79,0x00,0xC1,0x00,0x00)</TT></FONT>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -