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

📄 ch21.htm

📁 A very good resource on Visual C++ 6.0 environment. It teaches through step by step approach and fin
💻 HTM
📖 第 1 页 / 共 5 页
字号:
their default values (see Figure 21.7). The control should be Opaque with a Solid
Background and should use a normalized DC, even though that's slightly less efficient,
because your draw code will be much easier to write.</P>


<BLOCKQUOTE>
	<P>
<HR>
<strong>TIP:</strong> If you'd like to see how a DC is normalized for an ATL control, remember
	that the entire ATL source is available to you, just as the MFC source is. In Program
	Files\Microsoft Visual Studio\VC98\ATL\ Include\\ATLCTL.CPP, you will find CComControlBase::OnDrawAdvanced(),
	which normalizes a DC and calls OnDraw() for you. 
<HR>


</BLOCKQUOTE>

<P><A HREF="javascript:popUp('21uvc07.gif')"><B>FIG. 21.7</B></A><B> </B><I>Leave
the Miscellaneous properties at the defaults.</I><B></B></P>
<H3><A NAME="Heading7"></A>Supporting Stock Properties</H3>
<P>Click the Stock Properties tab to specify which stock properties the control will
support. To add support for a stock property, select it in the Not Supported list
box; then click the &gt; button, and it will be moved to the Supported list on the
right. Add support for Background Color and Foreground Color, as shown in Figure
21.8. If you plan to support a lot of properties, use the &gt;&gt; button to move
them all to the supported list and then move back the ones you don't want to support.</P>
<P><A HREF="javascript:popUp('21uvc08.gif')"><B>FIG. 21.8</B></A><B> </B><I>Support
Background Color and Foreground Color.</I></P>
<P>Click OK on the Object Wizard to complete the control creation. At this point,
you can build the project if you want, though the control does nothing at the moment.</P>
<P>
<H2><A NAME="Heading8"></A>Adding Properties to the Control</H2>
<P>The MFC versions of DieRoll featured three stock properties: BackColor, ForeColor,
and ReadyState. The first two have been added already, but the ReadyState stock properties
must be added by hand. Also, there are two custom properties, Number and Dots, and
an asynchronous property, Image.</P>
<P>
<H3><A NAME="Heading9"></A>Code from the Object Wizard</H3>
<P>A COM class that implements or uses an interface does so by inheriting from a
class representing that interface. Listing 21.1 shows all the classes that CDieRoll
inherits from.</P>
<P>
<H4>Listing 21.1&#160;&#160;Excerpt from DieRoll.h in the DieRollControl Project--Inheritance</H4>
<PRE>class ATL_NO_VTABLE CDieRoll : 
   public CComObjectRootEx&lt;CComSingleThreadModel&gt;,
   public CStockPropImpl&lt;CDieRoll, IDieRoll, &amp;IID_IDieRoll, 
     &#172;&amp;LIBID_DIEROLLCONTROLLib&gt;,
   public CComControl&lt;CDieRoll&gt;,
   public IPersistStreamInitImpl&lt;CDieRoll&gt;,
   public IOleControlImpl&lt;CDieRoll&gt;,
   public IOleObjectImpl&lt;CDieRoll&gt;,
   public IOleInPlaceActiveObjectImpl&lt;CDieRoll&gt;,
   public IViewObjectExImpl&lt;CDieRoll&gt;,
   public IOleInPlaceObjectWindowlessImpl&lt;CDieRoll&gt;,
   public ISupportErrorInfo,
   public IConnectionPointContainerImpl&lt;CDieRoll&gt;,
   public IPersistStorageImpl&lt;CDieRoll&gt;,
   public ISpecifyPropertyPagesImpl&lt;CDieRoll&gt;,
   public IQuickActivateImpl&lt;CDieRoll&gt;,
   public IDataObjectImpl&lt;CDieRoll&gt;,
   public IProvideClassInfo2Impl&lt;&amp;CLSID_DieRoll, 
    &#172;&amp;DIID__IDieRollEvents, &amp;LIBID_DIEROLLCONTROLLib&gt;,
   public IPropertyNotifySinkCP&lt;CDieRoll&gt;,
</PRE>
<PRE>   public CComCoClass&lt;CDieRoll, &amp;CLSID_DieRoll&gt;,
</PRE>
<P>Now you can see where the <I>T</I> in ATL comes in: All these classes are template
classes. (If you aren't familiar with templates, read Chapter 26, &quot;Exceptions
and Templates.&quot;) You add support for an interface to a control by adding another
entry to this list of interface classes from which it inherits.</P>


<BLOCKQUOTE>
	<P>
<HR>
<strong>NOTE:</strong>otice that some names follow the pattern IxxxImpl: That means that
	this class implements the Ixxx interface. Classes inheriting from IxxxImpl inherit
	code as well as function names. For example, CDieRoll inherits from ISupportErrorInfo,
	not ISupportErrorInfoImpl&lt;CDieRoll&gt;, even though such a template does exist.
	That is because the code in that template implementation class isn't appropriate
	for an ATL control, so the control inherits only the names of the functions from
	the original interface and provides code for them in the source file, as you will
	shortly see.&#160; 
<HR>


</BLOCKQUOTE>

<P>Farther down the header file, you will find the COM map shown in Listing 21.2.</P>
<P>
<H4>Listing 21.2&#160;&#160;Excerpt from DieRollControl.h--COM Map</H4>
<PRE>BEGIN_COM_MAP(CDieRoll)
   COM_INTERFACE_ENTRY_IMPL(IConnectionPointContainer)
   COM_INTERFACE_ENTRY(IDieRoll)
   COM_INTERFACE_ENTRY(IDispatch)
   COM_INTERFACE_ENTRY(IViewObjectEx)
   COM_INTERFACE_ENTRY(IViewObject2)
   COM_INTERFACE_ENTRY(IViewObject)
   COM_INTERFACE_ENTRY(IOleInPlaceObjectWindowless)
   COM_INTERFACE_ENTRY(IOleInPlaceObject)
   COM_INTERFACE_ENTRY2(IOleWindow, IOleInPlaceObjectWindowless)
   COM_INTERFACE_ENTRY(IOleInPlaceActiveObject)
   COM_INTERFACE_ENTRY(IOleControl)
   COM_INTERFACE_ENTRY(IOleObject)
   COM_INTERFACE_ENTRY(IPersistStreamInit)
   COM_INTERFACE_ENTRY2(IPersist, IPersistStreamInit)
   COM_INTERFACE_ENTRY(ISupportErrorInfo)
   COM_INTERFACE_ENTRY(IConnectionPointContainer)
   COM_INTERFACE_ENTRY(ISpecifyPropertyPages)
   COM_INTERFACE_ENTRY(IQuickActivate)
   COM_INTERFACE_ENTRY(IPersistStorage)
   COM_INTERFACE_ENTRY(IDataObject)
   COM_INTERFACE_ENTRY(IProvideClassInfo)
   COM_INTERFACE_ENTRY(IProvideClassInfo2)
</PRE>
<PRE> END_COM_MAP()
</PRE>
<P>This COM map is the connection between IUnknown::QueryInterface() and all the
interfaces supported by the control. All COM objects must implement IUnknown, and
QueryInterface() can be used to determine what other interfaces the control supports
and obtain a pointer to them. The macros connect the Ixxx interfaces to the IxxxImpl
classes from which CDieRoll inherits.</P>


<BLOCKQUOTE>
	<P>
<HR>
<strong>TIP:</strong> IUnknown and QueryInterface are discussed in Chapter 13, &quot;ActiveX
	Concepts,&quot; in the section titled &quot;The Component Object Model.&quot; 
<HR>


</BLOCKQUOTE>

<P>Looking back at the inheritance list for CDieRoll, most templates take only one
parameter, the name of this class, and come from AppWizard. This entry came from
ObjectWizard:</P>
<P>
<PRE>public CStockPropImpl&lt;CDieRoll, IDieRoll, &amp;IID_IDieRoll, 
   &#172;&amp;LIBID_DIEROLLCONTROLLib&gt;,
</PRE>
<P>This line is how ObjectWizard arranged for support for stock properties. Notice
that there is no indication which properties are supported. Farther down the header
file, two member variables have been added to CDieRoll:</P>
<P>
<PRE>OLE_COLOR m_clrBackColor;
OLE_COLOR m_clrForeColor; 
</PRE>
<P>The ObjectWizard also updated DieRollControl.idl, the interface definition file,
to show these two stock properties, as shown in Listing 21.3. (Double-click on the
interface, IDieRoll, in ClassView to edit the .IDL file.)</P>
<P>
<H4>Listing 21.3&#160;&#160;Excerpt from DieRollControl.idl--Stock Properties</H4>
<PRE>    [
        object,
        uuid(2DE15F32-8A71-11D0-9B10-0080C81A397C),
        dual,
        helpstring(&quot;IDieRoll Interface&quot;),
        pointer_default(unique)
    ]
    interface IDieRoll : IDispatch
    {
    [propput, id(DISPID_BACKCOLOR)]
        HRESULT BackColor([in]OLE_COLOR clr);
    [propget, id(DISPID_BACKCOLOR)]
        HRESULT BackColor([out,retval]OLE_COLOR* pclr);
    [propput, id(DISPID_FORECOLOR)]
        HRESULT ForeColor([in]OLE_COLOR clr);
    [propget, id(DISPID_FORECOLOR)]
        HRESULT ForeColor([out,retval]OLE_COLOR* pclr);
</PRE>
<PRE>    };
</PRE>
<P>This class will provide all the support for the get and put functions and will
notify the container when one of these properties changes.</P>
<P>
<H3><A NAME="Heading10"></A>Adding the ReadyState Stock Property</H3>
<P>Although ReadyState wasn't on the stock property list in the ATL Object Wizard,
it's supported by CStockPropImpl. You can add another stock property by editing the
header and idl files. In the header file, immediately after the lines that declare
m_clrBackColor and m_clrForeColor, declare another member variable:</P>
<P>
<PRE>long m_nReadyState;
</PRE>
<P>This property will be used in the same way as the ReadyState property in the MFC
version of DieRoll: to implement Image as an asynchronous property. In DieRollControl.idl,
add these lines to the IDispatch block, after the lines for BackColor and ForeColor:</P>
<P>
<PRE>[propget, id(DISPID_READYSTATE)]
HRESULT ReadyState([out,retval]long* prs);
</PRE>
<P>You don't need to add a pair of lines to implement put for this property, because
external objects can't update ReadyState. Save the header and idl files to update
ClassView--if you don't, you won't be able to add more properties with ClassView.
Expand CDieRoll and IDieRoll in ClassView to see that the member variable has been
added to CDieRoll and a ReadyState() function has been added to IDieRoll.</P>
<P>
<H3><A NAME="Heading11"></A>Adding Custom Properties</H3>
<P>To add custom properties, you will use an ATL tool similar to the MFC ClassWizard.
Right-click on IDieRoll (the top-level one, not the one under CDieRoll) in ClassView
to open the shortcut menu shown in Figure 21.9, and choose Add Property.</P>
<P><A HREF="javascript:popUp('21uvc09.gif')"><B>FIG. 21.9</B></A><B> </B><I>ATL projects
have a different ClassView shortcut menu than MFC projects.</I></P>
<P>The Add Property to Interface dialog box, shown in Figure 21.10, appears. Choose
<B>short</B> for the type and fill in <B>Number</B> for the name. Deselect Put Function
because containers won't need to change the number showing on the die. Leave the
rest of the settings unchanged and click OK to add the property.</P>
<P><A HREF="javascript:popUp('21uvc10.gif')"><B>FIG. 21.10</B></A><B> </B><I>Add
</I><B>Number</B><I> as a read-only property.</I></P>
<P>Repeat this process for the BOOL Dots, which should have both get and put functions.
(Leave the Put radio button at PropPut.) The ClassView now shows entries under both
CDieRoll and IDieRoll related to these new properties. Try double-clicking the new
entries. For example, double-clicking get_Dots() under the IDieRoll that is under
CDieRoll opens the source (cpp) file scrolled to the get_Dots() function. Double-clicking
Dots() under the top-level IDieRoll opens the idl file scrolled to the propget entry
for Dots.</P>
<P>Although a number of entries have been added to CDieRoll, no member variables
have been added. Only you can add the member variables that correspond to the new
properties. Although in many cases it's safe to assume that the new properties are
simply member variables of the control class, they might not be. For example, Number
might have been the dimension of some array kept within the class rather than a variable
of its own.</P>
<P>Add the following to the header file, after the declarations of m_clrBackColor,
m_clrForeColor, and m_nReadyState:</P>
<P>
<PRE>short m_sNumber;
BOOL m_bDots;
</PRE>
<P>In the idl file, the new propget and propput entries use hard-coded dispids of
1 and 2, like this:</P>
<P>
<PRE>[propget, id(1), helpstring(&quot;property Number&quot;)] 
    HRESULT Number([out, retval] short *pVal);
[propget, id(2), helpstring(&quot;property Dots&quot;)] 
    HRESULT Dots([out, retval] BOOL *pVal);
[propput, id(2), helpstring(&quot;property Dots&quot;)] 
    HRESULT Dots([in] BOOL newVal); 
</PRE>
<P>To make the code more readable, use an enum of dispids. Adding the declaration
of the enum to the idl file will make it usable in both the idl and header file.
Add these lines to the beginning of DieRollControl.idl:</P>
<P>
<PRE>     typedef enum propertydispids
          {
               dispidNumber = 1,
               dispidDots = 2,
          }PROPERTYDISPIDS;
</PRE>
<P>Now you can change the propget and propput lines:</P>
<P>
<PRE>[propget, id(<B>dispidNumber</B>), helpstring(&quot;property Number&quot;)] 
    HRESULT Number([out, retval] short *pVal);
[propget, id(<B>dispidDots</B>), helpstring(&quot;property Dots&quot;)] 
    HRESULT Dots([out, retval] BOOL *pVal);
[propput, id(<B>dispidDots</B>), helpstring(&quot;property Dots&quot;)] 
    HRESULT Dots([in] BOOL newVal);
</PRE>
<P>The next step is to code the get and set functions to use the member variables.
Listing 21.4 shows the completed functions. (If you can't see these in ClassView,
expand the IDieRoll under CDieRoll.)</P>
<P>
<H4>Listing 21.4&#160;&#160;Excerpt from DieRoll.cpp--get and set Functions</H4>
<PRE>STDMETHODIMP CDieRoll::get_Number(short * pVal)
{
     *pVal = m_sNumber;
     return S_OK;
}
STDMETHODIMP CDieRoll::get_Dots(BOOL * pVal)

⌨️ 快捷键说明

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