📄 ch13.htm
字号:
<OL>
<LI>Select the <U>N</U>ew command from the <U>F</U>ile menu in the Visual C++ development
environment.
<P>
<LI>From the New dialog, select the Projects tab.
<P>
<LI>From the Projects tab, select the ATL COM AppWizard (see fig. 13.1).
<P><A HREF="Art/13/jfig01.jpg"><B>FIG. 13.1</B></A> <I><BR>
Select the ActiveX Template Library COM AppWizard to create an ATL-based COM server.</I><BR>
<LI>Enter the name of the project in the Name edit box. For this project, enter the
name <B>AtlCustomBass</B>. Then click the OK button.
<P><BR>
The ATL COM AppWizard is presented in Figure 13.2.<BR>
<BR>
<A HREF="Art/13/jfig02.jpg"><B>FIG. 13.2</B></A> <I><BR>
Choose the COM object options by using the ATL COM AppWizard.</I><BR>
<LI>Select the type of COM server to create. The AtlCustomBass project is created
as a DLL. It is good practice to select the option "Allow merging of _proxy/stub
code" (AtlCustomBass selects this option). The stub code option provides parameter
marshalling for the objects. If your server needs to support MFC, select the option
Support <U>M</U>FC. Click the <U>F</U>inish button to create the ATL COM server.
A New Project Information dialog is displayed (see fig. 13.3). Click OK, and the
project is automatically created.
</OL>
<P><A HREF="Art/13/jfig03.jpg"><B>FIG. 13.3</B></A> <BR>
<I>The New Project Information dialog box recaps the ATL COM server options.</I></P>
<P>After creating the project, a COM object needs to be added to the project. To
add a COM object, perform the following steps:
<OL>
<LI>Select the <U>N</U>ew Class command from the <U>I</U>nsert menu of the Visual
C++ development environment. The New Class dialog is displayed, as shown in Figure
13.4.
<P><A HREF="Art/13/jfig04.jpg"><B>FIG. 13.4</B></A> <I><BR>
Use the New Class dialog box to create COM classes.</I></P>
<LI>Select ATL Class from the Class <U>t</U>ype drop-down list. Selecting ATL Class
means that the new class will be derived from the ATL framework.
<P>
<LI>Type <B>AtlCustomBass1</B> in the <U>N</U>ame edit box.
<P>
<LI>Select the Cu<U>s</U>tom Interface type radio button. There are two interface
type choices:
<UL>
<P>
<LI>Dual Interface--Derives the COM interfaces within the server from the <TT>IDispatch</TT>
interface used for OLE automation.
<P>
<LI>Custom Interface--Derives the COM interfaces from the <TT>IUnknown</TT> interface.
If OLE automation is not needed, this is the recommended interface.
</UL>
<P>
<LI>Specify 2 (two) in the N<U>u</U>mber of interfaces edit box. This setting determines
how many interfaces the COM object will contain. The New Class dialog imposes a limit
of 3. Again, this limit is imposed by the dialog, <I>not </I>the ATL library. The
A<TT>tlCustomBass</TT> project will contain two interfaces (<TT>IFish</TT> and <TT>IBass</TT>)
in the object.
<P>
<LI>Select the <U>E</U>dit button to change the default interface names. The Edit
Interface Information dialog shown in Figure 13.5 is displayed.
<P><A HREF="Art/13/jfig05.jpg"><B>FIG. 13.5</B></A> <I><BR>
The interface names can be changed from the Edit Interface Information dialog.</I></P>
<LI>To change the names of the interfaces, click each interface shown in the Interface
Na<U>m</U>es list. The <TT>CAtlCustonBass1</TT> class supports the <TT>IFish</TT>
and <TT>IBass</TT> interfaces. Enter <B>IFish</B> and <B>IBass</B> in the Interface
Na<U>m</U>es list. Click the OK button when finished.
<P>
<LI>Click the OK button in the New Class dialog box to create the class.
</OL>
<P>All the templates for the ATL COM server are now created. What remains is for
the server's specific implementations to be incorporated. Before performing the customizations,
you need to examine the results created by the ATL COM AppWizard.
<H3><A NAME="Heading10"></A>Examining the Results of the ATL COM Wizard</H3>
<P>A total of 11 files were created when the ATL COM AppWizard and New Class dialogs
were used to create the ATLCustomBass project. Table 13.1 shows the filenames and
purpose of each file created.
<TABLE BORDER="1" WIDTH="100%">
<CAPTION><B>Table 13.1</B><SPACER TYPE="HORIZONTAL" SIZE="10"><B> Files Created for the AtlCustomBass
Project</B></CAPTION>
<TR ALIGN="LEFT" rowspan="1">
<TD ALIGN="LEFT" VALIGN="TOP"><B>Filename</B></TD>
<TD ALIGN="LEFT" VALIGN="TOP"><B>Purpose</B></TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD ALIGN="LEFT" VALIGN="TOP">Stdafx.cpp</TD>
<TD ALIGN="LEFT" VALIGN="TOP">Contains the includes needed globally for the project. This usually generates precompiled
headings used by all other c or cpp files.</TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD ALIGN="LEFT" VALIGN="TOP">AtlCustomBass.cpp</TD>
<TD ALIGN="LEFT" VALIGN="TOP">Contains the COM server entry point implementations and COM class registration function.</TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD ALIGN="LEFT" VALIGN="TOP">AtlBass1.cpp</TD>
<TD ALIGN="LEFT" VALIGN="TOP">Skeleton cpp file for the <TT>AtlCustomBass</TT> COM object. All class and interface
implementations are placed in this file.</TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD ALIGN="LEFT" VALIGN="TOP">AtlCustomBass.def</TD>
<TD ALIGN="LEFT" VALIGN="TOP">Export definition file for the COM object server.</TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD ALIGN="LEFT" VALIGN="TOP">AtlCustomBassps.def</TD>
<TD ALIGN="LEFT" VALIGN="TOP">Export definition file for the interface library. The interface library is used for
generating proxy code for parameter marshaling.</TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD ALIGN="LEFT" VALIGN="TOP">AtlBass1.h</TD>
<TD ALIGN="LEFT" VALIGN="TOP"><TT>AtlCustomBass</TT> COM object definition file.</TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD ALIGN="LEFT" VALIGN="TOP">AtlCustomBass.idl</TD>
<TD ALIGN="LEFT" VALIGN="TOP"><TT>AtlCustomBass</TT> COM class and interface IDL definitions.</TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD ALIGN="LEFT" VALIGN="TOP">Resource.h</TD>
<TD ALIGN="LEFT" VALIGN="TOP">Standard resource file used for icons, version information, and so on.</TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD ALIGN="LEFT" VALIGN="TOP">Stdafx.h</TD>
<TD ALIGN="LEFT" VALIGN="TOP">Wrapper include file that includes all needed ATL header files.</TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD ALIGN="LEFT" VALIGN="TOP">Atlcustombassps.mk</TD>
<TD ALIGN="LEFT" VALIGN="TOP">Makefile used for compiling the interface definition file. This file produces the
parameter marshaling code for the COM interfaces.</TD>
</TR>
</TABLE>
<BR>
<BR>
As you can see, the AppWizard and New Class dialog have been busy on your behalf
creating the templates necessary for creating COM objects. You now need to implement
the actual interfaces.
<H3><A NAME="Heading11"></A>Implementing the COM Server Access Functions</H3>
<P><A HREF="ch12.htm">Chapter 12</A> includes information about several access functions
that must be exported from the COM server. These functions are accessed by the COM
libraries to load, unload, and register the objects within the server. These functions
are shown in the definition file for the <TT>CAtlCustomBass</TT> server (see Listing
13.1).
<H3><A NAME="Heading12"></A>Listing 13.1 AtlCustomBass.def--Library Definition File
for CAtlCustomBass</H3>
<P><FONT COLOR="#0066FF"><TT>; AltCustomBass.def : Declares the module parameters.
<BR>
LIBRARY ALTCUSTOMBASS.DLL <BR>
EXPORTS <BR>
DllCanUnloadNow @1 PRIVATE <BR>
DllGetClassObject @2 PRIVATE <BR>
DllRegisterServer @3 PRIVATE <BR>
DllUnregisterServer @4 PRIVATE </TT></FONT></P>
<P>The ATL library provides all of the necessary code for implementing the DLL access
functions. For the <TT>CAtlCustomBass</TT> project, these functions are implemented
in the file (see Listing 13.2).
<H3><A NAME="Heading13"></A>Listing 13.2 AtlCustomBass.cpp--ATL Implementation of
DLL Access Functions for COM Server</H3>
<P><FONT COLOR="#0066FF"><TT>#include "stdafx.h" <BR>
#include "resource.h" <BR>
#include "initguid.h" <BR>
#include "AltCustomBass.h" <BR>
#include "AltCustomBass1.h" <BR>
#include "dlldatax.h" <BR>
#define IID_DEFINED <BR>
#include "AltCustomBass_i.c" <BR>
#ifdef _MERGE_PROXYSTUB <BR>
extern "C" HINSTANCE hProxyDll; <BR>
#endif <BR>
CComModule _Module; <BR>
BEGIN_OBJECT_MAP(ObjectMap) <BR>
OBJECT_ENTRY(CLSID_CAltCustomBass1, CAltCustomBass1) <BR>
END_OBJECT_MAP() <BR>
///////////////////////////////////////////////////////////////////////////// <BR>
// DLL Entry Point <BR>
extern "C" <BR>
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) <BR>
{ <BR>
lpReserved; <BR>
#ifdef _MERGE_PROXYSTUB <BR>
if (!PrxDllMain(hInstance, dwReason, lpReserved)) <BR>
return FALSE; <BR>
#endif <BR>
if (dwReason == DLL_PROCESS_ATTACH) <BR>
{ <BR>
_Module.Init(ObjectMap, hInstance); <BR>
DisableThreadLibraryCalls(hInstance); <BR>
} <BR>
else if (dwReason == DLL_PROCESS_DETACH) <BR>
_Module.Term(); <BR>
return TRUE; // ok <BR>
} <BR>
///////////////////////////////////////////////////////////////////////////// <BR>
// Used to determine whether the DLL can be unloaded by OLE <BR>
STDAPI DllCanUnloadNow(void) <BR>
{ <BR>
#ifdef _MERGE_PROXYSTUB <BR>
if (PrxDllCanUnloadNow() != S_OK) <BR>
return S_FALSE; <BR>
#endif <BR>
return (_Module.GetLockCount()==0) ? S_OK : S_FALSE; <BR>
} <BR>
///////////////////////////////////////////////////////////////////////////// <BR>
// Returns a class factory to create an object of the requested type <BR>
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) <BR>
{ <BR>
#ifdef _MERGE_PROXYSTUB <BR>
if (PrxDllGetClassObject(rclsid, riid, ppv) == S_OK) <BR>
return S_OK; <BR>
#endif <BR>
return _Module.GetClassObject(rclsid, riid, ppv); <BR>
} <BR>
///////////////////////////////////////////////////////////////////////////// <BR>
// DllRegisterServer - Adds entries to the system registry <BR>
STDAPI DllRegisterServer(void) <BR>
{ <BR>
#ifdef _MERGE_PROXYSTUB <BR>
HRESULT hRes = PrxDllRegisterServer(); <BR>
if (FAILED(hRes)) <BR>
return hRes; <BR>
#endif <BR>
// registers object, typelib and all interfaces in typelib <BR>
return _Module.RegisterServer(TRUE); <BR>
} <BR>
///////////////////////////////////////////////////////////////////////////// <BR>
// DllUnregisterServer - Removes entries from the system registry <BR>
STDAPI DllUnregisterServer(void) <BR>
{ <BR>
#ifdef _MERGE_PROXYSTUB <BR>
PrxDllUnregisterServer(); <BR>
#endif <BR>
_Module.UnregisterServer(); <BR>
return S_OK; <BR>
}</TT></FONT></P>
<H3><A NAME="Heading14"></A>Using IDL to Create Object Definitions</H3>
<P>All COM classes and interfaces are defined through IDL, the Interface Definition
Language. IDL is also used in the creation of RPC interfaces and Automation interfaces.
When the AtlCustomBass project was created, the COM AppWizard generated the file
AtlCustomBass.idl. This file contains template structures for the COM class and interfaces
specified when running the AppWizard. All methods for the custom interfaces must
be added to this file. Listing 13.3 illustrates the contents of AtlCustomBass.idl
with the methods for custom interface IFish and IBass.
<H3><A NAME="Heading15"></A>Listing 13.3 AtlCustomBass.idl--Adding Custom Interface
Methods to the Project Interface Definition File</H3>
<P><FONT COLOR="#0066FF"><TT>import "unknwn.idl"; <BR>
#define MAX_FISH_BSTR_LEN 255 <BR>
typedef [string] WCHAR FISH_BSTR[MAX_FISH_BSTR_LEN]; <BR>
// This file will be processed by the MIDL tool to <BR>
// produce the type library (AltCustomBass.tlb) and marshalling code. <BR>
[ <BR>
object, <BR>
uuid(F3C2DDA2-7434-11D0-B6FC-00008607092E), <BR>
helpstring("IFish Interface"), <BR>
pointer_default(unique) <BR>
] <BR>
interface IFish : IUnknown <BR>
{ <BR>
import "oaidl.idl"; <BR>
HRESULT IsFreshwater([out] BOOL *pBool); <BR>
HRESULT GetFishName([out, string] FISH_BSTR p); <BR>
}; <BR>
[ <BR>
object, <BR>
uuid(F3C2DDA3-7434-11D0-B6FC-00008607092E), <BR>
helpstring("IFish Interface"), <BR>
pointer_default(unique) <BR>
] <BR>
interface IBass : IUnknown <BR>
{ <BR>
import "oaidl.idl"; <BR>
HRESULT GetLocation([out, string] FISH_BSTR p); <BR>
HRESULT SetLocation([in, string] FISH_BSTR p); <BR>
HRESULT EatsOtherFish([out] BOOL *pBool); <BR>
}; [ <BR>
uuid(F3C2DDA0-7434-11D0-B6FC-00008607092E), <BR>
version(1.0), <BR>
helpstring("AltCustomBass 1.0 Type Library") <BR>
] <BR>
library ALTCUSTOMBASSLib <BR>
{ <BR>
importlib("stdole32.tlb"); <BR>
[ <BR>
uuid(F3C2DDA6-7434-11D0-B6FC-00008607092E), <BR>
helpstring("AltCustomBass1 Class") <BR>
] <BR>
coclass CAltCustomBass1 <BR>
{ <BR>
[default] interface IFish; <BR>
interface IBass; <BR>
}; }; </TT></FONT></P>
<P>In the IDL file for <TT>AtlCustomBass</TT> are definitions for two interfaces,
<TT>IFish</TT> and <TT>IBass</TT>, and the COM class, <TT>CAltBass1</TT>. As you
can see from Listing 13.3, both the <TT>IFish</TT> and <TT>IBass</TT> interfaces
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -