📄 ch21.htm
字号:
<pre><font color="#008000"> HRESULT Dots([in] BOOL newVal);</font></pre>
<P>The next step is to code the <font color="#008000">get</font> and <font color="#008000">set</font>
functions to use the member variables. Listing 21.4 shows the completed functions. (If you can't see these in ClassView, expand the <font color="#008000">IDieRoll</font> under <font color="#008000">CDieRoll</font>.)</P>
<P><I>Listing 21.4—Excerpt from
DieRoll.cpp—Get and Set Functions</I></P>
<pre><font color="#008000">STDMETHODIMP CDieRoll::get_Number(short * pVal)</font></pre>
<pre><font color="#008000">{</font></pre>
<pre><font color="#008000"> *pVal = m_sNumber;</font></pre>
<pre><font
color="#008000"> return S_OK;</font></pre>
<pre><font color="#008000">}</font></pre>
<pre><font color="#008000">STDMETHODIMP CDieRoll::get_Dots(BOOL * pVal)</font></pre>
<pre><font color="#008000">{</font></pre>
<pre><font color="#008000"> *pVal =
m_bDots;</font></pre>
<pre><font color="#008000"> return S_OK;</font></pre>
<pre><font color="#008000">}</font></pre>
<pre><font color="#008000">STDMETHODIMP CDieRoll::put_Dots(BOOL newVal)</font></pre>
<pre><font color="#008000">{</font></pre>
<pre><font color="#008000"> if (FireOnRequestEdit(dispidDots) == S_FALSE)</font></pre>
<pre><font color="#008000"> {</font></pre>
<pre><font color="#008000"> return S_FALSE;</font></pre>
<pre><font color="#008000"> }</font></pre>
<pre><font color="#008000"> m_bDots = newVal;</font></pre>
<pre><font color="#008000"> SetDirty(TRUE);</font></pre>
<pre><font color="#008000"> FireOnChanged(dispidDots);</font></pre>
<pre><font color="#008000">
FireViewChange();</font></pre>
<pre><font color="#008000"> return S_OK;</font></pre>
<pre><font color="#008000">}</font></pre>
<P>The code in the two <font color="#008000">get</font> functions is simple and straightforward. The <font
color="#008000">put_dots()</font> code is a little more complex, because it fires notifications. <font color="#008000">FireOnRequestEdit()</font> notifies all the <font color="#008000">IPropertyNotifySink</font> interfaces that this property is going to
change. Any one of these interfaces can deny the request, and if one does then this function will return <font color="#008000">S_FALSE</font> to forbid the change.</P>
<P>Assuming the change is allowed, the member variable is changed and the control is
marked as modified ("dirty") so that it will be saved. The call to FireOnChange() notifies the <font color="#008000">IPropertyNotifySink</font> interfaces that this property has changed, and the call to FireViewChange() tells the container to
redraw the control.</P>
<P><B>Initializing the Properties</B></P>
<P>Having added the code to get and set these properties, you should now change the CDieRoll constructor to initialize all the stock and custom properties, as shown in Listing 21.5. A stub
for the constructor is in the header file for you to edit.</P>
<P><I>Listing 21.5—Excerpt from DieRoll.h—Constructor</I></P>
<pre><font color="#008000"> CDieRoll()</font></pre>
<pre><font color="#008000"> {</font></pre>
<pre><font
color="#008000"> srand( (unsigned)time( NULL ) );</font></pre>
<pre><font color="#008000"> m_nReadyState = READYSTATE_INTERACTIVE;</font></pre>
<pre><font color="#008000"> m_clrBackColor = 0x80000000 | COLOR_WINDOW;</font></pre>
<pre><font color="#008000"> m_clrForeColor = 0x80000000 | COLOR_WINDOWTEXT;</font></pre>
<pre><font color="#008000"> m_sNumber = Roll();</font></pre>
<pre><font color="#008000"> m_bDots = TRUE;</font></pre>
<pre><font color="#008000">
}</font></pre>
<P>At the top of the header, add this line to bring in a declaration of the time() function:</P>
<pre><font color="#008000">#include "time.h"</font></pre>
<P>Just as you did in the MFC version of this control, you initialize
m_sNumber to a random number between 1 and 6, returned by the Roll() function. Add this function to CDieRoll by right-clicking on the class name in ClassView and choosing Add <U>M</U>ember Function from the shortcut menu. <font
color="#008000">Roll()</font> is <font color="#008000">protected</font>, takes no parameters, and returns a <font color="#008000">short</font>. The code for Roll() is in Listing 21.6, and was explained in <A HREF="index17.htm" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/index17.htm" target="text">Chapter 17</A>,
"Building an ActiveX Control."</P>
<P><I>Listing 21.6—CDieRoll::Roll()</I></P>
<pre><font color="#008000">short CDieRoll::Roll()</font></pre>
<pre><font color="#008000">{</font></pre>
<pre><font color="#008000"> double number =
rand();</font></pre>
<pre><font color="#008000"> number /= RAND_MAX + 1;</font></pre>
<pre><font color="#008000"> number *= 6;</font></pre>
<pre><font color="#008000"> return (short)number + 1;</font></pre>
<pre><font
color="#008000">}</font></pre>
<P><B>Adding the Asynchronous Property </B></P>
<P>Just as in <A HREF="index20.htm" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/index20.htm" target="text">Chapter 20</A>, "Building an Internet ActiveX Control," the Image property represents a bitmap to be loaded
asynchronously and used as a background image. Add the property to the interface just as Number and Dots were added. Use BSTR for the type and Image for the name. Update the enum in the idl file, so that dispidImage is 3, and edit the propget and propput
lines in the idl file to use the enum value:</P>
<pre><font color="#008000">[propget, id(dispidImage), helpstring("property Image")] </font></pre>
<pre><font color="#008000"> HRESULT Image([out, retval] BSTR *pVal);</font></pre>
<pre><font
color="#008000">[propput, id(dispidImage), helpstring("property Image")] </font></pre>
<pre><font color="#008000"> HRESULT Image([in] BSTR newVal);</font></pre>
<P>Add a member variable, <font color="#008000">m_bstrImage</font>, to the
class:</P>
<pre><font color="#008000">CComBSTR m_bstrImage;</font></pre>
<p><font color="#008000">CComBSTR</font> is an ATL wrapper class with useful member functions for manipulating a <font color="#008000">BSTR</font>.</P>
<P>A number of other member
variables must be added to handle the bitmap and the asynchronous loading. Add these lines to DieRoll.h:</P>
<pre><font color="#008000"> HBITMAP hBitmap;</font></pre>
<pre><font color="#008000"> BITMAPINFOHEADER bmih;</font></pre>
<pre><font
color="#008000"> char *lpvBits;</font></pre>
<pre><font color="#008000"> BITMAPINFO *lpbmi;</font></pre>
<pre><font color="#008000"> HGLOBAL hmem1;</font></pre>
<pre><font color="#008000"> HGLOBAL hmem2;</font></pre>
<pre><font
color="#008000"> BOOL BitmapDataLoaded;</font></pre>
<pre><font color="#008000"> char *m_Data;</font></pre>
<pre><font color="#008000"> unsigned long m_DataLength;</font></pre>
<P>The first six of these new variables are used to draw the bitmap
and will not be discussed. The last three combine to achieve the same behavior as the data path property used in the MFC version of this control.</P>
<P>Add these three lines to the constructor:</P>
<pre><font color="#008000"> m_Data =
NULL;</font></pre>
<pre><font color="#008000"> m_DataLength = 0;</font></pre>
<pre><font color="#008000"> BitmapDataLoaded = FALSE;</font></pre>
<P>Add a destructor to CDieRoll (in the header file) and add the code in listing 21.7.</P>
<P><I>Listing 21.7—CDieRoll::~CDieRoll()</I></P>
<pre><font color="#008000"> ~CDieRoll()</font></pre>
<pre><font color="#008000"> {</font></pre>
<pre><font color="#008000"> if (BitmapDataLoaded)</font></pre>
<pre><font color="#008000">
{</font></pre>
<pre><font color="#008000"> GlobalUnlock(hmem1);</font></pre>
<pre><font color="#008000"> GlobalFree(hmem1);</font></pre>
<pre><font color="#008000"> GlobalUnlock(hmem2);</font></pre>
<pre><font
color="#008000"> GlobalFree(hmem2);</font></pre>
<pre><font color="#008000"> BitmapDataLoaded = FALSE;</font></pre>
<pre><font color="#008000"> }</font></pre>
<pre><font color="#008000"> if (m_Data != NULL)</font></pre>
<pre><font color="#008000"> {</font></pre>
<pre><font color="#008000"> delete m_Data;</font></pre>
<pre><font color="#008000"> }</font></pre>
<pre><font color="#008000"> }</font></pre>
<P>The Image property has <font
color="#008000">get</font> and <font color="#008000">put</font> functions. Code them as in Listing 21.8.</P>
<P><I>Listing 21.8—DieRoll.cpp—get_Image() and put_Image()</I></P>
<pre><font color="#008000">STDMETHODIMP CDieRoll::get_Image(BSTR *
pVal)</font></pre>
<pre><font color="#008000">{</font></pre>
<pre><font color="#008000"> *pVal = m_bstrImage.Copy();</font></pre>
<pre><font color="#008000"> return S_OK;</font></pre>
<pre><font color="#008000">}</font></pre>
<pre><font
color="#008000">STDMETHODIMP CDieRoll::put_Image(BSTR newVal)</font></pre>
<pre><font color="#008000">{</font></pre>
<pre><font color="#008000"> USES_CONVERSION;</font></pre>
<pre><font color="#008000"> if (FireOnRequestEdit(dispidImage) ==
S_FALSE)</font></pre>
<pre><font color="#008000"> {</font></pre>
<pre><font color="#008000"> return S_FALSE;</font></pre>
<pre><font color="#008000"> }</font></pre>
<pre><font color="#008000">// if there was an old bitmap or data, delete
them</font></pre>
<pre><font color="#008000"> if (BitmapDataLoaded)</font></pre>
<pre><font color="#008000"> {</font></pre>
<pre><font color="#008000"> GlobalUnlock(hmem1);</font></pre>
<pre><font color="#008000">
GlobalFree(hmem1);</font></pre>
<pre><font color="#008000"> GlobalUnlock(hmem2);</font></pre>
<pre><font color="#008000"> GlobalFree(hmem2);</font></pre>
<pre><font color="#008000"> BitmapDataLoaded = FALSE;</font></pre>
<pre><font
color="#008000"> }</font></pre>
<pre><font color="#008000"> if (m_Data != NULL)</font></pre>
<pre><font color="#008000"> {</font></pre>
<pre><font color="#008000"> delete m_Data;</font></pre>
<pre><font color="#008000"> }</font></pre>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -