⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch09.htm

📁 用VC开发activeX控件的电子书,很不错的
💻 HTM
📖 第 1 页 / 共 5 页
字号:
the <TT>ReadyState</TT> property to the persistence since its value is not valid
across execution lifetimes.
<H3><A NAME="Heading13"></A>Listing 9.10<SPACER TYPE="HORIZONTAL" SIZE="10"> ATLCONTROLWIN.H--TextDataPath
Member Added to the Property Persistence Macro</H3>
<P><FONT COLOR="#0066FF"><TT>. . . <BR>
BEGIN_PROPERTY_MAP(CATLControlWin) <BR>
// PROP_ENTRY(&quot;Description&quot;, dispid, clsid) <BR>
PROP_ENTRY(&quot;TextDataPath&quot;, dispidTextDataPath, CLSID_ATLControlWinPPG)
<BR>
PROP_ENTRY(&quot;Alignment&quot;, dispidAlignment, CLSID_ATLControlWinPPG) <BR>
PROP_ENTRY(&quot;BackColor&quot;, DISPID_BACKCOLOR, CLSID_ATLControlWinPPG) <BR>
PROP_PAGE(CLSID_CColorPropPage) <BR>
END_PROPERTY_MAP() <BR>
. . . </TT></FONT></P>
<H3><A NAME="Heading14"></A>Static and Dynamic Property Enumeration</H3>
<P>Property enumeration 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. A language-based property 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>As is pointed out in <A HREF="ch07.htm">Chapter 7</A>, property enumeration adds
a new level of sophistication to your control with very little effort.</P>
<P>You can take two approaches when creating an enumeration for a property: use a
static approach with an enumeration defined in the control's ODL or IDL file, or
use a dynamic approach with enumeration code implemented in the control itself. <B><BR>
<BR>
Static Property Enumeration</B><SPACER TYPE="HORIZONTAL" SIZE="10"> <I>Static property
enumeration</I> for an ATL-implemented control is no different than the MFC implementation.
Static enumeration is dependent on the ODL/IDL file and involves no control code
to implement. See <A HREF="ch07.htm">Chapter 7</A> for more information.</P>
<P><B>Dynamic Property Enumeration</B><SPACER TYPE="HORIZONTAL" SIZE="10"> As with
your MFC implementation, adding dynamic property enumeration to your ATL implementation
is straightforward. <I>Dynamic property enumeration</I> is based on the interface
<TT>IPerPropertyBrowsing</TT>. The ATL Object Wizard does not add this interface
to the control class automatically; you are required to add it yourself. The first
step is to add the <TT>IPerPropertyBrowsingImpl</TT> class to your control inheritance
structure:</P>

<P><FONT COLOR="#0066FF"><TT>public IPerPropertyBrowsingImpl&lt;CATLControlWin&gt;
</TT></FONT></P>

<P>And then add the <TT>IPerPropertyBrowsing</TT> interface to the COM interface
map:</P>

<P><FONT COLOR="#0066FF"><TT>COM_INTERFACE_ENTRY_IMPL(IPerPropertyBrowsing) </TT></FONT></P>

<P>The last step is to implement the <TT>IPerPropertyBrowsing</TT> interface functions.
First you add the function prototypes to the class declaration (see Listing 9.11).
<H3><A NAME="Heading15"></A>Listing 9.11<SPACER TYPE="HORIZONTAL" SIZE="10"> ATLCONTROLWIN.H--IPerPropertyBrowsing
Interface Function Prototypes Must Be Added to the Class Declaration</H3>
<P><FONT COLOR="#0066FF"><TT>. . . <BR>
STDMETHOD(MapPropertyToPage)(DISPID dispID, CLSID *pClsid); <BR>
STDMETHOD(GetPredefinedStrings)(DISPID dispID, CALPOLESTR *pCaStringsOut, <BR>
CADWORD *pCaCookiesOut); <BR>
STDMETHOD(GetPredefinedValue)(DISPID dispID, DWORD dwCookie, VARIANT* pVarOut); <BR>
STDMETHOD(GetDisplayString)(DISPID dispID,BSTR *pBstr); <BR>
. . . </TT></FONT></P>
<P><TT>MapPropertyToPage</TT> (see Listing 9.12) is used to identify a property to
a specific control or system-defined property page. In this case, you return <TT>E_NOTIMPL</TT>
if the <TT>dispid</TT> matches that of the <TT>Alignment</TT> property. By returning
<TT>E_NOTIMPL</TT>, you are preventing the container application from displaying
the property page associated with the property; instead, the container will use the
property enumeration that you have implemented. The connection between the property
and the property page is made in the property map macro in the class declaration.
Remember that one of the parameters in the macro was the <TT>CLSID</TT> of the property
page for the property.
<H3><A NAME="Heading16"></A>Listing 9.12<SPACER TYPE="HORIZONTAL" SIZE="10"> ATLCONTROLWIN.CPP--MapPropertyToPage
Implementation</H3>
<P><FONT COLOR="#0066FF"><TT>STDMETHODIMP CATLControlWin::MapPropertyToPage(DISPID
dispID, CLSID *pClsid) <BR>
{ <BR>
// if this is the dispid property <BR>
if(dispID == dispidAlignment) <BR>
// defer to the property enumeration and not the property page <BR>
return E_NOTIMPL; <BR>
else <BR>
// defer to the base class implementation <BR>
return IPerPropertyBrowsingImpl&lt;CATLControlWin&gt;:: <BR>
MapPropertyToPage(dispID, pClsid); <BR>
} </TT></FONT></P>
<P><TT>GetPredefinedStrings</TT> is the first function to be called (see Listing
9.13). When this method is called, the <TT>dispid</TT> of the property that is currently
being referenced will be passed in. This method is called for all properties that
the control supports, so take care when adding code. If the function is called and
it is determined that the correct property is in context, the control is required
to create an array of strings and cookies. A <I>cookie</I> is any 32-bit value that
has meaning to the control implementation. In this case, the cookies that you supply
are the enumeration constants that you added in <A HREF="ch08.htm">Chapter 8</A>.
The strings are placed in a list from which the user of the control can select the
appropriate value to set the property.
<H3><A NAME="Heading17"></A>Listing 9.13 <SPACER TYPE="HORIZONTAL" SIZE="10">ATLCONTROLWIN.CPP--GetPredefinedStrings
Implementation</H3>
<P><FONT COLOR="#0066FF"><TT>STDMETHODIMP CATLControlWin::GetPredefinedStrings(DISPID
dispid, <BR>
CALPOLESTR * lpcaStringsOut, CADWORD * lpcaCookiesOut) <BR>
{ <BR>
USES_CONVERSION; <BR>
HRESULT hResult = S_FALSE; <BR>
// we should have gotten two pointers if we didn't <BR>
if((lpcaStringsOut == NULL) || (lpcaCookiesOut == NULL)) <BR>
// we are out of here <BR>
return E_POINTER; <BR>
// if this is the property that we are looking for <BR>
if(dispid == dispidAlignment) <BR>
{ <BR>
ULONG ulElems = 3; <BR>
// allocate the memory for our string array <BR>
lpcaStringsOut-&gt;pElems = (LPOLESTR *) ::CoTaskMemAlloc( <BR>
sizeof(LPOLESTR) * ulElems); <BR>
// if we couldn't allocate the memory <BR>
if(lpcaStringsOut-&gt;pElems == NULL) <BR>
// were out of here <BR>
return E_OUTOFMEMORY; <BR>
// allocate the memory for our cookie array <BR>
lpcaCookiesOut-&gt;pElems = (DWORD*) ::CoTaskMemAlloc(sizeof(DWORD*) * ulElems);
<BR>
// if we couldn't allocate the memory <BR>
if (lpcaCookiesOut-&gt;pElems == NULL) <BR>
{ <BR>
// free the string array <BR>
::CoTaskMemFree(lpcaStringsOut-&gt;pElems); <BR>
// exit the function <BR>
return E_OUTOFMEMORY; <BR>
} <BR>
// store the number of elements in each array <BR>
lpcaStringsOut-&gt;cElems = ulElems; <BR>
lpcaCookiesOut-&gt;cElems = ulElems; <BR>
// allocate the strings <BR>
lpcaStringsOut-&gt;pElems[0] = ATLA2WHELPER((LPWSTR)::CoTaskMemAlloc( <BR>
(lstrlen(EALIGN_LEFT_TEXT) + 1) * 2), EALIGN_LEFT_TEXT, <BR>
lstrlen(EALIGN_LEFT_TEXT) + 1); <BR>
lpcaStringsOut-&gt;pElems[1] = ATLA2WHELPER((LPWSTR)::CoTaskMemAlloc( <BR>
(lstrlen(EALIGN_CENTER_TEXT) + 1) * 2), EALIGN_CENTER_TEXT, <BR>
lstrlen(EALIGN_CENTER_TEXT) + 1); <BR>
lpcaStringsOut-&gt;pElems[2] = ATLA2WHELPER((LPWSTR)::CoTaskMemAlloc( <BR>
(lstrlen(EALIGN_RIGHT_TEXT) + 1) * 2), EALIGN_RIGHT_TEXT, <BR>
lstrlen(EALIGN_RIGHT_TEXT) + 1); <BR>
// assign the cookie value <BR>
lpcaCookiesOut-&gt;pElems[0] = EALIGN_LEFT; <BR>
lpcaCookiesOut-&gt;pElems[1] = EALIGN_CENTER; <BR>
lpcaCookiesOut-&gt;pElems[2] = EALIGN_RIGHT; <BR>
hResult = S_OK; <BR>
} <BR>
return hResult; <BR>
} </TT></FONT></P>
<P><TT>GetPredefinedValue</TT> (see Listing 9.14) is the method that is called when
the property browser of the container needs the value associated with the particular
<TT>dispid</TT> and cookie. The value returned is the actual value that is stored
in the property and not the string that was used to represent it.
<H3><A NAME="Heading18"></A>Listing 9.14<SPACER TYPE="HORIZONTAL" SIZE="10"> ATLCONTROLWIN.CPP--GetPredefinedValue
Implementation</H3>
<P><FONT COLOR="#0066FF"><TT>STDMETHODIMP CATLControlWin::GetPredefinedValue(DISPID
dispid, DWORD dwCookie, <BR>
VARIANT* lpvarOut) <BR>
{ <BR>
BOOL bResult = FALSE; <BR>
// which property is it <BR>
switch(dispid) <BR>
{ <BR>
case dispidAlignment: <BR>
// clear the variant <BR>
::VariantInit(lpvarOut); <BR>
// set the type to a long <BR>
lpvarOut-&gt;vt = VT_I4; <BR>
// set the value to the value that was stored with the string <BR>
lpvarOut-&gt;lVal = dwCookie; <BR>
// set the return value <BR>
bResult = TRUE; <BR>
break; <BR>
} <BR>
return bResult; <BR>
} </TT></FONT></P>
<P>After the property is set with its value, the property browser calls the function
<TT>GetDisplayString</TT> to get the string that is associated with the current property
setting (see Listing 9.15).
<H3><A NAME="Heading19"></A>Listing 9.15 <SPACER TYPE="HORIZONTAL" SIZE="10">ATLCONTROLWIN.CPP--GetDisplayString
Implementation</H3>
<P><FONT COLOR="#0066FF"><TT><BR>
STDMETHODIMP CATLControlWin::GetDisplayString(DISPID dispid, BSTR* lpbstr) <BR>
{ <BR>
USES_CONVERSION; <BR>
HRESULT hResult = S_FALSE; <BR>
// which property is it <BR>
switch(dispid) <BR>
{ <BR>
case dispidAlignment: <BR>
{ <BR>
switch(m_lAlignment) <BR>
{ <BR>
case EALIGN_LEFT: <BR>
*lpbstr = ::SysAllocString(T2OLE(EALIGN_LEFT_TEXT)); <BR>
break; <BR>
case EALIGN_CENTER: <BR>
*lpbstr = ::SysAllocString(T2OLE(EALIGN_CENTER_TEXT)); <BR>
break; <BR>
case EALIGN_RIGHT: <BR>
*lpbstr = ::SysAllocString(T2OLE(EALIGN_RIGHT_TEXT)); <BR>
break; <BR>
} <BR>
// set the return value <BR>
hResult = S_OK; <BR>
} <BR>
break; <BR>
} <BR>
return hResult; <BR>
} </TT></FONT></P>
<P><IMG SRC="bar.gif" WIDTH="480" HEIGHT="6" ALIGN="BOTTOM" BORDER="0"></P>


<BLOCKQUOTE>
	<P><B>NOTE:</B> Having the method <TT>GetDisplayString</TT> when the property browser
	already has the string for the value from the <TT>GetPredefinedStrings</TT> function
	may seem a little redundant. You do this because the <TT>GetDisplayString</TT> function
	can be implemented without implementing the other methods. Providing only the function
	<TT>GetDisplayString</TT> is done for those property types that do not use the standard
	property selection mechanism, for example, font selection that uses a font selection
	dialog and not a list of choices.

</BLOCKQUOTE>

<P><IMG SRC="bar.gif" WIDTH="480" HEIGHT="6" ALIGN="BOTTOM" BORDER="0">
<H2><A NAME="Heading20"></A>Drawing the Control</H2>
<P>Optimized drawing allows you to create drawing objects, such as pens or brushes.
Rather than removing them when you are finished drawing, you can store them as control
member variables and use them the next time your control draws itself. The benefit
is that you create a pen once for the drawing lifetime of your control, instead of
every time it draws. Here's one thing to remember, though: Optimized drawing does
not guarantee performance improvements. It simply supplies a framework for how drawing
should be performed and how drawing resources should be used. A poorly written control
is still poorly written, no matter how you slice it.</P>
<P>Standard and optimized drawings have a single tradeoff and that is size versus
speed. Standard drawing does not require member variables for the drawing objects
that are created and used-- thus requiring less instance data but more processing
time--whereas optimized code is the opposite.</P>
<P>An additional drawback to optimized drawing is that a container may not support
it. A control must, at the very least, support standard drawing functionality, deferring
to optimized only if it is available.</P>
<P>For ATL (like MFC), the scope of optimized drawing is very narrow compared to
the OC 96 specification, but it will, nonetheless, result in performance improvements
if taken advantage of. The OC 96 specification further breaks optimized drawing into
what is known as aspects. For more information on aspect drawing, please see the
OC 96 specification that ships with the ActiveX SDK.
<H3><A NAME="Heading21"></A>Optimized Drawing</H3>
<P>In <A HREF="ch08.htm">Chapter 8</A>, you learn how to implement standard drawing.
In this chapter, you enhance the original implementation to take advantage of drawing
optimization.</P>
<P>Add a message handler, <TT>OnDestroy</TT>, for the Windows message <TT>WM_DESTROY</TT>.
Also add an <TT>OnDestroy</TT> function prototype to the class declaration (see Listing
9.16). <TT>OnDestroy</TT> is used to clean up the drawing resources if any are still
around when the control is destroyed. This should happen <I>only</I> if the container
supports optimized drawing.
<H3><A NAME="Heading22"></A>Listing 9.16 <SPACER TYPE="HORIZONTAL" SIZE="10">ATLCONTROLWIN.H--Drawing

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -