📄 ch12.htm
字号:
or if the ActiveX SDK is installed.
<H3><A NAME="Heading8"></A>Adding the Tools to the Visual C++ Development Environment</H3>
<P>In order to maximize development productivity, the tools needed for COM programming
should be integrated into the Visual C++ environment. Each of the tools needed can
be added to the IDEs (Integrated Development Environment) <U>T</U>ools menu. The
following sections illustrate how to incorporate the tools into the IDE. <B><BR>
<BR>
Adding the MIDL Compiler to the IDE </B><SPACER TYPE="HORIZONTAL" SIZE="10">Adding
the MIDL compiler to the IDE allows for easy compilation of an IDL (Interface Definition
Language) file. After adding this command, an IDL file can be compiled, and the MIDL
compiler will generate a C source file with all appropriate parameter marshaling
code. To add the MIDL compiler to the Visual C++ environment:
<OL>
<LI>Select the <U>C</U>ustomize command from the <U>T</U>ools menu. Select the Tools
tab from the Customize dialog.
<P>
<LI>In the <U>C</U>ommand edit box, type <B>MIDL.EXE</B>.
<P>
<LI>In the <U>M</U>enu contents edit box, type <B>Compile &IDL File</B>.
<P>
<LI>In the Argume<U>n</U>ts edit box, type <B>/ms_ext /char unsigned /c_ext $FileName</B>.
<P>
<LI>In the <U>I</U>nitial directory edit box, type <B>$FileDir</B>.
<P>
<LI>Click the check box <U>U</U>se Output Window (the box should already be checked).
<P>
<LI>In the completed Customize dialog, click the Close button to add the entry to
the <U>T</U>ools menu (see fig. 12.3).
</OL>
<P><A HREF="Art/12/ifig03.jpg"><B>FIG. 12.3</B></A> <BR>
<I>Add your tools settings for the MIDL compiler in the Customize dialog.</I></P>
<P><B>Adding <I>GUIDGEN</I> </B><SPACER TYPE="HORIZONTAL" SIZE="10">Adding <TT>GUIDGEN</TT>
to the Visual C++ environment enables the generation of a <TT>UUID</TT> from a single
menu command. As stated earlier, the generated <TT>UUID</TT> is placed in the Windows
Clipboard and must be pasted into the project code. To add <TT>GUIDGEN</TT> to the
Visual C++ development environment:
<OL>
<LI>Select the <U>C</U>ustomize command from the <U>T</U>ools menu. Select the Tools
tab from the Customize dialog.
<P>
<LI>In the <U>C</U>ommand edit box, type <B>GUIDGEN.EXE</B>.
<P>
<LI>In the <U>M</U>enu contents edit box, type <B>&Generate New UUID</B>.
<P>
<LI>Clear all text from the Argume<U>n</U>ts edit box.
<P>
<LI>Clear all text from the <U>I</U>nitial Directory edit box.
<P>
<LI>Click the Close button to add the entry to the <U>T</U>ools menu.
</OL>
<P><B>Adding the Registry Editor </B><SPACER TYPE="HORIZONTAL" SIZE="10">The Registry
Editor serves two purposes: to add registration information to the Windows registry
and to browse the registry to view information. To add the Registry Editor to the
Visual C++ environment, follow these steps:
<OL>
<LI>Select the <U>C</U>ustomize command from the <U>T</U>ools menu. Select the Tools
tab from the Customize dialog.
<P>
<LI>In the <U>C</U>ommand edit box, type <B>REGEDIT.EXE</B> if the development platform
is Windows 95. Type <B>REGEDT32.EXE</B> if the development platform is Windows NT.
<P>
<LI>In the <U>M</U>enu contents edit box, type <B>&Registry Editor</B>.
<P>
<LI>Clear all text from the Argume<U>n</U>ts edit box.
<P>
<LI>In the <U>I</U>nitial directory edit box, type <B>$FileDir</B>.
<P>
<LI>Click the Close button to add the entry to the <U>T</U>ools menu.
</OL>
<P><B>Adding the Registration Server</B><SPACER TYPE="HORIZONTAL" SIZE="10"><B> </B>If
the ActiveX Control option was selected during the Visual C++ installation, the registration
server is already installed as the Regis<U>t</U>er Control command from the <U>T</U>ools
menu. If you have not installed the ActiveX Control option, installing it now adds
the appropriate files and menu items to the Visual C++ development environment.
<H2><A NAME="Heading9"></A>Defining COM Interfaces Using IDL</H2>
<P>A <I>COM interface </I>is a group of functions used to manipulate the data of
the class that is implementing the interface. Interfaces only <I>define</I> the functions
that belong to the group. An interface does not implement the function or contain
data. The function implementation and data belong to the class that implements the
interface.</P>
<P>ActiveX is based entirely on a set of COM interfaces. These COM interfaces are
a standard part of the operating system. In other words, Windows 95 and Windows NT
contain all of the code that implement the ActiveX COM interfaces.</P>
<P>When building new components based on COM, these components define <I>custom</I>
interfaces. A custom interface is an interface that is not already supported by the
operating system. A custom interface contains a set of functions that are specific
to the new component being built. For example, a spell-checker component may contain
a custom interface that contains a set of functions used by a program that uses the
spell-checker component. Once an interface is defined, multiple components may be
built that support and implement the interface.</P>
<P>Going back to the spell-checker component, a defined spell-checker interface may
be implemented by multiple companies. Having multiple companies provide a component
with the same interface gives application developers the flexibility to have all
of the components exist on a system, yet provide the user with the ability to load
and use a specific company's spelling checker.</P>
<P>When creating a custom interface, the interface definitions need to be shared
among multiple applications, such as the server that implements the interface and
the client that uses the interface. For this reason, it makes sense to define the
interfaces in a project separate from the server or client projects. Multiple interfaces
can be defined within a single project.</P>
<P>In this chapter, we develop three projects to implement and use COM Objects. Table
12.1 shows the project names and the purpose of each project. <BR>
<BR>
<TABLE BORDER="1" WIDTH="100%">
<CAPTION><B>Table 12.1</B><SPACER TYPE="HORIZONTAL" SIZE="10"><B> Chapter 12 Project Descriptions</B></CAPTION>
<TR ALIGN="LEFT" rowspan="1">
<TD ALIGN="LEFT" VALIGN="TOP"><B>Project Name</B></TD>
<TD ALIGN="LEFT" VALIGN="TOP"><B>Purpose</B></TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD ALIGN="LEFT" VALIGN="TOP">IFISH (IFISH.DLL)</TD>
<TD ALIGN="LEFT" VALIGN="TOP">Implements a COM interface definition.</TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD ALIGN="LEFT" VALIGN="TOP">BASS (BASS.DLL)</TD>
<TD ALIGN="LEFT" VALIGN="TOP">Contains an MFC class that implements the COM interfaces in IFISH.</TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD ALIGN="LEFT" VALIGN="TOP">COMTEST (COMTEST.EXE)</TD>
<TD ALIGN="LEFT" VALIGN="TOP">Sample Test application that uses the BASS COM Object.</TD>
</TR>
</TABLE>
<BR>
<BR>
The project IFISH defines two COM interfaces, the <TT>IFish</TT> interface and the
<TT>IBass</TT> interface. The <TT>IFish</TT> interface is a <I>base </I>class for
all of the different species of fish. The <TT>IBass</TT> interface is an interface
specific to a particular type of fish. Both of these interface definitions will be
implemented within the IFISH project.
<H3><A NAME="Heading10"></A>Creating the IFISH Project</H3>
<P>The IFISH project contains two COM interface definitions, <TT>IFish</TT> and <TT>IBass</TT>.
The project IFISH is implemented as a DLL. The DLL does not contain any MFC code
or written C\C++ code. The code contained within IFISH is produced by the MIDL compiler.
The MIDL compiler takes the interface definition files (IDL) as input and produces
C code for the interface as output. The C code that is produced is needed to implement
<I>parameter marshaling. </I>Parameter marshaling is needed if the COM interface
is implemented in an executable (EXE). The marshaling allows the parameters to be
passed across process boundaries.</P>
<P>Even if the COM interface implementation is in a DLL (in-process server), the
MIDL compiler should still be used. There are no penalties for implementing parameter
marshaling. <BR>
<BR>
<IMG SRC="bar.gif" WIDTH="480" HEIGHT="6" ALIGN="BOTTOM" BORDER="0"></P>
<BLOCKQUOTE>
<P><B>NOTE:</B> The IFISH project is built as a DLL. This is not the DLL that is
implementing the COM interface. IFISH contains only the interface definitions. Projects
that <I>contain</I> the interface definitions should be implemented as DLLs.
</BLOCKQUOTE>
<P><IMG SRC="bar.gif" WIDTH="480" HEIGHT="6" ALIGN="BOTTOM" BORDER="0"><BR>
<BR>
Perform the following steps in order to create the IFISH project:
<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>Select Dynamic Link Library (see fig. 12.4). Enter the project name into the
Project <U>n</U>ame edit box. The project is named IFISH. Select the OK button.
<P><A HREF="Art/12/ifig04.jpg"><B>FIG. 12.4</B></A> <I><BR>
Select the project attributes for IFISH in the New dialog.</I></P>
<LI>The project IFISH is now created.
</OL>
<H3><A NAME="Heading11"></A>Creating the Interface Definition</H3>
<P>When creating the interface definition, you must determine whether marshaling
code is needed to provide support for passing parameters between two processes. The
safest method is to always assume that marshaling is needed. Providing marshaling
support also allows the freedom to create either an in-process server (DLL) or an
out-of-process server (EXE) to implement the interface.</P>
<P>Use of the Microsoft RPC MIDL compiler provides parameter marshaling support.
Parameter marshaling is automatically provided by defining the COM interface with
the <I>Interface Definition Language</I> (IDL). Once the interface is defined using
IDL, the RPC MIDL compiler automatically generates the code necessary for marshaling
support.</P>
<P>Two interface definition files are used in the IFISH project, IFISH.IDL and IBASS.IDL
(see Listing 12.1).
<H3><A NAME="Heading12"></A>Listing 12.1 <SPACER TYPE="HORIZONTAL" SIZE="10">IFISH.IDL--Interface
Definition for IFish</H3>
<P><FONT COLOR="#0066FF"><TT>[ <BR>
object, <BR>
uuid(011BB310-5AB0-11d0-907E-00A0C91FDE82), <BR>
pointer_default(unique) <BR>
] <BR>
interface IFish : IUnknown <BR>
{ <BR>
import "unknwn.idl"; <BR>
HRESULT IsFreshwater([out] BOOL *pBool); <BR>
HRESULT GetFishName([out, string, size_is(255)] char *p); } </TT></FONT></P>
<P>All interface definition files have the extension IDL. The first portion of the
IDL file contains an object definition section. The most important part of this section
is the <TT>UUID</TT> of the object. The <TT>UUID</TT> is a unique 128-bit number
that is created through the tool <TT>GUIDGEN</TT>. The <TT>UUID</TT> in IFISH.IDL
distinctly identifies the <TT>IFish</TT> COM interface definition. This number is
used by applications that will use the <TT>IFish</TT> interface.</P>
<P>A unique <TT>UUID</TT> number can be generated by performing the following steps:
<OL>
<LI>From the Visual C++ development environment, select the command <U>G</U>enerate
New UUID, located under the <U>T</U>ools menu. (<I>Note: </I>This command was added
earlier to the <U>T</U>ools menu, as shown in the section "Adding GUIDGEN").
The Create GUID dialog is displayed (see fig. 12.5).
<P><A HREF="Art/12/ifig05.jpg"><B>FIG. 12.5</B></A> <I><BR>
Use the Create GUID dialog to generate unique identifiers for COM interfaces.</I></P>
<LI>From the dialog, under <TT>GUID</TT> Format, select Registry Format [i.e., {XXXXXXX-XXXX...XXXX}].
<P>
<LI>Select the <U>C</U>opy button. This option copies the new <TT>UUID</TT> into
the Windows Clipboard.
<P>
<LI>Select E<U>x</U>it to close the GUIDGEN dialog.
<P>
<LI>In the interface definition file, paste the contents of the Clipboard (that is,
the new <TT>UUID</TT>) into the <TT>UUID</TT> section of the IDL file. This is the
unique identifier used for your interface. If another <TT>GUID</TT> is needed, you
can press the <U>N</U>ew GUID button and then copy the second <TT>GUID</TT> from
the Clipboard.
</OL>
<P>Following the object definition section is the actual interface definition. As
shown in Listing 12.1, the object definition resembles a C++ class definition. The
keyword interface specifies the start of an interface definition. The name of the
interface and any inherited interfaces follows. In this case, the interface name
is <TT>IFish</TT>, and this interface inherits the <TT>IUnknown</TT> interface.</P>
<P>Since the <TT>IUnknown</TT> interface is a standard interface within the operating
system, you don't need to redefine the functions within the interface. You only need
to import the <TT>IUnknown</TT> interface definition. You do this through the statement
<TT>import "unknwn.idl";</TT>.</P>
<P>The functions implemented by the interface need to be added in order to complete
the interface definition. When using IDL, all portions of a function must be defined:
the return value and all parameters, including direction (<TT>in</TT>, <TT>out</TT>,
or both) and size of the parameters. Specifying all portions of a function allows
the MIDL compiler to generate the correct marshaling code for the interface. <BR>
<BR>
<IMG SRC="bar.gif" WIDTH="480" HEIGHT="6" ALIGN="BOTTOM" BORDER="0"></P>
<BLOCKQUOTE>
<P><B>NOTE:</B> All return values <I>must</I> be of type <TT>HRESULT</TT>, which
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -