📄 ch07.htm
字号:
of bytes of data that are currently available in this call to the function. <TT>BscfFlag</TT>
is a set of flags indicating the current operation taking place (see Table 7.1).
<TABLE BORDER="1" WIDTH="100%">
<CAPTION><B>Table 7.1</B><SPACER TYPE="HORIZONTAL" SIZE="10"><B> <I>BSCF</I> Notifications</B></CAPTION>
<TR ALIGN="LEFT" rowspan="1">
<TD ALIGN="LEFT" VALIGN="TOP"><B>Notification Message</B></TD>
<TD ALIGN="LEFT" VALIGN="TOP"><B>Description</B></TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD ALIGN="LEFT" VALIGN="TOP"><TT>BSCF_FIRSTDATANOTIFICATION</TT></TD>
<TD ALIGN="LEFT" VALIGN="TOP">This message is sent the first time that the <TT>OnDataAvailable</TT> function is
called. It is important to note that this message can be sent along with the <TT>BSCF_LASTDATANOTIFICATION</TT>
message.</TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD ALIGN="LEFT" VALIGN="TOP"><TT>BSCF_INTERMEDIATEDATANOTIFICATION</TT></TD>
<TD ALIGN="LEFT" VALIGN="TOP">This message is sent while the OLE is still loading data.</TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD ALIGN="LEFT" VALIGN="TOP"><TT>BSCF_LASTDATANOTIFICATION</TT></TD>
<TD ALIGN="LEFT" VALIGN="TOP">This message is sent when a control has been given all of the data that is available
to the property. It is important to note that this message can be sent along with
the <TT>BSCF_FIRSTDATANOTIFICATION</TT> message.</TD>
</TR>
</TABLE>
<BR>
<BR>
Note the use of the <TT>BSCF</TT> notification messages and how you must respond
to each. Do not process the messages exclusive of each other; you must process each
message individually. Remember that you can receive more than one notification message
in each call to <TT>OnDataAvailable</TT>.</P>
<P>The <TT>OnDataAvailable</TT> implementation first clears the string buffer if
this is the first call to the function. Next it creates a buffer of the appropriate
size to receive the data from the <TT>Read</TT> function. If the data was successfully
read, the data is added to the member variable <TT>cstrMyBuffer</TT>. Finally if
this is the last call to the <TT>OnDataAvailable</TT> function, the <TT>CaptionMethod</TT>
is called supplying the new data and an empty variant parameter for the alignment.
The last thing you must do is change the state of the control to <TT>READYSTATE_COMPLETE</TT>,
which indicates that all of the asynchronous properties have been loaded.
<H3><A NAME="Heading7"></A>Listing 7.4 MYDATAPATH.CPP--OnDataAvailable Implementation</H3>
<P><FONT COLOR="#0066FF"><TT>void CMyDataPath::OnDataAvailable(DWORD dwSize, DWORD
bscfFlag) <BR>
{<BR>
// if this is the first notification<BR>
if(bscfFlag & BSCF_FIRSTDATANOTIFICATION)<BR>
// clear the string buffer<BR>
cstrMyBuffer.Empty();<BR>
CString cstrTempBuffer;<BR>
// get a temp buffer<BR>
LPTSTR lptstrTempBuffer = cstrTempBuffer.GetBuffer(dwSize);<BR>
// read the data to a temp buffer<BR>
UINT uiBytesRead = this->Read(lptstrTempBuffer, dwSize);<BR>
// if we read in any data<BR>
if(uiBytesRead)<BR>
{<BR>
// store the data<BR>
cstrTempBuffer.ReleaseBuffer(uiBytesRead);<BR>
cstrMyBuffer += cstrTempBuffer;<BR>
}<BR>
// if this is our last notification<BR>
if(bscfFlag & BSCF_LASTDATANOTIFICATION)<BR>
{<BR>
VARIANT varAlignment;<BR>
::VariantInit(&varAlignment);<BR>
varAlignment.vt = VT_EMPTY;<BR>
((CMFCControlWinCtrl *) this->GetControl())->CaptionMethod(cstrMyBuffer,
<BR>
varAlignment);<BR>
this->GetControl()->InternalSetReadyState(READYSTATE_COMPLETE);<BR>
}<BR>
}</TT></FONT>
<PRE><FONT COLOR="#0066FF"></FONT></PRE>
<P>Next you need to add an OLE property to store the actual location of the data
that is to be loaded asynchronously. Open the ClassWizard, select the Automation
tab, select the <TT>CMFCControlWinCtrl</TT> class, and click the Add Property button.
In the Add Property dialog, enter the <U>E</U>xternal name TextData, select the <U>T</U>ype
<TT>BSTR</TT> and an Implementation of <TT>Get/Set</TT> <U>m</U>ethods. Do not use
the <TT>OLE_DATAPATH</TT> type for this property, as it doesn't work; the type must
be a <TT>BSTR</TT>. Use of the OLE_DATAPATH and its related problems is a known bug
with Microsoft and MFC. Click the OK button to close the dialog and add the property
to the class. Double-click the <TT>TextData</TT> entry in the E<U>x</U>ternal names
list box to close the ClassWizard and open the source file.</P>
<P>To complete your implementation, you need to add some code to the <TT>CMFCControlWinCtrl</TT>
class source file. First update the class constructor to set the control class in
the <TT>oMyDataPath</TT> object (see Listing 7.5). Doing this is absolutely necessary
for the <TT>DoPropExchange</TT> function to work correctly when loading the data
path property.
<H3><A NAME="Heading8"></A>Listing 7.5 MFCCONTROLWINCTL.CPP--oMyDataPath Object Initialized
in the CMFCControlWinCtrl Class Constructor</H3>
<P><FONT COLOR="#0066FF"><TT>CMFCControlWinCtrl::CMFCControlWinCtrl()<BR>
{<BR>
InitializeIIDs(&IID_DMFCControlWin, &IID_DMFCControlWinEvents);<BR>
// TODO: Call InternalSetReadyState when the readystate changes.<BR>
m_lReadyState = READYSTATE_LOADING;<BR>
<BR>
// set the alignment to the default of left<BR>
m_lAlignment = EALIGN_LEFT;<BR>
<BR>
// don't forget this - DoPropExchange won't work without it<BR>
oMyDataPath.SetControl(this);<BR>
}</TT></FONT>
<PRE><FONT COLOR="#0066FF"></FONT></PRE>
<P>Next add the <TT>oMyDataPath</TT> property persistence to the <TT>DoPropExchange</TT>
function (see Listing 7.6). Remember that without the call to <TT>SetControl</TT>
in the constructor, this code will not function correctly.
<H3><A NAME="Heading9"></A>Listing 7.6 MFCCONTROLWINCTRL.CPP--oMyDataPath Added to
DoPropExchange</H3>
<P><FONT COLOR="#0066FF"><TT>void CMFCControlWinCtrl::DoPropExchange(CPropExchange*
pPX)<BR>
{<BR>
ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));<BR>
COleControl::DoPropExchange(pPX);<BR>
<BR>
// TODO: Call PX_ functions for each persistent custom property.<BR>
// if we are loading the properties<BR>
if(pPX->IsLoading())<BR>
{<BR>
PX_Long(pPX, _T("Alignment"), m_lAlignment, EALIGN_LEFT);<BR>
PX_String(pPX, _T("CaptionProp"), m_cstrCaption, _T(""));<BR>
PX_DataPath(pPX, _T("TextData"), oMyDataPath);<BR>
}<BR>
<BR>
// if we are saving the properties<BR>
if(!pPX->IsLoading())<BR>
{<BR>
PX_Long(pPX, _T("Alignment"), m_lAlignment, EALIGN_LEFT);<BR>
PX_String(pPX, _T("CaptionProp"), m_cstrCaption, _T(""));<BR>
PX_DataPath(pPX, _T("TextData"), oMyDataPath);<BR>
}<BR>
}</TT></FONT>
<PRE><FONT COLOR="#0066FF"></FONT></PRE>
<P>Finally you add the code to the <TT>GetTextData</TT> and <TT>SetTextData</TT>
methods (see Listing 7.7). The <TT>GetTextData</TT> function simply returns a UNICODE
version of the property value. The <TT>SetTextData</TT> implementation calls the
<TT>Load</TT> function to load the data pointed to by the <TT>lpszNewValue</TT> parameter.
After the <TT>Load</TT> function returns, the <TT>SetModifiedFlag</TT> and <TT>InvalidateControl</TT>
functions are called to update the control and the data with the new information.
<H3><A NAME="Heading10"></A>Listing 7.7 MFCCONTROLWINCTL.H--Get/Set TextData Property
Implementation</H3>
<P><FONT COLOR="#0066FF"><TT>BSTR CMFCControlWinCtrl::GetTextData() <BR>
{<BR>
// retrieve the path and allocate a BSTR from it<BR>
return (oMyDataPath.GetPath()).AllocSysString();<BR>
}<BR>
<BR>
void CMFCControlWinCtrl::SetTextData(LPCTSTR lpszNewValue) <BR>
{<BR>
// load the DataPath variable based on the new information<BR>
this->Load(lpszNewValue, oMyDataPath);<BR>
<BR>
// update the property<BR>
this->SetModifiedFlag();<BR>
<BR>
// redraw the control<BR>
this->InvalidateControl();<BR>
}</TT></FONT>
<PRE><FONT COLOR="#0066FF"></FONT></PRE>
<P>Again, it is very important to understand that asynchronous properties are not
a guarantee of improved performance in a general sense. They are merely an option
available to you for creating Internet controls that are more responsive across slower
network connections.
<H3><A NAME="Heading11"></A>Static and Dynamic Property Enumeration</H3>
<P><I>Property enumeration</I> is a way of restricting a property to a specific set
of valid values. An example of an enumeration is a property for determining the alignment
of a control's displayed text: left-justified, centered, and right-justified, in
your case. Another case is a property used to select the different languages a control
supports. This is a good candidate for both a static set, say English and German,
and a dynamic set, say for all the languages on a particular machine.</P>
<P>Adding property enumeration greatly enhances the look and feel of your control.
This addition gives the user all the options that are possible, with a simple click
of a mouse. As a result the user doesn't have to rather than trying to search through
documentation or, worse yet, trying to guess the acceptable values.</P>
<P>When editing the value of an enumerated property within a property browser, note
that development tools such as Visual Basic display all the values of the enumeration
using a string representation rather than just the actual value that the control
can accept. For a Boolean data type, the strings used are <TT>TRUE</TT> and <TT>FALSE</TT>,
representing -1 or 0, respectively.</P>
<P>Two approaches can be taken when creating an enumeration for a property: You can
use a static approach, with an enumeration defined in the control's ODL file, or
a dynamic approach, with enumeration code implemented in the control itself. <B><BR>
<BR>
Static Property Enumeration </B><SPACER TYPE="HORIZONTAL" SIZE="10">ODL allows for
the creation of C/C++ style enumeration declarations that conform to the same rules
as C/C++. Like C/C++, the new enumeration can be used as data type within the ODL
file. While this style of enumeration is by far the easiest, it is also the most
restrictive because the enumeration is static to the type library. The <TT>Alignment</TT>
property is a good candidate for an enumeration because internally that is how it
is validated and used. Listing 7.8 contains the code that was added to your ODL file
to support the <TT>Alignment</TT> enumeration.</P>
<P>Remember to generate a new <TT>UUID</TT> for the enumeration with the GUIDGEN.EXE
application included with VC++.</P>
<P>The <TT>helpstring</TT> is what the user will see within the property browser
of your development environment. If you leave off the <TT>helpstring</TT>, the actual
numeric value will appear instead.</P>
<P>The last thing you did was to change the data type of the <TT>Alignment</TT> property
from <TT>long</TT> to <TT>EALIGNMENT</TT>. This is required if the property is to
display the enumerated values within the property browser. <BR>
<BR>
<IMG SRC="bar.gif" WIDTH="480" HEIGHT="6" ALIGN="BOTTOM" BORDER="0"></P>
<BLOCKQUOTE>
<P><B>NOTE:</B> ODL is very flexible in that it allows much the same style of data
type declaration and use as that of C or C++. Any data type that can be declared
in ODL can also be referenced and used within the same and other ODL files, including
interface declarations. In addition, other type libraries can be imported into an
ODL file to provide access to other user-defined data types. In the case of the sample
control, two types of libraries, <TT>STDOLE_TLB</TT> and <TT>STDTYPE_TLB</TT>, are
included for the standard OLE interface and data type declarations. <BR>
<BR>
The ODL documentation can be a little difficult to decipher, but we recommend that
you at least review the documentation. It is well worth the effort just to see what
you can and cannot do with your type library and how it will affect the container
of your control or component. <BR>
<BR>
It is absolutely critical that the developer of containers adhere to the standards
established in the ODL documentation. You will find that some of the aspects of type
library creation and use are based on cooperation and trust and that component developers
depend on that.
</BLOCKQUOTE>
<P><IMG SRC="bar.gif" WIDTH="480" HEIGHT="6" ALIGN="BOTTOM" BORDER="0">
<H3><A NAME="Heading12"></A>Listing 7.8 MFCCONTROL.ODL--EALIGNMENT Enumeration Added
to the MFCControl.odl File</H3>
<P><FONT COLOR="#0066FF"><TT> typedef<BR>
[ uuid(7F369B90-380D-11d0-BCB6-0020AFD6738C) ]<BR>
enum tagAlignmentEnum<BR>
{<BR>
[helpstring("Left Justify")] EALIGN_LEFT = 0,<BR>
[helpstring("Right Justify")] EALIGN_RIGHT = 1,<BR>
[helpstring("Center")] EALIGN_CENTER = 2,<BR>
}EALIGNMENT;<BR>
<BR>
// Primary dispatch interface for CMFCControlWinCtrl<BR>
<BR>
[ uuid(14DD5C04-60DE-11D0-BEE9-00400538977D),<BR>
helpstring("Dispatch interface for MFCControlWin Control"), hidden
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -