📄 ch12.htm
字号:
are a few differences between in-process servers and out-of-process servers.
<UL>
<LI>An in-process server typically provides better load time performance. COM Object
load time is faster with an in-process server due to the COM Object being contained
in a DLL. DLLs typically load faster than executables.
<P>
<LI>COM Objects in an in-process server also execute faster because parameter marshaling
does not need to occur when passing information from the calling application to the
COM Object.
</UL>
<P><IMG SRC="bar.gif" WIDTH="480" HEIGHT="6" ALIGN="BOTTOM" BORDER="0"></P>
<BLOCKQUOTE>
<P><B>CAUTION:</B><BR>
If DCOM is in your development plans, you have one detriment to in-process servers:
DCOM or the Distributed Component Object Model allows components to reside on other
computers in your network environment. This feature allows the components to utilize
the processing power of other workstations. If you are planning for DCOM, you must
implement your COM Objects as out-of-process servers because DLLs cannot be used
across machine boundaries.
</BLOCKQUOTE>
<P><IMG SRC="bar.gif" WIDTH="480" HEIGHT="6" ALIGN="BOTTOM" BORDER="0">
<H3><A NAME="Heading22"></A>Using the Visual C++ AppWizard to Create the COM Object</H3>
<P>Nothing special is needed to create a basic <I>application </I>for containing
your COM Objects. The application is where the COM interface definitions are implemented.
With this in mind, you can create a basic COM Object application. In this section,
you will create a COM Object using an MFC DLL (in-process server) as the containing
application. During creation of the application, the differences between creating
an in-process and out-of-process server will be pointed out. <BR>
<BR>
<IMG SRC="bar.gif" WIDTH="480" HEIGHT="6" ALIGN="BOTTOM" BORDER="0"></P>
<BLOCKQUOTE>
<P><B>NOTE:</B> The differences between an in-process and out-of-process server are
trivial at this point because the interface DLL already contains the proxy code used
for parameter marshaling. The determination to have an in-process server versus an
out-of-process server depends on the use and needs of the COM Object.
</BLOCKQUOTE>
<P><IMG SRC="bar.gif" WIDTH="480" HEIGHT="6" ALIGN="BOTTOM" BORDER="0"><BR>
<BR>
To create the basic application, perform the following steps:
<OL>
<LI>In the Visual C++ development environment, select the <U>N</U>ew command from
the <U>F</U>ile menu.
<P>
<LI>From the Projects tab on the New dialog, select MFC AppWizard (dll). (See fig.
12.7.) Enter the project name into the Project <U>n</U>ame edit box. This project
is called BASS. Select the OK button.
<P><A HREF="Art/12/ifig07.jpg"><B>FIG. 12.7</B></A> <I><BR>
Name the COM Object in the New Project Workspace dialog.<BR>
<BR>
<IMG SRC="bar.gif" WIDTH="430" HEIGHT="6" ALIGN="BOTTOM" BORDER="0" VSPACE="5"></I><B><BR>
NOTE:</B> When creating an out-of-process server, select the MFC AppWizard (exe)
item in the New Project tab.<IMG SRC="bar.gif" WIDTH="430" HEIGHT="6" ALIGN="BOTTOM"
BORDER="0" VSPACE="5">
<LI>From the MFC AppWizard dialog, select <U>R</U>egular DLL with MFC statically
linked or select Regular <U>D</U>LL using shared MFC DLL (see fig. 12.8), depending
on your needs. Also select the A<U>u</U>tomation option in the MFC AppWizard dialog.
The A<U>u</U>tomation option will cause the AppWizard to insert start-up and exit
code used for both OLE Automation Servers and COM Objects. Select the <U>F</U>inish
button when completed. The New Project Information dialog will confirm your choices
(see fig. 12.9).
</OL>
<P><A HREF="Art/12/ifig08.jpg"><B>FIG. 12.8</B></A> <I><BR>
Choose your project build options.</I></P>
<P><A HREF="Art/12/ifig09.jpg"><B>FIG. 12.9</B></A> <I><BR>
Recap the project selections in the New Project Information dialog.</I></P>
<P><IMG SRC="bar.gif" WIDTH="480" HEIGHT="6" ALIGN="BOTTOM" BORDER="0"></P>
<BLOCKQUOTE>
<P><B>TIP:</B> Your COM Objects will be easier to distribute if you use the static-linked
version of MFC. If your COM Objects are part of a project that contains other MFC
components and applications, you will get better performance by using the DLL version
of MFC.
</BLOCKQUOTE>
<P><IMG SRC="bar.gif" WIDTH="480" HEIGHT="6" ALIGN="BOTTOM" BORDER="0"><BR>
<BR>
At this point, you have a basic shell application that can be used for your COM Objects.
<H3><A NAME="Heading23"></A>Accessing In-Process COM Objects</H3>
<P>In-process servers contain two functions that serve as entry points for clients
accessing COM Objects. These functions are <TT>DllGetClassObject</TT> and <TT>DllCanUnloadNow</TT>.
These functions are not needed for EXE or out-of-process servers.</P>
<P>In order for the COM support functions to be accessed, the functions must be exported
from the DLL. An exported function can be called from any Windows application. The
COM support functions are defined in MFC but are implemented in the server DLL. These
support functions are also exported through the definition file (.DEF) of the DLL
that uses the functions--in this case, BASS DLL. The AppWizard has already created
a DEF file entitled BASS.DEF (see Listing 12.6).
<H3><A NAME="Heading24"></A>Listing 12.6<SPACER TYPE="HORIZONTAL" SIZE="10"> BASS.DEF--BASS
Definition File with the COM Support Functions Explicitly Exported</H3>
<P><FONT COLOR="#0066FF"><TT>; BASS.def : Declares the module parameters for the
DLL. <BR>
LIBRARY "BASS" <BR>
DESCRIPTION `FISH Windows Dynamic Link Library' <BR>
EXPORTS <BR>
; Explicit exports can go here <BR>
DllCanUnloadNow PRIVATE <BR>
DllGetClassObject PRIVATE <BR>
DllRegisterServer PRIVATE</TT></FONT></P>
<PRE><FONT COLOR="#0066FF"><TT></TT></FONT></PRE>
<P><IMG SRC="bar.gif" WIDTH="480" HEIGHT="6" ALIGN="BOTTOM" BORDER="0"></P>
<BLOCKQUOTE>
<P><B>NOTE:</B> The BASS definition file and the three support functions needed for
accessing COM Objects were automatically inserted by the MFC Application Wizard as
a result of selecting the OLE Automation option for the project. Automation and COM
Objects are accessed in in-process servers through the same support functions. If
OLE Automation was <I>not</I> selected, these functions will have to be implemented
manually.
</BLOCKQUOTE>
<P>
<HR>
Each of the COM support functions are explained in the following three sections.
<B><I><BR>
<BR>
HRESULT DllGetClassObject (REFCLSID rclsid</I>, <I>REFIID riid</I>, <I>LPVOID *ppv)</I>
</B><SPACER TYPE="HORIZONTAL" SIZE="10">When a user requests a given COM Object,
the Component Object Library looks into the Windows registry for the <TT>InProcServer</TT>
of the given <TT>CLSID</TT>. The DLL that implements the COM Object is then loaded
into memory, and the function <TT>DllGetClassObject</TT> is called. The <TT>CLSID</TT>
of the COM Object implementing the interface and <TT>IID</TT> of the interface the
user is requesting are passed into the function. The DLL containing the COM Object
then creates the appropriate class factory for the <TT>CLSID</TT> and returns the
corresponding interface pointer for the <TT>IID</TT>. Since a <TT>CLSID</TT> is passed
into <TT>DllGetClassObject</TT>, a DLL can contain many different COM Objects. The
interface pointer is returned to the caller through the parameter <TT>ppv</TT>.</P>
<P>The MFC AppWizard inserts all of the code needed for accessing COM Objects in
an MFC Application DLL. The code for <TT>DllGetClassObjects</TT> is shown in Listing
12.7.
<H3><A NAME="Heading25"></A>Listing 12.7<SPACER TYPE="HORIZONTAL" SIZE="10"> BASS.CPP--DLlGetClassObject
Implementation Code Inserted by the MFC AppWizard</H3>
<P><FONT COLOR="#0066FF"><TT>STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid,
LPVOID* ppv) <BR>
{ <BR>
AFX_MANAGE_STATE(AfxGetStaticModuleState()); <BR>
return AfxDllGetClassObject(rclsid, riid, ppv); <BR>
} </TT></FONT></P>
<P><B><I>STDAPI DllCanUnloadNow(void)</I></B> <SPACER TYPE="HORIZONTAL" SIZE="10">Since
the client application using the COM Object does not link directly with the server
creating the COM Object, an unload mechanism must be in place so that unneeded COM
Objects are removed from memory. With in-process servers, this mechanism is through
the function <TT>DllCanUnloadNow</TT>. The Component Object Library periodically
asks each COM Object server if it can be unloaded from memory. If the server returns
<TT>S_OK</TT>, the server DLL is removed from memory. A COM Object server returns
<TT>S_OK</TT> when clients have finished using the COM Objects. The function <TT>DllCanUnloadNow</TT>
is shown in Listing 12.8.</P>
<P>An EXE server does not need to implement the function <TT>DllCanUnloadNow</TT>
because an EXE can keep track of how many users it has. When the usage count reaches
0, the EXE can unload itself from memory.
<H3><A NAME="Heading26"></A>Listing 12.8 <SPACER TYPE="HORIZONTAL" SIZE="10">DLLCanUnloadNow--Implementation
Code Inserted by the MFC AppWizard</H3>
<P><FONT COLOR="#0066FF"><TT>STDAPI DllCanUnloadNow(void) <BR>
{ <BR>
AFX_MANAGE_STATE(AfxGetStaticModuleState()); <BR>
return AfxDllCanUnloadNow(); <BR>
}</TT></FONT></P>
<PRE><FONT COLOR="#0066FF"><TT></TT></FONT></PRE>
<P><B><I>BOOL DllRegisterServer(void)</I></B><SPACER TYPE="HORIZONTAL" SIZE="10"><B>
</B>The function <TT>DllRegisterServer</TT> is a useful method for having the COM
Object server correctly register with the Windows registry. When this function is
called, the COM Object server updates the Windows registry with the settings necessary
for client applications to use the server.</P>
<P>The ActiveX development kit has a tool called regsvr32.exe. This program can be
run with two parameters. The first parameter is the DLL to register. The second parameter
is <TT>TRUE</TT> (for registering a server) or <TT>FALSE</TT> for unregistering a
server. To register the BASS COM server, run <TT>regsvr32</TT><B> </B>with the following
parameters:</P>
<P><FONT COLOR="#0066FF"><TT>regsvr32 BASS.DLL TRUE</TT></FONT>
<H3><A NAME="Heading27"></A>Listing 12.9 <SPACER TYPE="HORIZONTAL" SIZE="10">DllRegisterServer--Implementation
Code Inserted by the MFC AppWizard</H3>
<P><FONT COLOR="#0066FF"><TT>// by exporting DllRegisterServer, you can use regsvr.exe
<BR>
STDAPI DllRegisterServer(void) <BR>
{ <BR>
AFX_MANAGE_STATE(AfxGetStaticModuleState()); <BR>
COleObjectFactory::UpdateRegistryAll(); <BR>
return S_OK; <BR>
}</TT></FONT></P>
<PRE><FONT COLOR="#0066FF"><TT></TT></FONT></PRE>
<H3><A NAME="Heading28"></A>Creating a Class that Implements COM Interfaces</H3>
<P>Now that the application that will contain the COM Class has been created, the
COM Class needs to be added to the project. The Visual C++ ClassWizard will be used
to implement this class. The class name being created is <TT>CBass</TT>. To create
the <TT>CBass</TT> class, perform the following steps:
<OL>
<LI>Select the Class<U>W</U>izard command from the <U>V</U>iew menu of the Visual
C++ development environment. The ClassWizard dialog will appear as shown in Figure
12.10.
<P>
<LI>Select the Add C<U>l</U>ass button, and then select the new option. The New Class
dialog appears (see fig. 12.11).
</OL>
<P><A HREF="Art/12/ifig11.jpg"><B>FIG. 12.11</B></A> <BR>
<I>Set the class options with the New Class dialog.</I></P>
<OL>
<LI>Enter the class name <B>CBass</B> in the <U>N</U>ame edit box.
<P>
<LI>Select the base class <TT>CCmdTarget</TT> from the <U>B</U>ase class drop-down
list.
<P>
<LI>Select the Create button. The Class <TT>CBass</TT> is now part of the BASS project.
</OL>
<P>The class <TT>CCmdTarget</TT> is chosen as the base class because MFC provides
a standard implementation of the <TT>IUnknown</TT> interface in this class. As you
have seen, the <TT>IUnknown</TT> interface provides the three basic methods that
<I>must </I>be supported by all COM Objects.</P>
<P>Deriving from the <TT>CCmdTarget</TT> base class also allows the object to be
created through the MFC class <TT>COleObjectFactory</TT>. The class <TT>COleObjectFactory</TT>
is called through the DLL entry point, <TT>DllGetClassObject</TT>. If the COM class
was not derived from a class with <TT>CCmdTarget</TT> as its base, special object
creation code must be written in the function <TT>DllGetClassObject</TT> to create
an instance of the object. <BR>
<BR>
<IMG SRC="bar.gif" WIDTH="480" HEIGHT="6" ALIGN="BOTTOM" BORDER="0"></P>
<BLOCKQUOTE>
<P><B>NOTE:</B> Even though <TT>CCmdTarget</TT> was selected as the base class for
the <TT>CBass</TT> class, any of the other classes derived from <TT>CCmdTarget</TT>
can be used. If a class <I>not </I>derived from <TT>CCmdTarget</TT> is used, you
<I>must </I>manually provide support for the <TT>IUnknown</TT> interface.
</BLOCKQUOTE>
<P><IMG SRC="bar.gif" WIDTH="480" HEIGHT="6" ALIGN="BOTTOM" BORDER="0"><BR>
<BR>
Figure 12.12 illustrates the <TT>CBass</TT> class and the interfaces that will be
encapsulated within this class. <B><BR>
<BR>
</B><A HREF="Art/12/ifig12.jpg"><B>FIG. 12.12</B></A> <I><BR>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -