Click here to Skip to main content
15,896,606 members
Articles / Desktop Programming / ATL

ATL PersistXML implementation

Rate me:
Please Sign up or sign in to vote.
5.00/5 (5 votes)
28 Jul 20032 min read 127.4K   1.3K   38  
Easiest way to add XML persistence to an existing IDispatch based ATL COM object.
//IPersistVarXMLImpl.h

/////////////////////////////////////////////////////
//											
// This is a part of the ATL PersistXML add-on
// 
// Copyright (c) VitalyKatasonov.  All rights reserved.
//
// free to use everywhere!
//
// any comments send to:  vkatasonov@yahoo.com
//
/////////////////////////////////////////////////////

#ifndef __IPersistVarXMLImp_h_
#define __IPersistVarXMLImp_h_

#include "IPersistVarXML.h"
#include "atlsax.h"


#define _FACPersistVarXMLERR	0x301
#define MAKE_PERSISTVARXMLERRHRESULT( code )	MAKE_HRESULT( SEVERITY_ERROR, _FACPersistVarXMLERR, code )

#define ERR_CoCreateInstance_SAXAttributes			MAKE_PERSISTVARXMLERRHRESULT( 1 )
#define ERR_CoCreateInstance_SAXXMLReader			MAKE_PERSISTVARXMLERRHRESULT( 2 )
#define ERR_CoCreateInstance_MXXMLWriter			MAKE_PERSISTVARXMLERRHRESULT( 3 )

