ATL PersistXML Implementation

Environment: VC6, ATL

The easiest way to add XML persistence to an existing IDispatch-based ATL COM object.

Introduction

Think, how many times have you wanted to add PersistXML support to your existing ATL COM object?

It is true that it is supposed to be as easy as adding the IpersistPropertyBagImpl or IpersistStreamInitImpl ATL templates. Moreover, those classes already share the use of property maps.

BEGIN_PROP_MAP( CMyClass )
    PROP_ENTRY_EX( "Caption",DISPID_CAPTION,
CLSID_MyClassPropPage2, IID_IMyDual1 )
END_PROP_MAP( )

Let's do this to add XML support!

The Interface

I used the IPersistVarXML interface name because Microsoft has already taken IPersistXML for Commerce Server 2002 and it was less convenient than I wanted. (It uses BSTR for the XML input output instead of VARIANT.)

I designed my own IPersistVarXML interface (see the IDL description below). This interface supports VARIANT as an XML input and output. In fact, it can even use the ISAXContentHandler (MXXMLWriter) for the XML output!

[
object,
  uuid(B66873EC-BBFF-11D4-A802-112233445566),
  helpstring("IPersistVarXML Interface"),
  pointer_default(unique)
]
interface IPersistVarXML : IUnknown
{
  [propget, helpstring("property ElementName")] HRESULT
            ElementName([out, retval] BSTR* bstrElementName);
  HRESULT LoadXML([in] VARIANT varSource, [in, optional,
                  defaultvalue(0L)] IUnknown * pAttributes);
  HRESULT SaveXML([in] VARIANT varSource);
};

The Implementation

The interface IPersistVarXML is implemented via the IPersistVarXMLImpl<class T> template in IPersistVarXMLImpl.h:

template <class T>
class ATL_NO_VTABLE IPersistVarXMLImpl:
                    public IPersistVarXML,
                    public ISAXContentHandlerImpl<T>

This implementation makes heavy use of the Microsoft MS XML SDK (version 3 and higher). Therefore, you need to have msxml3.dll or higher installed on your machine. (These DLLs always come with all latest versions of MS Internet Explorer or can be installed separately from www.microsoft.com/xml).

Supported Properties

If your class is already derived from one of the IPerPropertyBrowsingImpl, IPersistPropertyBagImpl, IPersistStreamInitImpl, and ISpecifyPropertyPagesImpl classes and have the BEGIN_PROP_MAP() macro, IPersistVarXMLImpl can reuse this and you do not need to do anything extra!

If you need to save an internal object or handle some XML entries "manually," you can use the BEGIN_XML_CONTENT_MAP() macro. It creates one extra MAP for the XML parser and saver. This map is optional.

BEGIN_XML_CONTENT_MAP(CMyClass)
  XML_CONTENT_LOAD_HANDLER("ENTRY",
OnENTRY_HandleFunction)
  XML_CONTENT_ENTRY(&m_objInternal1)
  XML_CONTENT_SAVE_ENTRY(&m_objInternal2)
  XML_CONTENT_CREATE_OBJECT("ObjectName", CLSID_AnObject,
OnXMLContextCreateAnObjec)
END_XML_CONTENT_MAP()

HRESULT OnENTRY_HandleFunction(ISAXAttributes * pAttributes);
HRESULT OnXMLContextUser(IPersistVarXML* pAnOblect);

CComObjectGlobal<CMyInternalObject>    m_objInternal1;
CComObjectGlobal<CMyInternalObject>    m_objInternal2;

How to Add XML Support

To add PersistXML support to your ATL COM object, you need the following:

  • Add include: IPersistVarXMLImpl.h and IPersistVarXMLImpl.cpp in your project.


  • #include IPersistVarXMLImpl.h

  • Drive your class from IPersistVarXMLImpl:


  • ///////////////////////////////////////////////////////////
    // CSystemUser
    
    class ATL_NO_VTABLE CSystemUser :
    
      public CComObjectRootEx<CComSingleThreadModel>,
      public CComCoClass<CSystemUser,&CLSID_SystemUser>,
      public IDispatchImpl<ISystemUser,&IID_ISystemUser,
                           &LIBID_ATLPERSISTXMLSAMPLELib>,
    
    public IPersistVarXMLImpl<CSystemUser>
    
    {
    
  • Modify the com map. Add the ISAXContentHandler and IPersistVarXML interfaces to your object.
  • BEGIN_COM_MAP(CSystemUser)
      COM_INTERFACE_ENTRY(ISystemUser)
      COM_INTERFACE_ENTRY(IDispatch)
      COM_INTERFACE_ENTRY(ISAXContentHandler)
      COM_INTERFACE_ENTRY(IPersistVarXML)
    END_COM_MAP()
    
  • Add a public member,
  • unsigned m_bRequiresSave:1;
    
    as is required for all IPersistXXX interfaces.
  • Add or modify the property map. Add only properties that need to be XML persistable!
  • BEGIN_PROP_MAP(CSystemUser)
      PROP_ENTRY_EX("Name",    1, CLSID_NULL, IID_ISystemUser)
      PROP_ENTRY_EX("Address", 2, CLSID_NULL, IID_ISystemUser)
    END_PROP_MAP()
    
  • Add an XML Context map for extra functionality (handle dynamic object creation and savings, not standard data types support, and so forth).
  • BEGIN_XML_CONTENT_MAP(T)
      XML_CONTENT_SAVE_ENTRY(&m_objInternal)
      XML_CONTENT_LOAD_HANDLER("ALIAS",OnXMLContextAlias)
    END_XML_CONTENT_MAP()
    
  • That's it!

Uses

Use the LoadXML(varSource) and SaveXML(varDest) functions of IPersistVarXML to save and load XML content.

VarSource can be all supported ISAXXMLReader::parse() Variant types:

"The application can use this method to instruct the reader to begin parsing a document from a variety of sources. Supported VARIANT types are: VT_BSTR, SafeArray of bytes (VT_ARRAYVT_UI1), VT_UNK(IStream), and VT_UNK(ISequentialStream). One-level referencing is also permitted.

  VT_BYREF | VT_VARIANT d
  VT_BYREF | VT_VARIANT -> VT_BSTR
  VT_BYREF | VT_VARIANT -> IStream
  VT_BYREF | VT_VARIANT -> VT_ARRAY|VT_UI1."
(from the MS XML SDK manual)

varDest can be all supported IMXWriter::output() Variant types:

"Determines the output for MXXMLWriter. By default, the output property is a BSTR (string) value. You can also set this property to any implementation of the IStream interface, and the resulting document will be written into the provided IStream. Setting this property to the empty value (VT_EMPTY or " ") will return output to the internal string and reset it."

(from the MS XML SDK manual)

Because this implementation uses CComDispatchDriver::PutProperty() and CComDispatchDriver::GetProperty(), the base class must be IDispatch derived.

Sample Application

I have created two Visual Studio 6.0 projects as an example of how easy it is to add XML support to ATL objects:

  • AtlPersistXmlSample.exe—the main Dialog-based application
  • MyObjects.dll—SystemUser and MySystem classes implementations

It can be compiled for both the Unicode and ASCII platforms.

Load the AtlPersistXmlSample.dsw workspace into Visual Studio, build two projects, and run.



Click here for a larger image.

It demonstrates the XML file save/restore configuration for the whole application and dynamic XML string generation (including all internal classes and collections) and visualization.

Reference Material

www.microsoft.com/xml

Downloads

Download demo project - AtlPersistXmlSample.zip - 51 Kb—Simple application
Download source - PersistVarXml.zip - 18 Kb—ATL XML persistence add-on


Comments

  • Thanks!

    Posted by Legacy on 11/14/2002 12:00am

    Originally posted by: Sergey

    Great!
    Big thanks!

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: December 11, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT Market pressures to move more quickly and develop innovative applications are forcing organizations to rethink how they develop and release applications. The combination of public clouds and physical back-end infrastructures are a means to get applications out faster. However, these hybrid solutions complicate DevOps adoption, with application delivery pipelines that span across complex hybrid cloud and non-cloud environments. Check out this …

  • CentreCorp is a fully integrated and diversified property management and real estate service company, specializing in the "shopping center" segment, and is one of the premier retail service providers in North America. Company executives travel a great deal, carrying a number of traveling laptops with critical current business data, and no easy way to back up to the network outside the office. Read this case study to learn how CentreCorp implemented a suite of business continuity services that included …

Most Popular Programming Stories

More for Developers

RSS Feeds