📄 ch05.htm
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<!--last modified on Tue, Apr 15, 1997 10:01 AM-->
<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 5</TITLE>
</HEAD>
<BODY TEXT="#000000" BGCOLOR="#FFFFFF">
<H1>Chapter 5<BR>
Creating ActiveX Automation Servers Using BaseCtl</H1>
<UL>
<LI><A HREF="#Heading1">Creating ActiveX Automation Servers Using BaseCtl</A>
<UL>
<LI><A HREF="#Heading2">Creating the Basic Project</A>
<LI><A HREF="#Heading3">Registry</A>
<UL>
<LI><A HREF="#Heading4">Listing 5.1 TRACKER.H--Basic Registration Information in
the DEFINE_AUTOMATIONOBJECT Structure</A>
</UL>
<LI><A HREF="#Heading5">Sample Server Support Code</A>
<UL>
<LI><A HREF="#Heading6">Listing 5.2 TRACKER.H--Sample Server Support Code Added to
the Header File</A>
<LI><A HREF="#Heading7">Listing 5.3 TRACKER.CPP--Sample Server Support Code Added
to the Source File</A>
</UL>
<LI><A HREF="#Heading8">Adding Methods</A>
<UL>
<LI><A HREF="#Heading9">Listing 5.4 BCFSERVER.ODL--OutputLines Method ODL Declaration</A>
<LI><A HREF="#Heading10">Listing 5.5 TRACKER.H--OutputLines Function Prototype Added
to the Class Definition</A>
<LI><A HREF="#Heading11">Listing 5.6 TRACKER.CPP--Member Initialization in the Constructor</A>
<LI><A HREF="#Heading12">Listing 5.7 TRACKER.CPP--OutputLines Function Implementation
Added to the Source File Tracker.cpp</A>
</UL>
<LI><A HREF="#Heading13">Adding Properties</A>
<UL>
<LI><A HREF="#Heading14">Listing 5.8 BCFSERVER.ODL--Indent Property Added to the
ODL</A>
<LI><A HREF="#Heading15">Listing 5.9 TRACKER.H--Indent Property Function Prototypes
Added to the Class Definition</A>
<LI><A HREF="#Heading16">Listing 5.10 TRACKER.CPP--Indent Property Implementation</A>
</UL>
<LI><A HREF="#Heading17">Generating OLE Exceptions</A>
<UL>
<LI><A HREF="#Heading18">Listing 5.11 BCFSERVER.ODL--Error Enumeration in the ODL
File</A>
<LI><A HREF="#Heading19">Listing 5.12 TRACKER.CPP--Rich Error Information Added to
Tracker Implementation</A>
</UL>
<LI><A HREF="#Heading20">Dual-Interface</A>
<LI><A HREF="#Heading21">Generating Dual-Interface OLE Exceptions</A>
<LI><A HREF="#Heading22">Server Instantiation Using C++</A>
<UL>
<LI><A HREF="#Heading23">Listing 5.13 Example--Creating an OLE Server Using C++</A>
</UL>
<LI><A HREF="#Heading24">Shared Servers</A>
<UL>
<LI><A HREF="#Heading25">Listing 5.14 TRACKER.CPP--Create Function Implementation
of Shared Object Support</A>
<LI><A HREF="#Heading26">Listing 5.15 TRACKER.H--DECLARE_STANDARD_UNKNOWN_SHARED
Macro Implementation</A>
<LI><A HREF="#Heading27">Listing 5.16 TRACKER.H--New Macro</A>
</UL>
<LI><A HREF="#Heading28">Single Instance Servers</A>
<UL>
<LI><A HREF="#Heading29">Listing 5.17 TRACKER.CPP--Create Function Implementation
Updated to Support Single Instance Servers</A>
</UL>
<LI><A HREF="#Heading30">User Interface and Events</A>
<LI><A HREF="#Heading31">From Here...</A>
</UL>
</UL>
<P>
<HR SIZE="4">
<H1><A NAME="Heading1"></A>Creating ActiveX Automation Servers Using BaseCtl</H1>
<UL>
<LI><B>Server registration support</B>
<SPACER TYPE="VERTICAL" SIZE="2">
Like ATL, the basic BaseCtl framework allows registration and unregistration support
without additional code modification.
<P>
<LI><B>Adding methods and properties</B>
<SPACER TYPE="VERTICAL" SIZE="2">
The single greatest drawback in using BaseCtl is its lack of integration with the
VC++ IDE. Properties provide a uniform mechanism for getting and setting the state
of a server's data variables.
<P>
<LI><B>OLE exceptions</B>
<SPACER TYPE="VERTICAL" SIZE="2">
Unlike MFC, BaseCtl does not support OLE exceptions through a C++ exception class;
BaseCtl takes advantage of OLE error reporting mechanisms.
<P>
<LI><B>Dual-interface</B>
<SPACER TYPE="VERTICAL" SIZE="2">
BaseCtl servers implement dual-interface as a standard feature of the application.
<P>
<LI><B>Shared servers and single instance servers</B>
<SPACER TYPE="VERTICAL" SIZE="2">
Adding shared server support to the BaseCtl framework gives insights into how the
BaseCtl class factory is implemented.
</UL>
<P>The history of the BaseCtl framework has its roots in the Visual Basic (VB) group
where it was first developed. The single most unique thing about the BaseCtl Framework
is its lack of dependence on MFC, which was viewed by the VB team as a burden to
creating small and fast OCXs.</P>
<P>Several versions of the BaseCtl framework are floating around. The basic version
is the one that ships with the ActiveX SDK, consisting of a number of source files
and several samples. A more thorough version, consisting of more samples and even
an AppWizard written in VB, has been available to the members of the VB 5 beta testing
group for some time.</P>
<P>The BaseCtl framework is intended merely as a sample application and does not
have the same support and backing of Microsoft as do its other development products.</P>
<P>In addition to creating ActiveX Controls (see <A HREF="ch08.htm">Chapter 8</A>
for more information), the BaseCtl framework can be used to create ActiveX Automation
Servers, which are the focus of this chapter. Like ATL, the BaseCtl is not integrated
with the VC++ IDE and requires that all code be entered and modified by hand.</P>
<P>In this chapter, you will create a simple in-process Automation Server. As with
<A HREF="ch03.htm">Chapters 3</A> and <A HREF="ch04.htm">4</A>, your sample server
implementation will be used to log string data to a file.
<H2><A NAME="Heading2"></A>Creating the Basic Project</H2>
<P>Unfortunately, the BaseCtl framework that ships in the ActiveX SDK does not have
an AppWizard like its MFC and ATL counterparts. We have provided a sample project
based on the BaseCtl samples from which you can create new projects. The sample application
that we have created is a bare-bones project similar to the kind that would be generated
by an AppWizard. We've included our own sample application because the samples included
with the BaseCtl framework are already implemented with specific features and are
intended to demonstrate different aspects of BaseCtl development, whereas our sample
is meant as a starting point for your own component development.</P>
<P>To create a new project, you first need to define a new directory into which you
can copy the sample files; in this case, call the directory BCFServer. Copy all of
the files from the BCFBasicServer directory into your new directory, BCFServer. Rename
all of the files in the BCFServer directory as described in Table 5.1. The files
dispids.h, dwinvers.h, guids.cpp, guids.h, localobj.h, and resource.h will remain
as they are.
<TABLE BORDER="1" WIDTH="100%">
<CAPTION><B>Table 5.1 </B><SPACER TYPE="HORIZONTAL" SIZE="10"><B>New Filenames</B></CAPTION>
<TR ALIGN="LEFT" rowspan="1">
<TD WIDTH="138" ALIGN="LEFT" VALIGN="TOP"><B>Old Filename</B></TD>
<TD ALIGN="LEFT" VALIGN="TOP"><B>New Filename</B></TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD WIDTH="138" ALIGN="LEFT" VALIGN="TOP">BasicAutoObj.h</TD>
<TD ALIGN="LEFT" VALIGN="TOP">Tracker.h</TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD WIDTH="138" ALIGN="LEFT" VALIGN="TOP">BasicAutoObj.cpp</TD>
<TD ALIGN="LEFT" VALIGN="TOP">Tracker.cpp</TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD WIDTH="138" ALIGN="LEFT" VALIGN="TOP">BCFBasicServer.h</TD>
<TD ALIGN="LEFT" VALIGN="TOP">BCFServer.h</TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD WIDTH="138" ALIGN="LEFT" VALIGN="TOP">BCFBasicServer.cpp</TD>
<TD ALIGN="LEFT" VALIGN="TOP">BCFServer.cpp</TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD WIDTH="138" ALIGN="LEFT" VALIGN="TOP">BCFBasicServer.def</TD>
<TD ALIGN="LEFT" VALIGN="TOP">BCFServer.def</TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD WIDTH="138" ALIGN="LEFT" VALIGN="TOP">BCFBasicServer.mak</TD>
<TD ALIGN="LEFT" VALIGN="TOP">BCFServer.mak</TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD WIDTH="138" ALIGN="LEFT" VALIGN="TOP">BCFBasicServer.odl</TD>
<TD ALIGN="LEFT" VALIGN="TOP">BCFServer.odl</TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD WIDTH="138" ALIGN="LEFT" VALIGN="TOP">BCFBasicServer.rc</TD>
<TD ALIGN="LEFT" VALIGN="TOP">BCFServer.rc</TD>
</TR>
</TABLE>
</P>
<P>Open the VC++ IDE, and from the <U>F</U>ile menu select the Find In Files menu
item. Look for <TT>BCFBasicServer</TT> in all of the files in the <TT>BCFServer</TT>
directory. In all of the files that contain the string <TT>BCFBasicServer</TT>, replace
the text with <TT>BCFServer</TT>. Make sure to do the text replacement on a case-sensitive
basis. Repeat the <U>F</U>ind In Files search to ensure that you did not miss any
files or <TT>BCFBasicServer</TT> entries.</P>
<P>Next search for the string <TT>BasicAutoObj</TT> and replace all of the entries
with Tracker. Do the same for the string <TT>BasicAuto</TT>. Remember all text should
be replaced on a case-sensitive basis and should be done for all of the files in
the new project directory.</P>
<P>The last step is to generate new <TT>CLSID</TT> that are unique to the project.
Use the GUIDGEN.EXE to create the new <TT>CLSID</TT>, and add them to the ODL file.</P>
<P>After all of the files have been changed, from the <U>F</U>ile menu, select the
Open <U>W</U>orkspace menu item. In the Open Workspace dialog, open the BCFServer.mak
file. The VC++ IDE will automatically create the file BCFServer.mdp file, which should
be used from this point on when opening the project file. <BR>
<BR>
<IMG SRC="bar.gif" WIDTH="480" HEIGHT="6" ALIGN="BOTTOM" BORDER="0"></P>
<BLOCKQUOTE>
<P><B>NOTE:</B> At the time of the writing of this book, VC++ 5.0 was still in beta.
The file extensions .mak and .mdp have been replaced with the extensions .dsp and
.dsw, respectively. Using the older file extensions will in no way affect the sample
project or your development.
</BLOCKQUOTE>
<P><IMG SRC="bar.gif" WIDTH="480" HEIGHT="6" ALIGN="BOTTOM" BORDER="0"><BR>
<BR>
The last step is to ensure that the location of the BaseCtl include files directory
and the path of the BaseCtl libraries are correct. The BCFBasicServer sample assumes
that the include directory is established in the Directory tab of the Options dialog,
which can be accessed via the <U>T</U>ools menu and the <U>O</U>ptions menu item.
The link settings of the basic project is where the path of the BaseCtl libraries
is defined. <BR>
<BR>
<IMG SRC="bar.gif" WIDTH="480" HEIGHT="6" ALIGN="BOTTOM" BORDER="0"></P>
<BLOCKQUOTE>
<P><B>Linking Got You Down?</B></P>
<P>When building your projects utilizing the BaseCtl framework, make sure that you
use exactly the same compile settings as those used to create the library. It is
important to check all of the settings to ensure that they match exactly. If the
compile options do not match, the linker will be unable to create your project and
will generate a number of linker errors.
</BLOCKQUOTE>
<P><IMG SRC="bar.gif" WIDTH="480" HEIGHT="6" ALIGN="BOTTOM" BORDER="0"><BR>
<BR>
At this point, you can compile the project and even register it in the system registry.
However, you can do very little with it since it does not contain any methods or
properties.</P>
<P>Like all ActiveX/OLE components, ActiveX Servers are required to support registration
and unregistration if they are to be used by other applications.
<H2><A NAME="Heading3"></A>Registry</H2>
<P>The basic registration and unregistration support for the server is already implemented
by BaseCtl. Remember that the MFC implementation only allows for registering the
server.</P>
<P>Registration support is handled completely by the BaseCtl framework and is hidden
from the developer. The registration information is part of the <TT>DEFINE_AUTOMATIONOBJECT</TT>
structure (see Listing 5.1). See the BaseCtl documentation and samples for information
about the structure and its content.
<H3><A NAME="Heading4"></A>Listing 5.1 TRACKER.H--Basic Registration Information
in the DEFINE_AUTOMATIONOBJECT Structure</H3>
<P><FONT COLOR="#0066FF"><TT>// TODO: modify anything appropriate in this structure,
such as the helpfile <BR>
// name, the version number, etc. <BR>
// <BR>
DEFINE_AUTOMATIONOBJECT(Tracker, <BR>
&CLSID_Tracker, <BR>
"Tracker", <BR>
CTracker::Create, <BR>
1, <BR>
&IID_ITracker, </TT></FONT></P>
<P><FONT COLOR="#0066FF"><TT><BR>
"Tracker.Hlp"); </TT></FONT></P>
<H2><A NAME="Heading5"></A>Sample Server Support Code</H2>
<P>Since the server is used to output data to a file, you need to add some support
code to the application before adding its methods and properties.</P>
<P>Listing 5.2 shows the additions that are made to the class header file. First
you added two new include files that are needed to support the file and timer functions
that the server uses. A set of member variables is added for storing the file handle
and timer information that will be used throughout the server implementation.
<H3><A NAME="Heading6"></A>Listing 5.2 TRACKER.H--Sample Server Support Code Added
to the Header File</H3>
<P><FONT COLOR="#0066FF"><TT>// <BR>
#ifndef _TRACKER_H_ <BR>
<BR>
#include "AutoObj.H" <BR>
#include "BCFServerInterfaces.H" <BR>
// needed for FILE services <BR>
#include <stdio.h> <BR>
// needed for the high resolution timer services <BR>
#include <mmsystem.h> <BR>
<BR>
class CTracker : public ITracker, public CAutomationObject, ISupportErrorInfo { <BR>
<BR>
public: <BR>
<BR>
. . . <BR>
<BR>
protected: <BR>
virtual HRESULT InternalQueryInterface(REFIID riid, void **ppvObjOut); <BR>
<BR>
private: <BR>
// member variables that nobody else gets to look at. <BR>
// TODO: add your member variables and private functions here. <BR>
<BR>
protected: <BR>
FILE * m_fileLog; <BR>
long m_lTimeBegin; <BR>
long m_lHiResTime; <BR>
long m_lLastHiResTime; </TT></FONT></P>
<P><FONT COLOR="#0066FF"><TT><BR>
}; </TT></FONT></P>
<P>In the sample implementation, the constructor and destructor implementations are
updated to open and close the log file (see Listing 5.3). First a high resolution
timer is created and its current value is stored in the member variables. The timer
is useful for determining the number of milliseconds that have passed since the last
method call was made. This is great for tracking the performance of a particular
action or set of actions.</P>
<P>You then get the current date and create a filename with the format YYYYMMDD.tracklog.
After successfully opening the file, you output some startup data to the file and
exit the constructor.</P>
<P>The destructor does the exact opposite of the constructor. If you have a valid
file handle, you write some closing information to the file and close it. Next you
terminate the timer.
<H3><A NAME="Heading7"></A>Listing 5.3 TRACKER.CPP--Sample Server Support Code Added
to the Source File</H3>
<P><FONT COLOR="#0066FF"><TT>#pragma warning(disable:4355) // using `this' in constructor
<BR>
CTracker::CTracker <BR>
( <BR>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -