Framework Support: COM Persistence

 < Free Open Study > 



COM objects tend to maintain a stateful existence, especially as far as ActiveX controls are concerned. As we have seen earlier in the chapter, ATL provides a property map, which is used to save and load the values of your custom properties at a container's request. COM's persistence model is unique in that different containers have unique ways to save the state of an object. Some containers wish to save an object's state out as a stream of bytes. Others may wish to save stateful information using OLE structured storage, while still others might wish to save state information using a name-value association called a property bag. Typically, a COM object does not know who is using it and what sort of persistence they wish to employ. As a COM object, the best we can do is provide support for each type of persistence and let the container use whichever persistence model it so desires.

COM provides a number of standard interfaces to support each type of client-specified persistence, the core of which is IPersist. From this base interface, a number of other standard COM interfaces are derived, each adding a number of methods to support storage into a stream, storage, or property bag. ATL provides a set of templates that takes care of the implementation behind each variety of COM persistence: IPersistStreamInitImpl<>, IPersistStorageImpl<>, and IPersistPropertyBagImpl<>. If you examine your control's inheritance chain, you can see the Object Wizard has already added support for IPersist- StreamInitImpl<> and IPersistStorageImpl<>. However, if you wish to have your control save its state into a property bag, you will have to derive from IPersistProperty- BagImpl<> (and update your COM map) yourself. This is something you should most always do, as Internet Explorer is only able to persist a control's state in using a property bag:

// To round out your control's persistence support, manually add support for // IPersistPropertyBag<>. class ATL_NO_VTABLE CShapesControl : ...      public IPersistStreamInitImpl<CShapesControl>, ...      public IPersistStorageImpl<CShapesControl>, ...      public IPersistPropertyBagImpl< CShapesControl > ... { ... BEGIN_COM_MAP(CShapesControl) ...      COM_INTERFACE_ENTRY(IPersistPropertyBag) END_COM_MAP() ... };

The nice thing about ATL's persistence support (beyond the various implementation templates) is that the property map works with all three varieties. ATL always provides a property map for full controls, which we have previously updated to support the persistence of our custom ShapeType property:

// Our property map. 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)      PROP_ENTRY("ShapeType", 1, CLSID_NULL) END_PROP_MAP() 

The ATL Property Map Macros

The BEGIN_PROP_MAP macro expands to define an array of ATL_PROPMAP_ENTRY structures, which can be obtained by the resulting GetPropMap() method. As with other ATL maps, END_PROP_MAP terminates the array:

// Property map macros are defined in <atlcom.h> #define BEGIN_PROP_MAP(theClass) \ ...      static ATL_PROPMAP_ENTRY* GetPropertyMap()\      {\           static ATL_PROPMAP_ENTRY pPropMap[] = \           { #define END_PROP_MAP() \                {NULL, 0, NULL, &IID_NULL, 0, 0, 0} \           }; \           return pPropMap; \      }

Each ATL_PROPMAP_ENTRY structure holds all relevant information of each of COM's persistence models. Here is the definition:

// The ATL property map is an array of these... struct ATL_PROPMAP_ENTRY {      LPCOLESTR szDesc;               // String name for property bags.      DISPID dispid;                  // DISPID of item being saved.      const CLSID* pclsidPropPage;    // CLSID of the property page.      const IID* piidDispatch;        // Interface which supports this property.      DWORD dwOffsetData;             // Offset to data.      DWORD dwSizeData;               // Size of item in bytes.      VARTYPE vt;                     // What kind of variable is this? };

Rather than filling the array of ATL_PROPMAP_ENTRY structures by hand, we are provided with a small set of property macros. PROP_ENTRY is used for properties that are supported by your [default] interface. If you have properties contained in another dispinterface supported on your coclass, you can specify the name of this alternative interface using PROP_ENTRY_EX. PROP_DATA_ENTRY is used to save out data in your control which cannot be obtained by a COM interface. Here is the expansion of each macro, all of which can be found in <atlcom.h>:

// These macros populate the fields of the ATL_PROPMAP_ENTRY structure. #define PROP_ENTRY(szDesc, dispid, clsid) \           {OLESTR(szDesc), dispid, &clsid, &IID_IDispatch, 0, 0, 0}, #define PROP_ENTRY_EX(szDesc, dispid, clsid, iidDispatch) \           {OLESTR(szDesc), dispid, &clsid, &iidDispatch, 0, 0, 0}, #define PROP_DATA_ENTRY(szDesc, member, vt) \           {OLESTR(szDesc), 0, &CLSID_NULL, NULL,\           offsetof(_PropMapClass, member), \           sizeof(((_PropMapClass*)0)->member), vt}, 

The property map is also used to specify which property pages are used to represent design time access to specific properties. As of yet, we do not have any custom pages in AXShapesServer.dll, and therefore we specified CLSID_NULL when listing the property map entry for ShapeType. Notice, however, that our stock BackColor and Font entries do specify particular CLSIDs which identify two stock pages:

// The property page map is also used to associate properties to pages. 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)      PROP_ENTRY("ShapeType", 1, CLSID_NULL) END_PROP_MAP()

Even though Caption is a stock property, there is not a stock page that can be used to manipulate the underlying value. Given this, it is time to learn how to build property pages using ATL.



 < 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