The ATL implementation of these three persistence interfaces requires that your object provide a table that describes all the properties that should be saved and loaded during a persistence operation. This table is called the property map. ATL uses the property map of a class for two independent purposes: persistence support and control property page support (discussed in Chapter 11, "ActiveX Controls").
The various property map entries enable you to do the following:
The CDemagogue class's property map looks like this:
BEGIN_PROP_MAP(CDemagogue) PROP_ENTRY_EX("Speech", DISPID_SPEECH, CLSID_NULL, IID_ISpeaker) PROP_ENTRY_EX("Volume", DISPID_VOLUME, CLSID_NULL, IID_ISpeaker) PROP_ENTRY_EX("Name", DISPID_NAME, CLSID_NULL, IID_INamedObject) END_PROP_MAP()
The BEGIN_PROP_MAP and END_PROP_MAP macros define a class's property map. You list the persistent properties of an object in the property map using the PROP_ENTRY and PROP_ENTRY_EX macros. The PROP_ENTRY macro describes a property that the persistence implementation can access via the default dispatch interfacein other words, the interface retrieved when you query for IID_IDispatch. You use the PROP_ENTRY_EX macro to describe a property that the persistence implementation must access using some other specified dispatch interface. Both macros require the name of the property, the property's DISPID, and the CLSID of the property's associated property page (discussed in Chapter 11). The PROP_ENTRY_EX macro also requires the IID of the dispatch interface that supports the specified property; the PROP_ENTRY macro uses IID_IDispatch.
PROP_ENTRY (szDesc, dispid, clsid) PROP_ENTRY_EX (szDesc, dispid, clsid, iidDispatch) PROP_DATA_ENTRY (szDesc, member, vt)
You might also want to load and save member variables of your object that are not accessible via a dispatch interface. The PROP_DATA_ENTRY macro enables you to specify the name of a property, the member variable containing the value, and the VARIANT type of the variable, like so:
BEGIN_PROP_MAP(CBullsEye) PROP_DATA_ENTRY("_cx", m_sizeExtent.cx, VT_UI4) PROP_DATA_ENTRY("_cy", m_sizeExtent.cy, VT_UI4) ... END_PROP_MAP()
Effectively, the PROP_DATA_ENTRY macro causes the persistence implementation to reach into your object, access the specified member variable for the length implied by the VARIANT type, place the data into a VARIANT, and write the VARIANT to the persistent medium. This is quite handy when you have a member variable that is a VARIANT-compatible type. However, it doesn't work for noncompatible types such as indexed properties. Note that a PROP_PAGE macro also is used to associate a property to a property page; I discuss its use in Chapter 11, "ActiveX Controls." The persistence implementations skip entries in the property map made with the PROP_PAGE macro.
One caution: Don't add a PROP_ENTRY, PROP_ENTRY_EX, or PROP_DATA_ENTRY macro that has a property name with an embedded space character. Some relatively popular containers, such as Visual Basic 6, provide an implementation of IPropertyBag that cannot handle names with embedded spaces.
When you have a member variable that you want to load and save during a persistence operation, and that variable is not a VARIANT-compatible type (for example, an indexed or array variable), the property map mechanism doesn't help. You have to override the appropriate member functions of the persistence implementation classes, and read and write the variable explicitly. To do this, you need to know the basic structure of the ATL persistence implementation.