📄 ch14.htm
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<!--last modified on Tue, Apr 15, 1997 1:42 PM-->
<HTML>
<HEAD>
<!-- This document was created from RTF source by rtftohtml version 3.0.1 -->
<META NAME="GENERATOR" Content="Symantec Visual Page 1.0">
<META NAME="Author" Content="Steph Mineart">
<META HTTP-EQUIV="Content-Type" CONTENT="text/html;CHARSET=iso-8859-1">
<TITLE>Chapter 14</TITLE>
</HEAD>
<BODY TEXT="#000000" BGCOLOR="#FFFFFF">
<H1>Chapter 14<BR>
Creating ActiveX COM Objects and Custom Interfaces on Your Own</H1>
<UL>
<LI><A HREF="#Heading1">Creating ActiveX COM Objects and Custom Interfaces on Your
Own</A>
<UL>
<LI><A HREF="#Heading2">Creating a Basic In-Process Server</A>
<UL>
<LI><A HREF="#Heading3">Creating the Project Definition File</A>
<LI><A HREF="#Heading4">Listing 14.1 CUSTOMBASS.DEF--DLL Library Definition File
for CUSTOMBASS.DLL</A>
<LI><A HREF="#Heading5">Custom COM Server Architecture</A>
</UL>
<LI><A HREF="#Heading6">Creating the COM Class COBass</A>
<UL>
<LI><A HREF="#Heading7">Listing 14.2 COBASS.H--COM Object COBass that Implements
the IFish and IBass Interfaces</A>
<LI><A HREF="#Heading8">Listing 14.3 COBASS.CPP--IUnknown Implementation for COBass</A>
<LI><A HREF="#Heading9">Listing 14.4 COBASS.CPP--COBass Interface Implementations
of the IFish and IBass Interfaces</A>
<LI><A HREF="#Heading10">Listing 14.5 CUSTOMBASSID.H--Header File CUSTOMBASSID.H,
which Contains the Implementation of CLSID for the COBass Class</A>
</UL>
<LI><A HREF="#Heading11">Implementing the COBass Class Factory</A>
<UL>
<LI><A HREF="#Heading12">Listing 14.6 FACTORY.H--Class Factory Definition File, FACTORY.H,
for CFBass</A>
<LI><A HREF="#Heading13">Listing 14.7 FACTORY.CPP--Implementation of the CFBass Class
and IUnknown Interface</A>
<LI><A HREF="#Heading14">Listing 14.8 FACTORY.CPP--IUnknown and IClassFactory Implementations
in CImpIClassFactory</A>
</UL>
<LI><A HREF="#Heading15">Implementation of the Server Application</A>
<UL>
<LI><A HREF="#Heading16">Listing 14.9 SERVER.H--CServer Class Definition</A>
<LI><A HREF="#Heading17">Listing 14.10 SERVER.CPP--CServer Object Implementation</A>
</UL>
<LI><A HREF="#Heading18">Implementation of the Server Access Functions</A>
<UL>
<LI><A HREF="#Heading19">Listing 14.11 CUSTOMBASS.CPP--Server Access Function Implementation</A>
</UL>
<LI><A HREF="#Heading20">Compiling and Testing the COM Server</A>
<LI><A HREF="#Heading21">From Here...</A>
</UL>
</UL>
<P>
<HR SIZE="4">
<H1><A NAME="Heading1"></A>Creating ActiveX COM Objects and Custom Interfaces on
Your Own</H1>
<UL>
<LI><B>Writing a custom handler for registering components for regsvr32.exe</B>
<SPACER TYPE="VERTICAL" SIZE="2">
The server can directly register all of the COM Objects that it supports.
<P>
<LI><B>Implementing a custom class factory (IClassFactory) interface</B>
<SPACER TYPE="VERTICAL" SIZE="2">
Without the benefit of a COM framework, you must implement an IClassFactory interface
for each COM Object created.
<P>
<LI><B>Building a DLL-based server for containing COM Objects</B>
<SPACER TYPE="VERTICAL" SIZE="2">
Building COM servers without a framework requires implementing some basic COM APIs
that are entry points into DLL-based servers.
<P>
<LI><B>Unloading DLLs from memory when instances of COM Objects are no longer being
used</B>
<SPACER TYPE="VERTICAL" SIZE="2">
COM servers are responsible for removal of all COM components that are no longer
being used.
<P>
<LI><B>Utilizing different strategies for implementing COM interfaces</B>
<SPACER TYPE="VERTICAL" SIZE="2">
Multiple techniques can be used for implementing COM Objects.
</UL>
<P>A variety of methods are available for creating COM classes based upon the MFC
and ActiveX frameworks. In this chapter, you will examine methods for creating COM
classes without MFC or ActiveX frameworks.</P>
<P>How the COM class was defined or implemented does not matter to the client application
using the class. The use and function of the class are identical to the client. Defining
and implementing COM classes without a framework such as MFC or ActiveX is an easy
task, although additional work must be performed by the COM developer for object
creation and termination.</P>
<P>Although application frameworks tend to make the creation of COM components easier,
you will find several advantages to creating your own COM classes:
<UL>
<LI>The component does not have to carry excess baggage (code) incurred from using
a framework.
<P>
<LI>When using C++ without a framework, a particular base class is not required from
which to derive COM classes. This removes excess baggage which is not needed from
the implementation of the class.
<LI>COM components not derived from a framework class can still be used and accessed
from within a framework-based DLL or EXE.
</UL>
<P>Creating COM components without the benefit of a framework also has some disadvantages.
The biggest drawback is that you need to perform all of the detailed work such as
creating <TT>IClassFactory</TT> interfaces, which are normally supplied by the framework.
<H2><A NAME="Heading2"></A>Creating a Basic In-Process Server</H2>
<P>In <A HREF="ch12.htm">Chapter 12</A>, two COM interfaces are defined: <TT>IFish</TT>
and <TT>IBass</TT>. These interfaces are defined within a project called IFISH.DLL.
The <TT>IFish</TT> and <TT>IBass</TT> interfaces are accessed through a COM class
entitled <TT>CBass</TT>, which is derived from the MFC base class <TT>CCmdTarget</TT>.</P>
<P>In this chapter, the interfaces <TT>IFish</TT> and <TT>IBass</TT> will again be
used along with a new class entitled <TT>COBass</TT>, which is used to access the
interfaces. The <TT>COBass</TT> class will be implemented within a DLL and will not
be derived from a framework class.</P>
<P>To create the basic in-process server, the New dialog will be used. To create
the CUSTOMBASS project, perform the following steps:
<OL>
<LI>From within the Visual C++ development environment, select the command <U>N</U>ew
from the <U>F</U>ile menu.
<P>
<LI>Select Projects tab from the New dialog.
<P>
<LI>From the Projects tab, select Win32 Dynamic Link Library. Enter the project name
<B>CUSTOMBASS</B> into the Project <U>n</U>ame edit box. Select the OK button.
<P>
<LI>The project CUSTOMBASS is now created.
</OL>
<H3><A NAME="Heading3"></A>Creating the Project Definition File</H3>
<P>When creating a generic dynamic link library (DLL), the New dialog does not create
a definition file (DEF). All DLLs must have a definition file that is used to define
information about the project, such as functions that are exported from the library.</P>
<P>All DLLs that support COM classes <I>must</I> export some basic functions in order
for the client applications to access the COM classes. From within the Visual C++
Developer Studio, create a file called CUSTOMBASS.DEF. Listing 14.1 illustrates the
contents of this file.
<H3><A NAME="Heading4"></A>Listing 14.1<SPACER TYPE="HORIZONTAL" SIZE="10"> CUSTOMBASS.DEF--DLL
Library Definition File for CUSTOMBASS.DLL</H3>
<P><FONT COLOR="#0066FF"><TT>LIBRARY CUSTOMBASS<BR>
DESCRIPTION `CUSTOMBASS Dynamic Link Library' <BR>
EXPORTS<BR>
DllGetClassObject<BR>
DllCanUnloadNow<BR>
DllRegisterServer<BR>
DllUnregisterServer</TT></FONT></P>
<P>The function <TT>DllGetClassObject</TT> is called to create an instance of a COM
Object. <TT>DLLCanUnloadNow</TT> is called periodically by the operating system to
remove unused DLLs from system memory. <TT>DllRegisterServer</TT> is used by the
program regsvr32.exe to allow the DLL to register all COM Objects with the Windows
Registry. The function <TT>DllUnregisterServer</TT> is called to remove all registry
settings for the COM Objects from the Windows Registry.
<H3><A NAME="Heading5"></A>Custom COM Server Architecture</H3>
<P>When creating a COM server without the aid of an application framework such as
MFC, you need to establish a system architecture for implementing the COM model.
The architecture used in the CUSTOMBASS project consists of three classes:
<UL>
<LI><TT>CServer</TT>: A global class within CUSTOMBASS.DLL that acts as a reference
manager for all COM Objects within the server. This class is responsible for unloading
the DLL from memory and providing reference bookkeeping.
<P>
<LI><TT>CFBass</TT>: A class factory for the <TT>COBass</TT> COM Object. This class
implements the <TT>IClassFactory</TT> interface for the server.
<P>
<LI><TT>COBass</TT>: The COM Object class that contains and implements the <TT>IFish</TT>
and <TT>IBass</TT> interfaces.
</UL>
<P><IMG SRC="bar.gif" WIDTH="480" HEIGHT="6" ALIGN="BOTTOM" BORDER="0"></P>
<BLOCKQUOTE>
<P><B>NOTE:</B> While the CUSTOMBASS project utilizes three classes as its basic
architecture, many different approaches can be used. The only requirement is that
in all COM architectures there <I>must </I>be a COM Object class and a class factory
for each COM class.
</BLOCKQUOTE>
<P><IMG SRC="bar.gif" WIDTH="480" HEIGHT="6" ALIGN="BOTTOM" BORDER="0"><BR>
When implementing COM Objects without the use of a framework, the interfaces supported
by the class can be implemented through several methods:
<UL>
<LI>Single inheritance: In this scheme, each interface is implemented with a single
C++ implementation class. One controlling object then contains pointers to all of
the implementation classes. Although this mechanism works, it requires a significant
amount of coding, and each additional interface supported by the COM class requires
reprogramming of the COM Object.
<P>
<LI>Nested interface classes: This technique is similar to single inheritance, but
instead of having a separate C++ class for each interface, the interface implementation
classes are contained or nested within the COM Object. When a COM Object is created,
it also creates each of the interface classes. This technique is the one that MFC
uses for interface implementation within a class. Although this technique requires
less code than the single inheritance technique, it still requires a fair amount
of coding to implement. <TT>CFBass</TT><I>, </I>the class factory in CUSTOMBASS,
uses this technique.
<P>
<LI>Multiple inheritance: This method is by far the easiest one for implementing
and coding. The multiple inheritance technique requires that the COM Object class
be derived from the interface classes. The ATL framework utilizes this method. This
technique requires less code and consumes much less memory at runtime. The COM class
<TT>COBass</TT> supports the <TT>IFish</TT> and <TT>IBass</TT> interfaces through
multiple inheritance.
</UL>
<H2><A NAME="Heading6"></A>Creating the COM Class COBass</H2>
<P>In the CUSTOMBASS project, the COM class <TT>COBass,</TT> which will implement
the <TT>IFish</TT> and <TT>IBass</TT> COM interfaces, is created. You may want to
refer to <A HREF="ch12.htm">Chapter 12</A>, where the <TT>IFish</TT> and <TT>IBass</TT>
interfaces are implemented in the MFC-derived COM class <TT>CBass</TT>.</P>
<P>The class <TT>COBass</TT> is derived directly from the <TT>IFish</TT> and <TT>IBass</TT>
interfaces. By definition, this makes the interface methods of <TT>IFish</TT>, <TT>IBass</TT>,
and <TT>IUnknown</TT> an integral part of <TT>COBass</TT>. The class <TT>Cbass</TT>
is derived from the <TT>CCmdTarget</TT> class. The <TT>IFish</TT> and <TT>IBass</TT>
interfaces are added as members of the <TT>COBass</TT> class (nested interfaces).</P>
<P><TT>COBass</TT> is a C++ class that is derived from the <TT>IBass</TT> and <TT>IFish</TT>
interfaces. Listing 14.2 shows the class definition for <TT>COBass</TT>. This is
different from <TT>CBass</TT><I>,</I> which was derived from the MFC class <TT>CCmdTarget</TT>.
<H3><A NAME="Heading7"></A>Listing 14.2 <SPACER TYPE="HORIZONTAL" SIZE="10">COBASS.H--COM
Object COBass that Implements the IFish and IBass Interfaces</H3>
<P><FONT COLOR="#0066FF"><TT>#if !defined(COBASS_H)<BR>
#define COBASS_H <BR>
#ifdef __cplusplus <BR>
#include "..\ifish\ifish.h"<BR>
#include "..\ifish\ibass.h" <BR>
class COBass : public IFish , public IBass<BR>
{<BR>
public:<BR>
// Main Object Constructor & Destructor.<BR>
COBass(IUnknown* pUnkOuter, CServer* pServer);<BR>
~COBass(void); <BR>
// shared IUnknown methods. Main object, non-delegating.<BR>
STDMETHODIMP QueryInterface(REFIID, PPVOID);<BR>
STDMETHODIMP_(ULONG) AddRef(void);<BR>
STDMETHODIMP_(ULONG) Release(void); <BR>
// IFish methods<BR>
STDMETHODIMP IsFreshwater(BOOL *);<BR>
STDMETHODIMP GetFishName( LPTSTR ); <BR>
// IBass methods<BR>
STDMETHODIMP GetLocation( LPTSTR );<BR>
STDMETHODIMP SetLocation( LPTSTR );<BR>
STDMETHODIMP EatsOtherFish( BOOL *); <BR>
private:<BR>
// We declare nested class interface implementations here. <BR>
// Main Object reference count.<BR>
ULONG m_cRefs; <BR>
// Outer unknown (aggregation & delegation).<BR>
IUnknown* m_pUnkOuter; <BR>
// Pointer to this component server's control object.<BR>
CServer* m_pServer;<BR>
char m_zFishName[256];<BR>
char m_zLocation[256];<BR>
BOOL m_bEatsOtherFish;<BR>
BOOL m_bFreshwater;<BR>
};<BR>
typedef COBass* PCOBass;<BR>
#endif // __cplusplus <BR>
#endif // COBASS_H</TT></FONT></P>
<P>When deriving COM classes from multiple interfaces, less coding is needed to implement
the COM Object and the interfaces. One of the advantages of deriving a COM class
from multiple interfaces is that only one implementation of the <TT>IUnknown</TT>
interfaces is required. The delegation of the <TT>IUnknown</TT> interface is also
avoided. Listing 14.3 illustrates the implementation of the <TT>IUnknown</TT> interface
in the <TT>COBass</TT> class.
<H3><A NAME="Heading8"></A>Listing 14.3<SPACER TYPE="HORIZONTAL" SIZE="10"> COBASS.CPP--IUnknown
Implementation for COBass</H3>
<P><FONT COLOR="#0066FF"><TT>#include <windows.h><BR>
#include <ole2.h><BR>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -