Examining the Initial Full Control: The IDL Code

 < Free Open Study > 



Examining your new project files may give you a serious headache. The header file for your new control has an elaborate inheritance chain and a hefty COM map. Before we get to these details, we will take a high-level overview, beginning with your project's IDL file. As always, you have been provided with a [default] dual interface, library statement, and coclass definition. Because we supported the connection point protocol, we also have an empty [source] dispinterface. The major changes are due to the fact that we specified support for some stock properties, all of which are listed as [propput] and [propget] methods:

// Like any property, stock properties are documented in your IDL definition. [ object, uuid(03FBA31F-71D1-11D3-B92D-0020781238D4), dual, helpstring("IShapesControl Interface"), pointer_default(unique) ] interface IShapesControl : IDispatch {      [propput, id(DISPID_BACKCOLOR)]      HRESULT BackColor([in]OLE_COLOR clr);      [propget, id(DISPID_BACKCOLOR)]      HRESULT BackColor([out,retval]OLE_COLOR* pclr);      [propputref, id(DISPID_FONT)]      HRESULT Font([in]IFontDisp* pFont);      [propput, id(DISPID_FONT)]      HRESULT Font([in]IFontDisp* pFont);      [propget, id(DISPID_FONT)]      HRESULT Font([out, retval]IFontDisp** ppFont);      [propput, id(DISPID_CAPTION)]      HRESULT Caption([in]BSTR strCaption);      [propget, id(DISPID_CAPTION)]      HRESULT Caption([out,retval]BSTR* pstrCaption); };

As you can see, each stock property has been listed with the correct preassigned DISPID which has been assigned to the correct underlying data type. All [propget] functions are configured to support [out, retval] parameters, allowing integration among various COM language mappings.

The Updated Registry Script (RGS) File

Like any COM object, ActiveX controls need to be registered with the system before they are ready for use. However, unlike a simple coclass, ActiveX controls have a number of additional values to be registered. If your COM object is indeed a control, the Control subkey should be added. As controls have a bitmap that is used for the toolbar icon, a ToolboxBitmap32 key should be added to provide the path to the valid BMP file. The set of additions can be seen under HKCR\CLSID\{<guid>}:

click to expand
Figure 14-11: Additional registration details for an ActiveX control.

Of course, your RGS file has been modified to insert these necessary entries:

HKCR {      AXShapesServer.ShapesControl.1 = s 'ShapesControl Class'      {           CLSID = s '{03FBA320-71D1-11D3-B92D-0020781238D4}'           'Insertable'      }      AXShapesServer.ShapesControl = s 'ShapesControl Class'      {           CLSID = s '{03FBA320-71D1-11D3-B92D-0020781238D4}'           CurVer = s 'AXShapesServer.ShapesControl.1'      }      NoRemove CLSID      {           ForceRemove {03FBA320-71D1-11D3-B92D-0020781238D4} = s           'ShapesControl Class'           {                ProgID = s 'AXShapesServer.ShapesControl.1'                VersionIndependentProgID = s 'AXShapesServer.ShapesControl'                ForceRemove 'Programmable'                InprocServer32 = s '%MODULE%'                {                     val ThreadingModel = s 'Apartment'                }                ForceRemove 'Control'                ForceRemove 'Insertable'                ForceRemove 'ToolboxBitmap32' = s '%MODULE%, 101'                'MiscStatus' = s '0'                {                 '1' = s '131473'                }                'TypeLib' = s '{03FBA313-71D1-11D3-B92D-0020781238D4}'                'Version' = s '1.0'           }      } } 

As you can see, you are given the standard ProgID entries, and a number of new settings under HKCR\CLSID. As we specified that ShapesControl is usable from OLE containers, we have an entry for the Insertable subkey. MiscStatus represents the combination of bits based on your selections in the Miscellaneous tab. The most interesting addition to your RGS file is the ToolboxBitmap32 entry.

The ATL Object Wizard has provided you with a new custom bitmap resource which can be found on the ResourceView tab and is shown in Figure 14-12. The location of this bitmap image will be set to the value of the ToolbarBitmap32 subkey.


Figure 14-12: The initial toolbox image.

To really take ownership of your controls, you should edit this image with the Visual Studio resource tools to represent the essence of your control. ShapesControl has such an updated image, which will be seen whenever you include your control into some IDE for use (Figure 14-13):


Figure 14-13: Our updated toolbar bitmap image.

Dissecting the Inheritance Chain of a Full Control

Most of the interesting code generation has taken place within the header file of CShapesControl. Although the list of inherited functionality looks intimidating, you have already seen a few of these ATL templates over the course of this book. For example, IConnectionPointContainerImpl<> is present given that your control supports connect- able objects. Because a Full Control is just a fancy COM object, CComObjectRootEx<> still provides the hooks for IUnknown. CComCoClass<> is still used to provide a default class factory. IProvideClassInfo2Impl<> is also present in a Full Control (recall that IProvideClassInfo2 is used to discover the [default, source] dispinterface of your class). We will get to know the additional templates later in this chapter, but here is an initial (and commented) look at each base class template:

// The inheritance chain for a Full Control. class ATL_NO_VTABLE CShapesControl :      // Support for IUnknown.      public CComObjectRootEx<CComSingleThreadModel>,      // Support for stock properties (and marks the [default] interface).      public CStockPropImpl<CShapesControl, IShapesControl, &IID_IShapesControl,                           &LIBID_AXSHAPESSERVERLib>,      // Establishes communication with container & provides windowing support.      public CComControl<CShapesControl>,      // Persistence support.      public IPersistStreamInitImpl<CShapesControl>,      // Support for ambient notifications.      public IOleControlImpl<CShapesControl>,      // Provides linking & embedding services.      public IOleObjectImpl<CShapesControl>,      // More linking & embedding services.      public IOleInPlaceActiveObjectImpl<CShapesControl>,      // Support for IViewObject(2)[Ex]      public IViewObjectExImpl<CShapesControl>,      // Behavior for a windowless control (drag & drop & windows messages)      public IOleInPlaceObjectWindowlessImpl<CShapesControl>,      // Connection point protocol.      public IConnectionPointContainerImpl<CShapesControl>,      // Support to persist properties into a storage.      public IPersistStorageImpl<CShapesControl>,      // Allows client to obtains CLSIDs for the set of pages used with this control.      public ISpecifyPropertyPagesImpl<CShapesControl>,      // Support for fast activation of object.      public IQuickActivateImpl<CShapesControl>,      // Uniform data transfer.      public IDataObjectImpl<CShapesControl>,      // Obtain [default, source] and type information.      public IProvideClassInfo2Impl<&CLSID_ShapesControl,                &DIID__IShapesControlEvents, &LIBID_AXSHAPESSERVERLib>,      // Informs container a [bindable] property has changed.      public IPropertyNotifySinkCP<CShapesControl>,      // Class factory.      public CComCoClass<CShapesControl, &CLSID_ShapesControl> { ... };

After we complete the ShapesControl, we will take a more detailed look at many of these ATL classes and the services they provide. For the time being, let's examine the rest of the generated code.

Wizard-Generated Maps

If you examine your control's COM map, you will see that each interface brought into the CShapesControl coclass has been given an interface entry. Remember that when your coclass supports a COM interface that does not derive directly from IUnknown, a separate provision must be made for each base interface. For example IViewObject, IViewObject2, and IViewObjectEx are all present in your COM map, although IViewObjectExImpl<> provides implementation of each interface:

// As mentioned, ActiveX controls express themselves with a number of // COM interfaces! BEGIN_COM_MAP(CShapesControl)      COM_INTERFACE_ENTRY(IShapesControl)     // Your [default] interface.      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(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) END_COM_MAP()

Also notice that you are provided with a default message map, allowing this control to respond to various Windows messages. Like a traditional window, your ActiveX control may populate the message map using any of the messaging macros detailed in Chapter 13. Here is the initial listing:

// Your initial message map. BEGIN_MSG_MAP(CShapesControl)      CHAIN_MSG_MAP(CComControl<CShapesControl>)      DEFAULT_REFLECTION_HANDLER() END_MSG_MAP()

Your control's message map "inherits" the map defined by the CComControl<> base class template. If you examine the MSG map for CComControl<>, you will see your derived ActiveX object already responds to the following windows messages:

// Messages provided to your control from CComControl<>. // <atlctl.h> BEGIN_MSG_MAP(thisClass)      MESSAGE_HANDLER(WM_PAINT, CComControlBase::OnPaint)      MESSAGE_HANDLER(WM_SETFOCUS, CComControlBase::OnSetFocus)      MESSAGE_HANDLER(WM_KILLFOCUS, CComControlBase::OnKillFocus)      MESSAGE_HANDLER(WM_MOUSEACTIVATE, CComControlBase::OnMouseActivate) END_MSG_MAP()

As we specified the ShapesControl to support the connection point mechanism, we have a connection point map in place, with a default listing for the IPropertyNotifySink interface (we will have more to say about its role later on). Your [default, source] interface is not yet a part of this map, as we have not run the Implement Connection Point Wizard:

// Your initial connection point map. BEGIN_CONNECTION_POINT_MAP(CShapesControl)      CONNECTION_POINT_ENTRY(IID_IPropertyNotifySink) END_CONNECTION_POINT_MAP()

The final map of your ATL control is the property map. This map is used to persist the values of your custom properties, using a client-specified persistence protocol. This same map is used to specify any property pages used by this control. We will discuss this map, and persistence in general, later in the chapter. Here is the initial listing:

// The ATL property map is used to specify property pages for this control // as well as providing support for property persistence. BEGIN_PROP_MAP(CShapesControl)      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("Caption", DISPID_CAPTION, CLSID_NULL)      PROP_ENTRY("Font", DISPID_FONT, CLSID_StockFontPage)      // Example entries      // PROP_ENTRY("Property Description", dispid, clsid)      // PROP_PAGE(CLSID_StockColorPage) END_PROP_MAP()



 < Free Open Study > 



Developer's Workshop to COM and ATL 3.0
Developers Workshop to COM and ATL 3.0
ISBN: 1556227043
EAN: 2147483647
Year: 2000
Pages: 171

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net