📄 ch21.htm
字号:
<pre><font color="#008000"> m_Data = NULL;</font></pre>
<pre><font color="#008000"> m_DataLength = 0;</font></pre>
<pre><font color="#008000"> m_bstrImage = newVal;</font></pre>
<pre><font color="#008000"> LPSTR string =
W2A(m_bstrImage);</font></pre>
<pre><font color="#008000"> if (string != NULL && strlen(string) > 0)</font></pre>
<pre><font color="#008000"> {</font></pre>
<pre><font color="#008000"> // not a null string so try to load
it</font></pre>
<pre><font color="#008000"> BOOL relativeURL = FALSE;</font></pre>
<pre><font color="#008000"> if (strchr(string, ':') == NULL)</font></pre>
<pre><font color="#008000"> {</font></pre>
<pre><font color="#008000">
relativeURL = TRUE;</font></pre>
<pre><font color="#008000"> }</font></pre>
<pre><font color="#008000"> m_nReadyState = READYSTATE_LOADING;</font></pre>
<pre><font color="#008000"> HRESULT ret =
CBindStatusCallback<CDieRoll>::Download(this, </font></pre>
<pre><font color="#008000"> OnData, m_bstrImage, m_spClientSite, relativeURL);</font></pre>
<pre><font color="#008000"> } else</font></pre>
<pre><font color="#008000">
{</font></pre>
<pre><font color="#008000"> // was a null string so don't try to load it</font></pre>
<pre><font color="#008000"> m_nReadyState = READYSTATE_INTERACTIVE;</font></pre>
<pre><font color="#008000">}</font></pre>
<pre><font
color="#008000"> SetDirty(TRUE);</font></pre>
<pre><font color="#008000"> FireOnChanged(dispidImage);</font></pre>
<pre><font color="#008000"> return S_OK;</font></pre>
<pre><font color="#008000">}</font></pre>
<P>As with Numbers and Dots, the
<font color="#008000">get</font> function is straightforward, and the <font color="#008000">put</font> function is a bit more complicated. The beginning and end of the function is like <font color="#008000">put_Dots(),</font> firing notifications to check
if the variable can be changed, then other notifications that it was changed. In between is the code unique to an asynchronous property. </P>
<P>To start the download of the asynchronous property, this function will call <font
color="#008000">CBindStatusCallback<CDieRoll>::Download()</font> but first it needs to determine whether the URL in m_bstrImage is a relative or absolute URL. Use the ATL macro <font color="#008000">W2A</font> to convert the wide <font
color="#008000">BSTR</font> to an ordinary C string so that the C function <font color="#008000">strchr()</font> can be used to search for a <font color="#008000">:</font> character in the URL. A URL with no <font color="#008000">:</font> in it is assumed
to be a relative URL.</P>
<blockquote><p><img src="note.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/note.gif">
<P>A <font color="#008000">BSTR</font> is a wide (double-byte) character on all 32-bit Windows platforms. It is a narrow (single-byte) string on a PowerMac.</P>
<p><img
src="bottom.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/bottom.gif"></blockquote>
<P>In the MFC version of the dieroll control with an asynchronous image property, whenever a block of data came through, the <font color="#008000">OnDataAvailable()</font> function was called. The call to Download() arranges
for a function called <font color="#008000">OnData() to be called when data arrives. You will write the </font><font color="#008000">OnData() function</font>. Add it to the class with the other public functions and add the implementation shown in Listing
21.9 to DieRoll.cpp.</P>
<P><I>Listing 21.9—DieRoll.cpp—CDieRoll::OnData()</I></P>
<pre><font color="#008000">void CDieRoll::OnData(CBindStatusCallback<CDieRoll>* pbsc, </font></pre>
<pre><font color="#008000"> BYTE *
pBytes, DWORD dwSize)</font></pre>
<pre><font color="#008000">{</font></pre>
<pre><font color="#008000"> char *newData = new char[m_DataLength + dwSize];</font></pre>
<pre><font color="#008000"> memcpy(newData, m_Data, m_DataLength);</font></pre>
<pre><font color="#008000"> memcpy(newData+m_DataLength, pBytes, dwSize);</font></pre>
<pre><font color="#008000"> m_DataLength += dwSize;</font></pre>
<pre><font color="#008000"> delete m_Data;</font></pre>
<pre><font color="#008000"> m_Data =
newData;</font></pre>
<pre><font color="#008000"> if (ReadBitmap())</font></pre>
<pre><font color="#008000"> {</font></pre>
<pre><font color="#008000"> m_nReadyState = READYSTATE_COMPLETE;</font></pre>
<pre><font color="#008000">}</font></pre>
<pre><font color="#008000">}</font></pre>
<P>Since there is no <font color="#008000">realloc()</font> when using new, this function uses<font color="#008000"> new </font>to allocate enough <font color="#008000">char</font>s to hold the data that has
already been read (<font color="#008000">m_DataLength</font>) and the new data that is coming in (<font color="#008000">dwSize</font>), then copies <font color="#008000">m_Data</font> to this block, and the new data (<font color="#008000">pBytes</font>)
after <font color="#008000">m_Data</font>. It then attempts to convert the data that has been recieved so far into a bitmap: if this succeeds the download must be complete and the call to <font color="#008000">FireViewChange()</font> sends a notification
to the container to redraw the view. You can get the <font color="#008000">ReadBitmap()</font> function from the CD and add it to your project: it's much like the MFC version but it does not use any MFC classes like <font color="#008000">Cfile</font>.</P>
<H3><B>Drawing the Control</B></H3>
<P>Now that all the properties have been added, you can code <font color="#008000">OnDraw().</font> While the basic structure of this function is the same as in the MFC version of <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,” there is a lot more work to be done because you cannot rely on MFC to do some of it for you.</P>
<P>The structure of <font color="#008000">OnDraw()</font> is:</P>
<pre><font
color="#008000">HRESULT CDieRoll::OnDraw(ATL_DRAWINFO& di)</font></pre>
<pre><font color="#008000">// if the bitmap is ready, draw it</font></pre>
<pre><font color="#008000">// else draw a plan background using BackColor</font></pre>
<pre><font
color="#008000">// if !Dots draw a number in ForeColor</font></pre>
<pre><font color="#008000">// else draw the dots</font></pre>
<P>First, you need to test if the bitmap is ready, and draw it if possible. This code is in Listing 21.10: add it to the
existing <font color="#008000">OnDraw()</font> in place of the code left for you by AppWizard. Notice that if <font color="#008000">ReadyState</font> is <font color="#008000">READYSTATE_COMPLETE</font> but the call to <font
color="#008000">CreateDIBitmap()</font> doesn't result in a valid bitmap handle, the bitmap member variables are cleared away to make subsequent calls to this function give up a little faster. This chapter will not discuss how to draw bitmaps.</P>
<P><I>Listing 21.10—CDieRoll::OnDraw()—Use the Bitmap</I></P>
<pre><font color="#008000"> int width = (di.prcBounds->right - di.prcBounds->left + 1);</font></pre>
<pre><font color="#008000"> int height = (di.prcBounds->bottom -
di.prcBounds->top + 1); </font></pre>
<pre><font color="#008000"> BOOL drawn = FALSE;</font></pre>
<pre><font color="#008000"> if (m_nReadyState == READYSTATE_COMPLETE)</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"> hBitmap = ::CreateDIBitmap(di.hdcDraw, &bmih, CBM_INIT, lpvBits, </font></pre>
<pre><font
color="#008000"> lpbmi, DIB_RGB_COLORS);</font></pre>
<pre><font color="#008000"> if (hBitmap)</font></pre>
<pre><font color="#008000"> {</font></pre>
<pre><font color="#008000"> HDC hmemdc;</font></pre>
<pre><font color="#008000"> hmemdc = ::CreateCompatibleDC(di.hdcDraw);</font></pre>
<pre><font color="#008000"> ::SelectObject(hmemdc, hBitmap);</font></pre>
<pre><font color="#008000"> DIBSECTION
ds;</font></pre>
<pre><font color="#008000"> ::GetObject(hBitmap,sizeof(DIBSECTION),(LPSTR)&ds);</font></pre>
<pre><font color="#008000"> ::StretchBlt(di.hdcDraw,</font></pre>
<pre><font color="#008000">
di.prcBounds->left, // left</font></pre>
<pre><font color="#008000"> di.prcBounds->top, // top</font></pre>
<pre><font color="#008000"> width, // target width</font></pre>
<pre><font
color="#008000"> height, // target height</font></pre>
<pre><font color="#008000"> hmemdc, // the image</font></pre>
<pre><font color="#008000"> 0,
//offset into image -x</font></pre>
<pre><font color="#008000"> 0, //offset into image -y</font></pre>
<pre><font color="#008000"> ds.dsBm.bmWidth, // width</font></pre>
<pre><font
color="#008000"> ds.dsBm.bmHeight, // height</font></pre>
<pre><font color="#008000"> SRCCOPY); //copy it over</font></pre>
<pre><font color="#008000"> drawn =
TRUE;</font></pre>
<pre><font color="#008000"> ::DeleteObject(hBitmap);</font></pre>
<pre><font color="#008000"> hBitmap = NULL;</font></pre>
<pre><font color="#008000"> ::DeleteDC(hmemdc);</font></pre>
<pre><font color="#008000"> }</font></pre>
<pre><font color="#008000"> else</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"> }</font></pre>
<pre><font color="#008000"> }</font></pre>
<P>If the bitmap was not drawn, either because <font
color="#008000">ReadyState</font> is not <font color="#008000">READYSTATE_COMPLETE</font> yet or because there was a problem with the bitmap,<font color="#008000"> </font><font color="#008000">OnDraw()</font> draws a solid background by using the <font
color="#008000">BackColor</font> property, as shown in Listing 21.11. Add this code to OnDraw(). The SDK calls are very similar to the MFC calls used in the MFC version of DieRoll: for example <font color="#008000">::OleTranslateColor()</font> corresponds
to <font color="#008000">TranslateColor()</font>.</P>
<P><I>Listing 21.11—CDieRoll::OnDraw()—Draw a solid background</I></P>
<pre><font color="#008000"> if (!drawn)</font></pre>
<pre><font color="#008000"> {</font></pre>
<pre><font
color="#008000"> COLORREF back;</font></pre>
<pre><font color="#008000"> ::OleTranslateColor(m_clrBackColor, NULL, &back);</font></pre>
<pre><font color="#008000"> HBRUSH backbrush = ::CreateSolidBrush(back);</font></pre>
<pre><font color="#008000"> ::FillRect(di.hdcDraw, (RECT *)di.prcBounds, backbrush);</font></pre>
<pre><font color="#008000"> ::DeleteObject(backbrush);</font></pre>
<pre><font color="#008000"> }</font></pre>
<P>With the background drawn,
either as a bitmap image or a solid color, <font color="#008000">OnDraw()</font> must now tackle the foreground. Getting the foreground color is quite simple. Add these two lines to OnDraw():</P>
<pre><font color="#008000"> COLORREF fore;</font></pre>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -