Figure 5   BullsEye Stock Properties

Property Name
Type
Stock DISPID
Description
BackColor
OLE_COLOR
DISPID_BACKCOLOR
Background color
BackStyle
long
DISPID_BACKSTYLE
Background style, transparent or opaque
Enabled
VARIANT_BOOL
DISPID_ENABLED
Enabled status, TRUE or FALSE
ForeColor
OLE_COLOR
DISPID_FORECOLOR
Foreground color


Figure 6   BullsEye Stock Methods

Method Name
Stock DISPID
Description
AboutBox
DISPID_ABOUTBOX
Display the control's Help About dialog
DoClick
DISPID_DOCLICK
Simulate a mouse click on the control
Refresh
DISPID_REFRESH
Redraw the control


Figure 7   BullsEye Custom Properties

Property Name
Type
Custom DISPID
Description
Application
IDispatch*
DISPID_APPLICATION
Return the IDispatch* for the hosting application
AlternateColor
OLE_COLOR
DISPID_ALTERNATECOLOR
Get/set the color of the alternate (even) rings
Beep
VARIANT_BOOL
DISPID_BEEP
Enable/disable sound effects for the control
CenterColor
OLE_COLOR
DISPID_CENTERCOLOR
Get/set the color of the center (odd) rings
Parent
IDispatch*
DISPID_PARENT
Return the IDispatch* for the control's parent
RingCount
short
DISPID_RINGCOUNT
Get/set the number of rings
RingValue
long
DISPID_RINGVALUE
Get/set the value of each ring


Figure 8   ATLInternals.idl


// ATLInternals.idl : IDL source for ATLInternals.dll
//

// This file will be processed by the MIDL tool to
// produce the type library (ATLInternals.tlb) and marshalling code.
import "oaidl.idl";
import "ocidl.idl";
import "CategorizeProperties.idl";

#include "olectl.h"


// IBullsEye Interface
[
    object,
    uuid(7DC59CC4-36C0-11D2-AC05-00A0C9C8E50D),
    dual,
    helpstring("IBullsEye Interface"),
    pointer_default(unique)
]
    interface IBullsEye : IDispatch
{
    const int DISPID_ALTERNATECOLOR = 1;
    const int DISPID_BEEP           = 2;
    const int DISPID_CENTERCOLOR    = 3;
    const int DISPID_RINGCOUNT      = 4;
    const int DISPID_RINGVALUE      = 5;
    const int DISPID_APPLICATION    = 6;
    const int DISPID_PARENT         = 7;

    [propput, id(DISPID_BACKCOLOR)] HRESULT BackColor([in]OLE_COLOR clr);
    [propget, id(DISPID_BACKCOLOR)] HRESULT BackColor(
        [out,retval]OLE_COLOR* pclr);
    [propput, id(DISPID_BACKSTYLE)] HRESULT BackStyle([in]long style);
    [propget, id(DISPID_BACKSTYLE)] HRESULT BackStyle([out,retval]long* style);
    [propput, id(DISPID_FORECOLOR)] HRESULT ForeColor([in]OLE_COLOR clr);
    [propget, id(DISPID_FORECOLOR)] HRESULT ForeColor(
        [out,retval]OLE_COLOR* pclr);
    [propput, id(DISPID_ENABLED)] HRESULT Enabled([in]VARIANT_BOOL vbool);
    [propget, id(DISPID_ENABLED)] HRESULT Enabled(
        [out,retval]VARIANT_BOOL* pbool);
    [propget, id(DISPID_ALTERNATECOLOR), helpstring("property AlternateColor"), 
    bindable, requestedit] HRESULT AlternateColor([out, retval] OLE_COLOR *pVal);
    [propput, id(DISPID_ALTERNATECOLOR), helpstring("property AlternateColor"), 
        bindable, requestedit] HRESULT AlternateColor([in] OLE_COLOR newVal);
    [propget, id(DISPID_BEEP), helpstring("property Beep"), bindable,  
        requestedit] HRESULT Beep([out, retval] VARIANT_BOOL *pVal);
    [propput, id(DISPID_BEEP), helpstring("property Beep"), bindable,  
        requestedit] HRESULT Beep([in] VARIANT_BOOL newVal);
    [propget, id(DISPID_CENTERCOLOR), helpstring("property CenterColor"), 
       bindable, requestedit] HRESULT CenterColor([out, retval] OLE_COLOR *pVal);
    [propput, id(DISPID_CENTERCOLOR), helpstring("property CenterColor"), 
        bindable, requestedit] HRESULT CenterColor([in] OLE_COLOR newVal);
    [propget, id(DISPID_RINGCOUNT), helpstring("property RingCount"), bindable, 
        requestedit] HRESULT RingCount([out, retval] short *pVal);
    [propput, id(DISPID_RINGCOUNT), helpstring("property RingCount"), bindable, 
        requestedit] HRESULT RingCount([in] short newVal);
    [propget, id(DISPID_RINGVALUE), helpstring("property RingValue"), bindable, 
        requestedit] HRESULT RingValue([in] short sRingNumber, 
        [out, retval] long *pVal);
    [propput, id(DISPID_RINGVALUE), helpstring("property RingValue"), bindable, 
        requestedit] HRESULT RingValue([in] short sRingNumber, [in] long newVal);
    [propget, id(DISPID_APPLICATION), helpstring("property Application")] HRESULT 
        Application([out, retval] LPDISPATCH *pVal);
    [propget, id(DISPID_PARENT), helpstring("property Parent")] HRESULT 
        Parent([out, retval] LPDISPATCH *pVal);

    [id(DISPID_REFRESH), helpstring("method Refresh")] HRESULT Refresh();
    [id(DISPID_DOCLICK), helpstring("method DoClick")] HRESULT DoClick();
    [id(DISPID_ABOUTBOX), helpstring("method AboutBox")] HRESULT AboutBox();
};

// Useful definitions of the event DISPIDs
const int DISPID_ONRINGHIT    = 1;
const int DISPID_ONSCORECHANGED = 2;

[
    uuid(95CD3721-FC5C-11D1-8CC3-00A0C9C8E50D),
    version(1.0),
    helpstring("ATLInternals 1.0 Type Library")
]
library ATLINTERNALSLib
{
    importlib("stdole32.tlb");
    importlib("stdole2.tlb");

    // _IBullsEyeEvents Dispatch Interface
    [
        uuid(19FF9872-36ED-11d2-AC05-00A0C9C8E50D),
        helpstring("Event interface for BullsEye Control")
    ]
    dispinterface _IBullsEyeEvents
    {
        properties:
        methods:
        [id(DISPID_ONRINGHIT)] void OnRingHit(short ringNumber);
        [id(DISPID_ONSCORECHANGED)] void OnScoreChanged(long ringValue);
    };
    
    [
        uuid(7DC59CC5-36C0-11D2-AC05-00A0C9C8E50D),
        helpstring("BullsEye Class")
    ]
    coclass BullsEye
    {
        [default] interface IBullsEye;
        [default, source] dispinterface _IBullsEyeEvents;
    };

    [
        uuid(7DC59CC8-36C0-11D2-AC05-00A0C9C8E50D),
        helpstring("BullsEyePropPage Class")
    ]
    coclass BullsEyePropPage
    {
        interface IUnknown;
    };
};


Figure 9   BullsEye Custom Events

Event
Event DISPID
Description
void OnRingHit
(short sRingNumber)
DISPID_ONRINGHIT
The user clicked on one of the bull's-eye rings. The argument specifies the ring the user clicked. Rings are numbered from 1 to n from the center outwards.
void OnScoreChanged
(long RingValue)
DISPID_ONSCORECHANGED
This event follows the OnRingHit event when the user clicks on a bull's-eye ring. The argument specifies the score value of the ring the user clicked.


Figure 13   BullsEye


/////////////////////////////////////////////////////////////////////////////
// CBullsEye
class ATL_NO_VTABLE CBullsEye :
    // COM object support
    public CComObjectRootEx<CComSingleThreadModel>,
    // Class object support
    public CComCoClass<CBullsEye, &CLSID_BullsEye>,
    // Default dual (IDispatch-derived) interface to control
    // Request for properties preprocessed by stock property base class
    public CStockPropImpl<CBullsEye, IBullsEye, &IID_IBullsEye,
        &LIBID_ATLInternalsLib>,
    // Error info support for default dual interface 
    public ISupportErrorInfo,
    // Basic "Lite" Control implementation
    public CComControl<CBullsEye>,
    public IOleControlImpl<CBullsEye>,
    public IOleObjectImpl<CBullsEye>,
    public IOleInPlaceActiveObjectImpl<CBullsEye>,
    public IOleInPlaceObjectWindowlessImpl<CBullsEye>,
    public IViewObjectExImpl<CBullsEye>,
    // "Lite" control persistence implementation 
    public IPersistStreamInitImpl<CBullsEye>,
    // Full control additional implementations
    // Support for OLE embedding
    public IDataObjectImpl<CBullsEye>,
    public IPersistStorageImpl<CBullsEye>,
    // Support for property pages 
    public ISpecifyPropertyPagesImpl<CBullsEye>,
    // Support for fast activation
    public IQuickActivateImpl<CBullsEye>,
    // Connection point implementation 
    public IConnectionPointContainerImpl<CBullsEye>,
    public IProvideClassInfo2Impl<&CLSID_BullsEye, &DIID__IBullsEyeEvents,
                              &LIBID_ATLInternalsLib>,
    // Full controls supporting connection points
    // also receive property change notification support
    public IPropertyNotifySinkCP<CBullsEye>
{
public:
    CBullsEye() { }

DECLARE_REGISTRY_RESOURCEID(IDR_BULLSEYE)
DECLARE_PROTECT_FINAL_CONSTRUCT()

BEGIN_COM_MAP(CBullsEye)
    // Default dual (IDispatch-derived) interface to control
    COM_INTERFACE_ENTRY(IBullsEye)
    COM_INTERFACE_ENTRY(IDispatch)
    // Error info support for default dual interface 
    COM_INTERFACE_ENTRY(ISupportErrorInfo)
    // Basic "Lite" Control implementation
    COM_INTERFACE_ENTRY(IOleControl)
    COM_INTERFACE_ENTRY(IOleObject)
    COM_INTERFACE_ENTRY(IOleInPlaceActiveObject)
    COM_INTERFACE_ENTRY(IOleInPlaceObject)
    COM_INTERFACE_ENTRY(IOleInPlaceObjectWindowless)
    COM_INTERFACE_ENTRY2(IOleWindow, IOleInPlaceObjectWindowless)
    COM_INTERFACE_ENTRY(IViewObjectEx)
    COM_INTERFACE_ENTRY(IViewObject2)
    COM_INTERFACE_ENTRY(IViewObject)
    // "Lite" control persistence implementation 
    COM_INTERFACE_ENTRY(IPersistStreamInit)
    COM_INTERFACE_ENTRY2(IPersist, IPersistStreamInit)
    // Full control additional implementations
    // Support for OLE embedding
    COM_INTERFACE_ENTRY(IDataObject)
    COM_INTERFACE_ENTRY(IPersistStorage)
    // Support for property pages 
    COM_INTERFACE_ENTRY(ISpecifyPropertyPages)
    // Support for fast activation
    COM_INTERFACE_ENTRY(IQuickActivate)
    // Support for Connection Points    
    COM_INTERFACE_ENTRY(IConnectionPointContainer)
    COM_INTERFACE_ENTRY(IProvideClassInfo2)
    COM_INTERFACE_ENTRY(IProvideClassInfo)
END_COM_MAP()

// Initially, the control's stock properties are the only
// properties supported via persistence and property pages
BEGIN_PROP_MAP(CBullsEye)
    PROP_DATA_ENTRY("_cx", m_sizeExtent.cx, VT_UI4)
    PROP_DATA_ENTRY("_cy", m_sizeExtent.cy, VT_UI4)
    PROP_ENTRY("BackColor", DISPID_BACKCOLOR, CLSID_StockColorPage)
    PROP_ENTRY("BackStyle", DISPID_BACKSTYLE, CLSID_NULL)
    PROP_ENTRY("Enabled", DISPID_ENABLED, CLSID_NULL)
    PROP_ENTRY("ForeColor", DISPID_FORECOLOR, CLSID_StockColorPage)
END_PROP_MAP()

// Initially, enabling connection point support for a full control
// only supports property change notifications
BEGIN_CONNECTION_POINT_MAP(CBullsEye)
    CONNECTION_POINT_ENTRY(IID_IPropertyNotifySink)
END_CONNECTION_POINT_MAP()

// Initially, the control passes all Windows messages to the base class
BEGIN_MSG_MAP(CBullsEye)
    CHAIN_MSG_MAP(CComControl<CBullsEye>)
    DEFAULT_REFLECTION_HANDLER()
END_MSG_MAP()

// ISupportsErrorInfo
    STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid)
    { // Implementation deleted for clarity. . . }

// IViewObjectEx
    DECLARE_VIEW_STATUS(VIEWSTATUS_SOLIDBKGND | VIEWSTATUS_OPAQUE)

// IBullsEye
public:

    HRESULT OnDraw(ATL_DRAWINFO& di)
    { // . . . Sample drawing code omitted for clarity }

    // Initially, the only member variables are those for the stock properties    
    OLE_COLOR m_clrBackColor;
    LONG m_nBackStyle;
    BOOL m_bEnabled;
    OLE_COLOR m_clrForeColor;
};
 

Figure 14   CStockPropImpl Properties

Stock Property
Data Member
APPEARANCE
m_nAppearance
AUTOSIZE
m_bAutoSize
BACKCOLOR
m_clrBackColor
BACKSTYLE
m_nBackStyle
BORDERCOLOR
m_clrBorderColor
BORDERSTYLE
m_nBorderStyle
BORDERVISIBLE
m_bBorderVisible
BORDERWIDTH
m_nBorderWidth
CAPTION
m_bstrCaption
DRAWMODE
m_nDrawMode
DRAWSTYLE
m_nDrawStyle
DRAWWIDTH
m_nDrawWidth
ENABLED
m_bEnabled
FILLCOLOR
m_clrFillColor
FILLSTYLE
m_nFillStyle
FONT
m_pFont
FORECOLOR
m_clrForeColor
HWND
m_hWnd
MOUSEICON
m_pMouseIcon
MOUSEPOINTER
m_nMousePointer
PICTURE
m_pPicture
READYSTATE
m_nReadyState
TABSTOP
m_bTabStop
TEXT
m_bstrText
VALID
m_bValid


Figure 15   IMPLEMENT_STOCKPROP Macro


#define IMPLEMENT_STOCKPROP(type, fname, pname, dispid) \
HRESULT STDMETHODCALLTYPE put_##fname(type pname) \
{ \
    ATLTRACE2(atlTraceControls,2,_T("CStockPropImpl::put_%s\n"), _T(#fname)); \
    T* pT = (T*) this; \
    if (pT->FireOnRequestEdit(dispid) == S_FALSE) return S_FALSE; \
    pT->m_##pname = pname; \
    pT->m_bRequiresSave = TRUE; \
    pT->FireOnChanged(dispid); \
    pT->FireViewChange(); \
    pT->SendOnDataChange(NULL); \
    return S_OK; \
} \
HRESULT STDMETHODCALLTYPE get_##fname(type* p##pname) \
{ \
    ATLTRACE2(atlTraceControls,2,_T("CStockPropImpl::get_%s\n"), _T(#fname)); \
    T* pT = (T*) this; \
    *p##pname = pT->m_##pname; \
    return S_OK; \
}