#define DECLARE_XML_ELEMENT_NAME(strName) \
	STDMETHOD(get_ElementName)(BSTR* pElementName) \
	{ \
		*pElementName = ::SysAllocString(OLESTR(#strName)); \
		return S_OK;\
	}

struct IPersistVarXML_CONTENT_ENTRY
{
	const wchar_t* wszDesc;
	DWORD dwOffsetData;
	DWORD dwSizeData;
	VARTYPE vt;
};

#define BEGIN_XML_CONTENT_MAP(theClass) \
	public: \
	HRESULT SaveLoadContent(ISAXContentHandler* pISAXContentHandler,ISAXAttributes * pAttributes, BSTR bstrElementName) \
	{\
		HRESULT hRes=S_OK;\
		CComPtr<IPersistVarXML>		pPersistVarXML;\
		CComBSTR	bstrEntryName;

#define XML_CONTENT_LOAD_HANDLER(szName,func)\
			if(!pISAXContentHandler)\
				if(!wcscmp(OLESTR(szName), bstrElementName))\
					hRes = func(pAttributes);

#define XML_CONTENT_CREATE_OBJECT(szName,pclsid,pmember) \
				if(!pISAXContentHandler)\
					if(!wcscmp(OLESTR(szName), bstrElementName))\
						if(SUCCEEDED(pPersistVarXML.CoCreateInstance(pclsid)))\
						{\
							if(SUCCEEDED(hRes = pPersistVarXML->LoadXML(CComVariant(m_pCurrentXMLReader),pAttributes)))\
								hRes = pmember(pPersistVarXML);\
							pPersistVarXML.Release();\
						}else\
							ATLASSERT(0);\

#define XML_CONTENT_ENTRY(pmember) \
			if(!pPersistVarXML)\
				if(SUCCEEDED(hRes=(pmember)->QueryInterface(__uuidof(IPersistVarXML), (void**)&pPersistVarXML)))\
				{\
					if(pISAXContentHandler)\
					{\
						hRes=pPersistVarXML->SaveXML(CComVariant(pISAXContentHandler));\
						pPersistVarXML.Release();\
					}else\
					{\
						pPersistVarXML->get_ElementName(&bstrEntryName);\
						if(wcscmp(bstrEntryName, bstrElementName))\
							pPersistVarXML.Release();\
						bstrEntryName.Empty();\
					}\
				}
		


#define XML_CONTENT_SAVE_ENTRY(pmember) \
			if(pISAXContentHandler)\
				if(SUCCEEDED(hRes=(pmember)->QueryInterface(__uuidof(IPersistVarXML), (void**)&pPersistVarXML)))\
				{\
					if(pISAXContentHandler)\
						hRes=pPersistVarXML->SaveXML(CComVariant(pISAXContentHandler));\
					pPersistVarXML.Release();\
				}

#define END_XML_CONTENT_MAP() \
			if(pPersistVarXML && !pISAXContentHandler)\
			{\
				hRes = pPersistVarXML->LoadXML(CComVariant(m_pCurrentXMLReader),pAttributes);\
				pPersistVarXML.Release();\
			}\
		return hRes;\
	}

HRESULT AtlIPersistVarXML_Load(ISAXAttributes * pAttributes, ATL_PROPMAP_ENTRY* pMap, void* pThis, IUnknown* pUnk);
HRESULT AtlIPersistVarXML_Save(IMXAttributes*	pIMXAttributes, ATL_PROPMAP_ENTRY* pMap, void* pThis, IUnknown* pUnk);

// IPersistFile Help functions! :)
HRESULT ATLIPersistFile_Load(LPCOLESTR pszFileName, IUnknown* pUnk);
HRESULT ATLIPersistFile_Save( LPCOLESTR pszFileName, IUnknown* pUnk);


template <class T>
class ATL_NO_VTABLE IPersistVarXMLImpl : public IPersistVarXML, 
public ISAXContentHandlerImpl<T>
{
public:
	HRESULT IPersistVarXML_SaveContent(ISAXContentHandler* pISAXContentHandler) \
	{
		T* pT = static_cast<T*>(this);
		return pT->SaveLoadContent(pISAXContentHandler,NULL,NULL);
	}

	HRESULT IPersistVarXML_LoadContent(BSTR bstrIlementName, ISAXAttributes * pAttributes)
	{
		T* pT = static_cast<T*>(this);
		return pT->SaveLoadContent(NULL,pAttributes,bstrIlementName);
	}

	HRESULT SaveLoadContent(ISAXContentHandler* pISAXContentHandler,ISAXAttributes * pAttributes, BSTR bstrElementName)
	{
		//Default Implimentation
		return S_OK;
	}

	HRESULT IPersistVarXML_Load(ISAXAttributes * pAttributes)
	{
		T* pT = static_cast<T*>(this);
		ATL_PROPMAP_ENTRY* pMap = T::GetPropertyMap();
		ATLASSERT(pMap != NULL);

		HRESULT hr = AtlIPersistVarXML_Load(pAttributes, pMap, pT, pT->GetUnknown());
		if (SUCCEEDED(hr))
			pT->m_bRequiresSave = FALSE;
		return hr;
	}
	

	HRESULT IPersistVarXML_Save(IMXAttributes*	pIMXAttributes)
	{
		T* pT = static_cast<T*>(this);
		ATL_PROPMAP_ENTRY* pMap = T::GetPropertyMap();
		ATLASSERT(pMap != NULL);

		return AtlIPersistVarXML_Save(pIMXAttributes, pMap, pT, pT->GetUnknown());
	}


	//Default Implementations:
	HRESULT StartElement (ISAXAttributes * pAttributes, BSTR ElementName)
	{
		T* pT = static_cast<T*>(this);

		HRESULT hRes = S_OK;

		USES_CONVERSION;

		if(::SysStringLen(ElementName)==0 )
		{
			//Load THIS Object!!
			return pT->IPersistVarXML_Load(pAttributes);
		}else
			return pT->IPersistVarXML_LoadContent(ElementName, pAttributes);

		return hRes;
	}

	HRESULT SaveElement (ISAXContentHandler* pISAXContentHandler)
	{
		USES_CONVERSION;
		T* pT = static_cast<T*>(this);

		HRESULT hRes = E_FAIL;

		CComBSTR bstrThisItemName;
		hRes = pT->get_ElementName(&bstrThisItemName);

		unsigned short Lenght;
		ATLASSERT(bstrThisItemName.Length());

		if(Lenght = bstrThisItemName.Length())
		{
			CComPtr<IMXAttributes>			pIMXAttributes;
			if(SUCCEEDED(hRes = pIMXAttributes.CoCreateInstance(__uuidof(SAXAttributes ))))
			{
				CComQIPtr<ISAXAttributes>		pISAXAttributes(pIMXAttributes);
				if(pISAXAttributes)
				{
					if(SUCCEEDED(hRes = pT->IPersistVarXML_Save(pIMXAttributes)))
					{
						pISAXContentHandler->startElement(L"",0,OLE2W(bstrThisItemName),Lenght,OLE2W(bstrThisItemName),Lenght,pISAXAttributes);
					}
				}
			
				if(SUCCEEDED(hRes))
				{
					hRes = pT->IPersistVarXML_SaveContent(pISAXContentHandler);

					pISAXContentHandler->endElement(L"",0,OLE2W(bstrThisItemName),Lenght,OLE2W(bstrThisItemName),Lenght);
				}

			}else
				hRes = ERR_CoCreateInstance_SAXAttributes;
					
		}
		return hRes;
	}

	// for IPersistVarXML
	CComPtr<ISAXContentHandler>	m_pPrevContentHandler;
	CComQIPtr<ISAXXMLReader>	m_pCurrentXMLReader;
	BOOL	m_nStarted;

	// ISAXContentHandler
	STDMETHOD(startElement) (
        unsigned short * pwchNamespaceUri,
        int cchNamespaceUri,
        unsigned short * pwchLocalName,
        int cchLocalName,
        unsigned short * pwchQName,
        int cchQName,
        struct ISAXAttributes * pAttributes )
	{
		T* pT = static_cast<T*>(this);

		USES_CONVERSION;

		CComBSTR bstrName(cchQName,pwchQName);
		if(m_nStarted==0)
		{
			CComBSTR bstrThisItemName;
			pT->get_ElementName(&bstrThisItemName);

			if(bstrThisItemName==bstrName)
			{
				m_nStarted++;
				return pT->StartElement (pAttributes, CComBSTR(""));
			}
		}

		return pT->StartElement (pAttributes,bstrName);
	}

	STDMETHOD(endElement)(
        unsigned short * pwchNamespaceUri,
        int cchNamespaceUri,
        unsigned short * pwchLocalName,
        int cchLocalName,
        unsigned short * pwchQName,
        int cchQName )
		{
			T* pT = static_cast<T*>(this);

			if(m_pPrevContentHandler)
			{
				USES_CONVERSION;				
				CComBSTR bstrName(cchQName,pwchQName);	
				CComBSTR bstrThisItemName;
				pT->get_ElementName(&bstrThisItemName);
				
				if(bstrThisItemName == bstrName)
				{
					ATLASSERT(m_nStarted>0);
					m_nStarted--;
					if(m_nStarted==0)
					{
						ATLASSERT(m_pPrevContentHandler);
						m_pCurrentXMLReader->putContentHandler(m_pPrevContentHandler);
						m_pPrevContentHandler.Release();
						m_pCurrentXMLReader.Release();
					}
				}	
			}

			return S_OK;
		}

        STDMETHOD(LoadXML)( 
            /* [in] */ VARIANT varSource, IUnknown * pAttributes = 0L)
		{
			T* pT = static_cast<T*>(this);

			HRESULT hRes;
			
			if(V_VT(&varSource)==VT_UNKNOWN)
			{
				m_pCurrentXMLReader = V_UNKNOWN(&varSource);
			}

			if(m_pCurrentXMLReader)
			{
				ATLASSERT(!m_pPrevContentHandler);
				m_nStarted = 1;
				hRes = m_pCurrentXMLReader->getContentHandler(&m_pPrevContentHandler);
				hRes = m_pCurrentXMLReader->putContentHandler((ISAXContentHandler*)(this));
				hRes = pT->StartElement((ISAXAttributes*)pAttributes, CComBSTR(""));
				ATLASSERT(SUCCEEDED(hRes));

			}else
			{
				m_nStarted = 0;
				if(SUCCEEDED(hRes = m_pCurrentXMLReader.CoCreateInstance(__uuidof(SAXXMLReader))))
				{
					if(SUCCEEDED(hRes = m_pCurrentXMLReader->putContentHandler(static_cast<ISAXContentHandler*>(this))))
					{
						hRes = m_pCurrentXMLReader->parse(varSource);
						ATLASSERT(SUCCEEDED(hRes));
					}

					m_pCurrentXMLReader.Release();

				}else
				{
					hRes =  ERR_CoCreateInstance_SAXXMLReader;
				}

			}
			return hRes;
		}
        
        STDMETHOD(SaveXML)( 
            /* [in] */ VARIANT VarOutput)
		{
			T* pT = static_cast<T*>(this);

			HRESULT	hRes;

			CComQIPtr<ISAXContentHandler>	pISAXContentHandler;
			if(V_VT(&VarOutput) == VT_UNKNOWN)
			{
				pISAXContentHandler = V_UNKNOWN(&VarOutput);
				if(pISAXContentHandler)
					return pT->SaveElement(pISAXContentHandler);
			}
			
			CComPtr<IMXWriter>				pXMLWriter;
			if(SUCCEEDED(hRes = pXMLWriter.CoCreateInstance(__uuidof(MXXMLWriter))))
			{
				pISAXContentHandler = pXMLWriter;
				if(pISAXContentHandler)
				{
					//Setup
					hRes = pXMLWriter->put_omitXMLDeclaration(-1);
					hRes = pXMLWriter->put_standalone(-1);
					hRes = pXMLWriter->put_indent(-1);
					hRes = pXMLWriter->put_encoding(L"ASCII");
					hRes = pXMLWriter->put_output(VarOutput);

					//Start
					hRes = pISAXContentHandler->startDocument();

					//Save this object
					hRes = pT->SaveElement(pISAXContentHandler);
					
					//Finishing
					hRes = pISAXContentHandler->endDocument();

					if(V_VT(&VarOutput) == (VT_VARIANT|VT_BYREF) )
						hRes = pXMLWriter->get_output(V_VARIANTREF(&VarOutput));

					hRes = pXMLWriter->put_output(CComVariant(""));

				}
				pXMLWriter.Release();

			}else
				hRes = ERR_CoCreateInstance_MXXMLWriter;

			return hRes;
		}
		
		//IPersistFile Implementation (Help functions)
		HRESULT IPersistFile_Load( /* [in] */ LPCOLESTR pszFileName,/* [in] */ DWORD dwMode)
		{
			T* pT = static_cast<T*>(this);
			return ATLIPersistFile_Load( pszFileName, pT->GetUnknown());
		}

		HRESULT IPersistFile_Save( /* [unique][in] */ LPCOLESTR pszFileName,/* [in] */ BOOL fRemember)
		{
			T* pT = static_cast<T*>(this);
			return ATLIPersistFile_Save( pszFileName, pT->GetUnknown());
		}
};

#endif //__IPersistVarXMLImp_h_

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions