📄 ch06.htm
字号:
<TD ALIGN="LEFT" VALIGN="TOP"><U>M</U>ouse pointer notifications when inactive</TD>
<TD ALIGN="LEFT" VALIGN="TOP">Enables control to receive mouse messages, even though the control is in an inactive
state.</TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD ALIGN="LEFT" VALIGN="TOP"><U>O</U>ptimized drawing code</TD>
<TD ALIGN="LEFT" VALIGN="TOP">Allows the control to draw its User Interface in an optimized fashion if the container
supports optimized drawing; otherwise, the control must be drawn using standard drawing
techniques.</TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD ALIGN="LEFT" VALIGN="TOP"><U>L</U>oads properties asynchronously</TD>
<TD ALIGN="LEFT" VALIGN="TOP">Asynchronous properties are properties that load in thebackground and involve the
transfer of a large amount of data. The properties are loaded in the background to
prevent the container and the control from being disabled or inactive for too long
while waiting for the data to load.</TD>
</TR>
</TABLE>
<BR>
<BR>
From the Advanced ActiveX Features dialog, select only the following options (refer
to fig. 6.5):
<UL>
<LI><U>U</U>nclipped device context
<LI><U>F</U>licker-free activation
<LI><U>M</U>ouse pointer notifications when inactive
<LI><U>O</U>ptimized drawing code
<LI><U>L</U>oads properties asynchronously
</UL>
<P>Click OK to confirm the selection and close the dialog.</P>
<P>Select the <TT>MFCControlNoWin</TT> control, and click the A<U>d</U>vanced button
again. You are going to implement <TT>MFCControlNoWin</TT> as a windowless control
just to get a feel for the difference between the windowed and windowless control
implementations in MFC. From the Advanced ActiveX Features dialog, select only the
following options (refer to fig. 6.5):
<UL>
<LI><U>W</U>indowless activation
<LI><U>M</U>ouse pointer notifications when inactive
<LI><U>O</U>ptimized drawing code
<LI><U>L</U>oads properties asynchronously
</UL>
<P>Click OK to confirm the selections and close the dialog.</P>
<P>For your third and final control, you subclass an existing window's control. Be
sure to select the control <TT>MFCControlSubWin</TT>, and in the subclassing list
box, select BUTTON. Do not define any advanced ActiveX features for this control.</P>
<P>The MFC ActiveX ControlWizard -- Step 2 of 2 dialog also provides other features
for further defining your control project. For the sample project, leave the values
in their default state. See the VC++ documentation for more information regarding
other available options.</P>
<P>Click the Finish button on the ControlWizard dialog to complete the feature selection
process (refer to fig. 6.3). The New Project Information dialog displays to let you
confirm the choices you made (see fig. 6.6). Click OK to generate the source files
and the MFC control project. <B><BR>
<BR>
</B><A HREF="Art/06/f_fig06.jpg"><B>FIG. 6.6</B></A> <I><BR>
Make your confirmations in the New Project Information dialog.</I></P>
<P>The first step in any control project is to ensure that it contains registration
support. Without registration, the control cannot be used by any application.
<H2><A NAME="Heading3"></A>Control Registration</H2>
<P>Control registration and unregistration support is provided for you by MFC. You
are not required to make any code changes or additions to support it. Listing 6.1
shows the <TT>UpdateRegistry</TT> function that was created for the control by the
AppWizard; each control will have its own registration function.</P>
<P>One thing of interest is the comment from Microsoft regarding apartment model
threading and how you should register your control if you know it doesn't conform
to apartment model rules. Other than that, you will not have to make any changes
to your application or this function when it comes to control registration.
<H3><A NAME="Heading4"></A>Listing 6.1 MFCCONTROLWINCTL.CPP--Default UpdateRegistry
Implementation</H3>
<P><FONT COLOR="#0066FF"><TT>/////////////////////////////////////////////////////////////////////////////
<BR>
// CMFCControlWinCtrl::CMFCControlWinCtrlFactory::UpdateRegistry - <BR>
// Adds or removes system registry entries for CMFCControlWinCtrl <BR>
BOOLCMFCControlWinCtrl::CMFCControlWinCtrlFactory::UpdateRegistry(BOOLbRegister)
{ <BR>
// TODO: Verify that your control follows apartment-model threading rules. <BR>
// Refer to MFC TechNote 64 for more information. <BR>
// If your control does not conform to the apartment-model rules, then <BR>
// you must modify the code below, changing the 6th parameter from <BR>
// afxRegApartmentThreading to 0. <BR>
if (bRegister) <BR>
return AfxOleRegisterControlClass( <BR>
AfxGetInstanceHandle(), <BR>
m_clsid, <BR>
m_lpszProgID, <BR>
IDS_MFCCONTROLWIN, <BR>
IDB_MFCCONTROLWIN, <BR>
afxRegApartmentThreading, <BR>
_dwMFCControlWinOleMisc, <BR>
_tlid, <BR>
_wVerMajor, <BR>
_wVerMinor); <BR>
else <BR>
return AfxOleUnregisterClass(m_clsid, m_lpszProgID); <BR>
}</TT></FONT></P>
<P>You can now compile and register the control you've created, but it won't be of
much use because it doesn't contain methods, properties, or events, which are the
basis of every ActiveX Control.
<H2><A NAME="Heading5"></A>Creating Methods</H2>
<P>Now that you've successfully created your ActiveX control project, you can start
off by adding a <I>method, </I>which is one of the basic aspects of component development.</P>
<P>For the purposes of the sample control, you are going to add a method called <TT>CaptionMethod</TT>.
The method will accept two parameters, the second one being optional. The first parameter
is a string that the control will display within its client area, and the second,
optional parameter is the alignment of the caption within the client area, either
left, right, or center. From the <U>V</U>iew menu, select Class<U>W</U>izard, and
in the MFC ClassWizard dialog (see fig. 6.7), select the Automation tab. <B><BR>
<BR>
</B><A HREF="Art/06/f_fig07.jpg"><B>FIG. 6.7</B></A> <BR>
<I>Adding a method is done through the MFC ClassWizard.</I></P>
<P>From the Class <U>N</U>ame drop-down list box, select the <TT>CMFCControlWinCtrl</TT>
class, and click the <U>A</U>dd Method button to create a new method. Type CaptionMethod
in the <U>E</U>xternal Name combo box (see fig. 6.8), and set the Return <U>t</U>ype
to a <TT>long</TT>. Add two parameters--by clicking the appropriate column in the
<U>P</U>arameter List control--the first called <TT>lpctstrCaption</TT> of type <TT>LPCTSTR</TT>,
and the second, as your optional parameter, called <TT>varAlignment</TT> of type
<TT>VARIANT</TT>. Click OK to add the method to the class. Next click OK to close
the ClassWizard dialog. <BR>
<BR>
<A HREF="Art/06/f_fig08.jpg"><B>FIG. 6.8</B></A> <I><BR>
Add the <TT>CaptionMethod</TT> method to the control class.</I></P>
<P><IMG SRC="bar.gif" WIDTH="480" HEIGHT="6" ALIGN="BOTTOM" BORDER="0"></P>
<BLOCKQUOTE>
<P><B>NOTE:</B> All optional parameters must be of type <TT>VARIANT</TT>, and they
must fall at the end of the parameter list. Optional parameters are not managed in
any way by OLE. It is the server application's responsibility to determine whether
the <TT>VARIANT</TT> parameter passed to the method contains data and
<UL>
<LI>to either use the data passed to the method or convert the data to a useful type,
if possible, or
<P>
<LI>to ignore the parameter if invalid data was passed and use the default value
if appropriate, or
<P>
<LI>to inform the user of an error condition if one of the above conditions was not
met.
</UL>
</BLOCKQUOTE>
<P><IMG SRC="bar.gif" WIDTH="480" HEIGHT="6" ALIGN="BOTTOM" BORDER="0"><BR>
<BR>
To aid your <TT>CaptionMethod</TT> implementation, you need to add an enumeration
for all the valid alignment settings and two member variables to your class definition
(see Listing 6.2). The enumeration is included in the header file Alignmentenums.h
(see Listing 6.3). The two member variables, <TT>m_cstrCaption</TT> and <TT>m_lAlignment</TT>,
are used to store the caption string and the alignment setting while the control
is being used.</P>
<P>Note the type used for the <TT>m_lAlignment</TT> member variable. The variable
is declared as type <TT>long</TT> and not as the enumeration type because of the
data type restrictions that are imposed upon you by ActiveX Automation. Remember
that only data types that can be passed in a <TT>VARIANT</TT> can be used in methods
and properties. By declaring the <TT>m_lAlignment</TT> member as <TT>long</TT>, you
do not have to explicitly convert the value by casting to the enumerated type when
it is retrieved from the <TT>VARIANT</TT> parameter in the caption method. On the
other hand, casting the value to the enumerated type is a trivial issue and is completely
up to you to implement if you desire to do so.
<H3><A NAME="Heading6"></A>Listing 6.2 MFCCONTROLWINCTL.H--Alignment Enumeration
Include File and Member Variables Added to Class Definition</H3>
<P><FONT COLOR="#0066FF"><TT>. . . <BR>
// MFCControlWinCtl.h : Declaration oftheCMFCControlWinCtrlActiveXControl <BR>
#include "alignmentenums.h" <BR>
///////////////////////////////////////////////////////////////////////////// <BR>
// CMFCControlWinCtrl : See MFCControlWinCtl.cpp for implementation. <BR>
class CMFCControlWinCtrl : public COleControl <BR>
{ <BR>
. . . <BR>
protected: <BR>
// storage variable for the caption <BR>
CString m_cstrCaption; <BR>
// storage variable for the alignment <BR>
long m_lAlignment; <BR>
}; <BR>
<BR>
. . . </TT></FONT></P>
<P>The enumeration is added as an include file (see Listing 6.3) so that it can be
referenced by other files, which will be necessary as you proceed through the chapter.
<H3><A NAME="Heading7"></A>Listing 6.3 ALIGNMENTENUMS.H--Alignment Enumeration Include
File</H3>
<P><FONT COLOR="#0066FF"><TT>#if !defined _ALIGNMENTENUMS_H <BR>
#define _ALIGNMENTENUMS_H <BR>
// caption alignment enumeration <BR>
typedef enum tagAlignmentEnum <BR>
{ <BR>
EALIGN_LEFT = 0, <BR>
EALIGN_CENTER = 1, <BR>
EALIGN_RIGHT = 2, <BR>
}EALIGNMENT; <BR>
<BR>
#endif // #if !defined _ALIGNMENTENUMS_H </TT></FONT></P>
<P>Open the MFCCOntrolWinCtl.cpp file, and in the constructor initialize the <TT>m_Alignment</TT>
member variable to the value <TT>EALIGN_LEFT</TT> (see Listing 6.4).
<H3><A NAME="Heading8"></A>Listing 6.4 MFCCONTROLWINCTL.CPP--Initialize the m_lAlignment
Member Variable in the Class Constructor</H3>
<P><FONT COLOR="#0066FF"><TT>/////////////////////////////////////////////////////////////////////////////
<BR>
// CMFCControlWinCtrl::CMFCControlWinCtrl - Constructor <BR>
CMFCControlWinCtrl::CMFCControlWinCtrl() <BR>
{ <BR>
InitializeIIDs(&IID_DMFCControlWin, &IID_DMFCControlWinEvents); <BR>
m_lReadyState = READYSTATE_LOADING; <BR>
// TODO: Call InternalSetReadyState when the readystate changes. <BR>
// set the alignment to the default of left <BR>
m_lAlignment = EALIGN_LEFT; <BR>
} </TT></FONT></P>
<P>The <TT>CaptionMethod</TT> contains all of the code for setting the caption and
the alignment style (see Listing 6.5) and does several things of interest that need
to be pointed out.</P>
<P>First the method tries to deal with the optional parameter by looking for the
data type you really want, <TT>VT_I4</TT>, which is a data type of <TT>long</TT>.</P>
<P>If the <TT>VARIANT</TT> parameter doesn't contain a <TT>long</TT>, the method
then checks to see if any data was passed at all, by checking for <TT>VT_ERROR</TT>
or <TT>VT_EMPTY</TT>. This is necessary because the parameter is optional. A variant
parameter can either contain data or not. It is important to check <TT>VARIANT</TT>
data types not only for valid data but also for the actual existence of data. If
no data was supplied, the method relies on the value already contained in the <TT>m_lAligmnent</TT>
class member variable. <BR>
<BR>
<IMG SRC="bar.gif" WIDTH="480" HEIGHT="6" ALIGN="BOTTOM" BORDER="0"></P>
<BLOCKQUOTE>
<P><B>Automation Controllers and Optional Parameters</B><BR>
Some automation controllers, such as Visual Basic, do not require that any or all
of the optional parameters be supplied when calling a method, for example, the <TT>CaptionMethod</TT>
can be called as
</BLOCKQUOTE>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -