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

📄 ch21.htm

📁 A very good resource on Visual C++ 6.0 environment. It teaches through step by step approach and fin
💻 HTM
📖 第 1 页 / 共 5 页
字号:
to set the edit box contents to that URL.</P>
<P>OnDotsChanged() and OnImageChanged() are simple: Add the code for them both, as
presented in Listing 21.16, to the header file, after OnInitDialog().</P>
<P>
<H4>Listing 21.16&#160;&#160;DieRollPPG.h--The OnChanged Functions</H4>
<PRE>    LRESULT OnDotsChanged(WORD wNotify, WORD wID, HWND hWnd, BOOL&amp; bHandled)
    {
        SetDirty(TRUE);
        return FALSE;
    }
    LRESULT OnImageChanged(WORD wNotify, WORD wID, HWND hWnd, BOOL&amp; bHandled)
    {
        SetDirty(TRUE);
        return FALSE;
</PRE>
<PRE>    }
</PRE>
<P>The calls to SetDirty() in these functions ensure that the Apply() function will
be called when the user clicks OK on the property page.</P>
<P>The ObjectWizard generated a simple Apply() function, but it doesn't affect the
Dots or Number properties. Edit Apply() so that it resembles Listing 21.17.</P>
<P>
<H4>Listing 21.17&#160;&#160;DieRollPPG.h--CDieRollPPG::Apply()</H4>
<PRE>    STDMETHOD(Apply)(void)
    {
        USES_CONVERSION;
        BSTR image = NULL;
        GetDlgItemText(IDC_IMAGE, image);
        BOOL dots = (BOOL)::SendDlgItemMessage(m_hWnd, IDC_DOTS, 
                BM_GETCHECK, 0, 0L); 
        ATLTRACE(_T(&quot;CDieRollPPG::Apply\n&quot;));
        for (UINT i = 0; i &lt; m_nObjects; i++)
        {
            CComQIPtr&lt;IDieRoll, &amp;IID_IDieRoll&gt; pDieRoll(m_ppUnk[i]); 
            if FAILED(pDieRoll-&gt;put_Dots(dots))
            {
                CComPtr&lt;IErrorInfo&gt; pError;
                CComBSTR            strError;
                GetErrorInfo(0, &amp;pError);
                pError-&gt;GetDescription(&amp;strError);
                MessageBox(OLE2T(strError), _T(&quot;Error&quot;), MB_ICONEXCLAMATION);
                return E_FAIL;
            }
            if FAILED(pDieRoll-&gt;put_Image(image))
            {
                CComPtr&lt;IErrorInfo&gt; pError;
                CComBSTR            strError;
                GetErrorInfo(0, &amp;pError);
                pError-&gt;GetDescription(&amp;strError);
                MessageBox(OLE2T(strError), _T(&quot;Error&quot;), MB_ICONEXCLAMATION);
                return E_FAIL;
            }
        }
        m_bDirty = FALSE;
        return S_OK;
</PRE>
<PRE>    }
</PRE>
<P>Apply starts by getting dots and image from the dialog box. Notice in the call
to ::SendDlgItemMessage() that the third parameter is BM_GETCHECK, so this call ascertains
the selected state (TRUE or FALSE) of the check box. Then a call to ATLTRACE prints
a trace message to aid debugging. Like the trace statements discussed in Chapter
24, &quot;Improving Your Application's Performance,&quot; this statement disappears
in a release build.</P>
<P>The majority of Apply() is a for loop that is executed once for each control associated
with this property page. It obtains an IDieRoll interface pointer, just as in OnInitDialog(),
and tries calling the put_Dots() and put_Image() member functions of that interface.
If either call fails, a message box informs the user of the problem. After the loop,
the m_bDirty member variable can be set to FALSE.</P>
<P>Build the project at this point to be sure you have no errors.</P>
<P>
<H3><A NAME="Heading17"></A>Connecting the Property Page to CDieRoll</H3>
<P>The changes to CDieRollPPG are complete. You need to make some changes to CDieRoll
to connect it to the property page class. Specifically, the property map needs some
more entries. Add the first two entries for Dots and Image so that it looks like
Listing 21.18.</P>
<P>
<H4>Listing 21.18&#160;&#160;DieRoll.h--Property Map</H4>
<PRE>BEGIN_PROP_MAP(CDieRoll)
   PROP_ENTRY( &quot;Dots&quot;, dispidDots, CLSID_DieRollPPG)
   PROP_ENTRY( &quot;Image&quot;, dispidImage, CLSID_DieRollPPG)
   PROP_DATA_ENTRY(&quot;_cx&quot;, m_sizeExtent.cx, VT_UI4)
   PROP_DATA_ENTRY(&quot;_cy&quot;, m_sizeExtent.cy, VT_UI4)
   PROP_ENTRY(&quot;BackColor&quot;, DISPID_BACKCOLOR, CLSID_StockColorPage)
   PROP_ENTRY(&quot;ForeColor&quot;, DISPID_FORECOLOR, CLSID_StockColorPage)
</PRE>
<PRE>END_PROP_MAP()
</PRE>
<H3><A NAME="Heading18"></A>Persistence in a Property Bag</H3>
<P>In a number of different ways, Internet Explorer can get property values out of
some HTML and into a control wrapped in an &lt;OBJECT&gt; tag. With stream persistence,
provided by default, you use a DATA attribute in the &lt;OBJECT&gt; tag. If you would
like to use &lt;PARAM&gt; tags, which are far more readable, the control must support
property bag persistence through the IPersistPropertyBag interface.</P>
<P>Add another class to the list of base classes at the start of the CDieRoll class:</P>
<P>
<PRE>public IPersistPropertyBagImpl&lt;CDieRoll&gt;,
</PRE>
<P>Add this line to the COM map:</P>
<P>
<PRE>COM_INTERFACE_ENTRY(IPersistPropertyBag)
</PRE>
<P>Now you can use &lt;PARAM&gt; tags to set properties of the control.</P>
<P>
<H2><A NAME="Heading19"></A>Using the Control in Control Pad</H2>
<P>You've added a lot of code to CDieRoll and CDieRollPPG, and it's time to build
the control. After fixing any typos or minor errors, you can use the control.</P>
<P>You are going to build the HTML to display this control in Microsoft's Control
Pad. If you don't have Control Pad, it's downloadable free from <B>http://www.microsoft.com/workshop/
author/cpad/download.htm</B>. If you have a copy of Control Pad from before January
1997, find the latest one. If you use the old version, the init safe and script safe
work you will do later in this chapter will appear to malfunction.</P>


<BLOCKQUOTE>
	<P>
<HR>
<strong>NOTE:</strong> Control Pad used to serve two purposes: It simplified building &lt;OBJECT&gt;
	tags for ActiveX controls and helped developers use the HTML Layout control. Now
	that the functionality of the Layout control is in Internet Explorer 4.0, it's just
	a handy way to make &lt;OBJECT&gt; tags.&#160; 
<HR>


</BLOCKQUOTE>

<P>When you start Control pad, it makes an empty HTML document. With the cursor between
&lt;BODY&gt; and &lt;/BODY&gt;, choose Edit, Insert ActiveX Control. The Insert ActiveX
Control dialog appears: Choose DieRoll Class from the list (you might recall from
Figure 21.5 that the type name for this control is DieRoll Class) and click OK. The
control and a Properties dialog appear. Click on the Image property and enter the
full path to the image file you want to use in the edit box at the top of the Properties
dialog. (You can use any bmp file you have handy, including one you make yourself
in the Paint program that comes with Windows, or get beans.bmp from the Web site.)
Click Apply, and the control redraws with a background image, such as the jelly beans
shown in Figure 21.13. Close the Properties dialog and the Edit ActiveX Control dialog,
and you will see the HTML generated for you, including the &lt;PARAM&gt; tags that
were added because Control Pad could determine that DieRoll supports the IPersistPropertyBag
interface. Close Control Pad; you can save the HTML if you want.</P>
<P><A HREF="javascript:popUp('21uvc12.gif')"><B>FIG. 21.13</B></A><B> </B><I>Inserting
the control into Control Pad displays it for you.</I></P>
<P>The control doesn't have its full functionality yet: It doesn't roll itself when
you click it. The next section will add events.</P>
<P>
<H2><A NAME="Heading20"></A>Adding Events</H2>
<P>Two events must be added: one when the user clicks on the control and one when
the ready state changes. The Click event is discussed in Chapter 17 and the ReadyStateChanged
event is discussed in Chapter 20.</P>
<P>
<H3><A NAME="Heading21"></A>Adding Methods to the Event Interface</H3>
<P>In ClassView, right-click the _IDieRollEvents interface. Choose Add Method and
fill in the Return Type as <B>void</B> and the Method Name as <B>Click</B>; leave
the parameters blank. Figure 21.14 shows the completed dialog. Click OK to add the
method.</P>
<P><A HREF="javascript:popUp('21uvc13.gif')"><B>FIG. 21.14</B></A><B> </B><I>Add
the Click method to the event interface.</I></P>
<P>In the same way, add ReadyStateChange(), returning void and taking no parameters,
to the event interface. The dispinterface section in the idl file should now look
like this:</P>
<P>
<PRE>dispinterface _IDieRollEvents
{
   properties:
   methods:
   [id(DISPID_CLICK), helpstring(&quot;method Click&quot;)] void Click();
   [id(DISPID_READYSTATECHANGE), 
&#172;helpstring(&quot;method ReadyStateChange&quot;)] void ReadyStateChange();
};
</PRE>
<P>If the dispids appear as 1 and 2 rather than DISPID_CLICK and DISPID_READYSTATECHANGE,
edit them to match this code.</P>
<P>
<H3><A NAME="Heading22"></A>Implementing the IConnectionPoint Interface</H3>
<P>To fire events, you implement the IConnectionPoint interface. The Connection Point
Wizard will get you started, but first, save the idl file and build the project so
that the typelib associated with the project is up-to-date.</P>
<P>In ClassView, right-click CDieRoll and choose Implement Connection Point. Select
_IDieRollEvents, as in Figure 21.15, and click OK to generate a <I>proxy class</I>
for the connection point. This class will have methods you can call to fire an event.</P>
<P><A HREF="javascript:popUp('21uvc14.gif')"><B>FIG. 21.15</B></A><B> </B><I>The
Connection Point Wizard makes short work of adding events.</I></P>
<P>Look for the new class, CProxy_IDieRollEvents, in ClassView. Expand it, and you
will see it has two functions, Fire_Click() and Fire_ReadyStateChange().</P>
<P>
<H3><A NAME="Heading23"></A>Firing the Click Event</H3>
<P>When the user clicks the control, it should fire a Click event. Right-click CDieRoll
in ClassView and choose Add Windows Message Handler. Select WM_LBUTTONDOWN from the
long list on the left and click Add Handler; then click OK. You will see a new entry
in the message map:</P>
<P>
<PRE>MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
</PRE>
<P>Edit the member function OnLButtonDown() that has been added to CDieRoll, so that
it looks like Listing 21.19.</P>
<P>
<H4>Listing 21.19&#160;&#160;CDieRoll::OnLButtonDown()</H4>
<PRE>LRESULT OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &amp; bHandled)
{
   m_sNumber = Roll();
   FireOnChanged(dispidNumber);
   Fire_Click();
   FireViewChange();
   return 0;
</PRE>
<PRE>}
</PRE>
<P>This code rolls the die, fires a notification that Number has changed, fires a
Click event, and notifies the container that the control should be redrawn. Build
the control again and load the dieroll.htm page that was generated for you into Internet
Explorer. Click the die a few times and watch the displayed number change. Close
Internet Explorer, or later you'll have trouble building the project because the
DLL will be locked by Explorer.</P>
<P>
<H3><A NAME="Heading24"></A>Firing the ReadyStateChange Event</H3>
<P>Now put_Image() and OnData() can fire events when the ready state changes. There
are two ways to tell containers that ReadyState has changed: Fire_ReadyStateChange()
for older containers and, for Internet Explorer 4.0 and above, a FireOnChanged()
call exactly like the ones you've already coded for dispidImage and dispidDots.</P>
<P>In ClassView, expand CDieRoll and then expand IDieRoll underneath it. Double-click
put_Image() to edit it, and look for a line like this:</P>
<P>
<PRE>m_nReadyState = READYSTATE_LOADING;
</PRE>
<P>Add immediately after that line:</P>
<P>
<PRE>Fire_ReadyStateChange();
FireOnChanged(DISPID_READYSTATE);
</PRE>
<P>Then, later in put_Image() find this line:</P>
<P>
<PRE>m_nReadyState = READYSTATE_COMPLETE;
</PRE>
<P>Add the same two lines after this line as well. In OnData(), find this line:</P>
<P>
<PRE>m_nReadyState = READYSTATE_COMPLETE;
</PRE>
<P>Add the same two lines immediately after it.</P>
<P>Build the control again and insert it into a new page in Control Pad. Be sure
to assign the Image property so that you can see what happens while the image loads.
Click the die in the Edit ActiveX Control window, and it will roll a new number each
time that you click. Save the HTML, load it into Explorer, and see if you can roll
the die while the image loads. Click Refresh and you'll see that the image redraws
itself even if you don't click anything. As another test, open the ActiveX Control
Test container (available from the Tools menu in Developer Studio) and insert a DieRoll
control; then use the event log to confirm that Click and ReadyStateChange events
are being fired.</P>
<P>Probably the easiest and most relevant way to test the control is in Internet
Explorer 4. To do this, you specify Explorer as the executable for debug. First,
you must turn off the Active Desktop if you have it installed, because under the
Active Desktop, Explorer is always running.</P>
<P>To remove the Active desktop, first close any applications you have open, because
you're going to restart your system as part of the process. Choose Start, Settings,
Control Panel and double-click Add/Remove Programs. On the Install/Uninstall tab,
choose Microsoft Internet Explorer 4.0 and click Add/Remove. Choose the last radio
button, which says Remove the Windows Desktop Update Component, But Keep the Internet
Explorer 4.0 Web Browser. Click OK. Setup will adjust the Registry and restart your
system.</P>
<P>After the restart, open Developer Studio; load the DieRollControl project again;
choose Project, Settings; and click the Debug tab. If Internet Explorer 4 is your
default browser, click the arrow next to Executable for Debug Session and choose
Default Web Browser. If it's not, enter <B>C:\Program</B> <B>Files\Internet Explorer\IEXPLORE.EXE</B>
(or the path to Explorer on your system, if it's different) in the edit box. Under
Program Arguments, enter the path to the HTML you developed with Control Pad to test
the control. Click OK, and now whenever you choose Build, Start Debug, Go, or click
the Go button on the toolbar, Explorer will be launched, and the page that holds
the co

⌨️ 快捷键说明

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