ATL PersistXML 实现





5.00/5 (5投票s)
2002年10月28日
2分钟阅读

130488

1296
最简单的方法是将 XML 持久性添加到现有的基于 IDispatch 的 ATL COM 对象。
引言
想想,有多少次你想向现有的 ATL COM 对象添加 PersistXML 支持? 确实,这应该像添加 IpersistPropertyBagImpl
或 IpersistStreamInitImpl
ATL 模板一样简单。 此外,这些类已经共享了属性映射的使用。
BEGIN_PROP_MAP( CMyClass ) PROP_ENTRY_EX( "Caption", DISPID_CAPTION,
CLSID_MyClassPropPage2, IID_IMyDual1 ) END_PROP_MAP( )
让我们这样做来添加 XML 支持!
接口
我使用了 IPersistVarXML
接口名称,因为 Microsoft 已经为 Commerce Server 2002 采用了 IPersistXML
,并且它不如我想要的那么方便。(它使用 BSTR
作为 XML 输入输出,而不是 VARIANT
)。
我设计了自己的 IPersistVarXML
接口(请参阅下面的 IDL 描述)。此接口支持 VARIANT
作为 XML 输入和输出。 实际上,它甚至可以使用 ISAXContentHandlerfor
(MXXMLWriter
) 进行 XML 输出!
[ 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); }; template <class T> class ATL_NO_VTABLE IPersistVarXMLImpl : public IPersistVarXML, public ISAXContentHandlerImpl<T>
此实现大量使用 Microsoft MS XML SDK(版本 3 及更高版本)。 因此,您需要在您的机器上安装msxml3.dll或更高版本。(此 DLL 始终与所有最新版本的 MS Internet Explorer 一起提供,或者可以从 www.microsoft.com/xml 单独安装)。
支持的属性
如果您的类已经从 IPerPropertyBrowsingImpl
、IPersistPropertyBagImpl
、IPersistStreamInitImpl
和 ISpecifyPropertyPagesImpl
类之一派生,并且具有 BEGIN_PROP_MAP()
宏,则 IPersistVarXMLImpl
可以重用它,您无需执行任何额外的操作!
如果您需要保存内部对象或手动处理某些 XML 条目,则可以使用 BEGIN_XML_CONTENT_MAP ()
宏。 它为 XML 解析器和保存器创建一个额外的 MAP。 此映射是可选的。
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;
如何添加 XML 支持
要向您的 ATL COM 对象添加 PersistXML 支持,您需要
- 在您的项目中添加 include:IPersistVarXMLImpl.h 和 IPersistVarXMLImpl.cpp。
#include IPersistVarXMLImpl.h
- 从
IPersistVarXMLImpl
派生您的类////////////////////////////////////////////////////// // CSystemUser class ATL_NO_VTABLE CSystemUser : public CComObjectRootEx<CComSingleThreadModel>, public CComCoClass<CSystemUser, &CLSID_SystemUser>, public IDispatchImpl
, public IPersistVarXMLImpl<CSystemUser> { - 修改 COM 映射。 将
ISAXContentHandler
和IPersistVarXML
接口添加到您的对象。BEGIN_COM_MAP(CSystemUser) COM_INTERFACE_ENTRY(ISystemUser) COM_INTERFACE_ENTRY(IDispatch) COM_INTERFACE_ENTRY(ISAXContentHandler) COM_INTERFACE_ENTRY(IPersistVarXML) END_COM_MAP()
- 添加公共成员
unsigned m_bRequiresSave:1;
- 添加和/或修改属性映射。 只添加需要 XML 持久化的属性!
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()
- 为额外功能添加 XML 上下文映射(处理动态对象创建和保存,不支持标准数据类型等)。
BEGIN_XML_CONTENT_MAP(T) XML_CONTENT_SAVE_ENTRY(&m_objInternal) XML_CONTENT_LOAD_HANDLER("ALIAS",OnXMLContextAlias) END_XML_CONTENT_MAP()
就是这样!
用途
使用 IPersistVarXML
的 LoadXML(varSource)
和 SaveXML(varDest)
函数来保存和加载 XML 内容。 VarSource
可以是所有支持的 ISAXXMLReader::parse()
Variant 类型
“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.”
(MS XML SDK manual)
varDest
可以是所有支持的 IMXWriter::output()
Variant 类型
“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.” (MS XML SDK manual)
因为此实现使用 CComDispatchDriver::PutProperty()
和 CComDispatchDriver::GetProperty()
,所以基类必须是 IDispatch
派生的。
示例应用程序
我已经创建了两个 Visual Studio 6.0 项目,作为如何轻松地向 ATL 对象添加 XML 支持的示例
- AtlPersistXmlSample.exe – 基于主对话框的应用程序,以及
- MyObjects.dll –
SystemUser
和类实现。
它可以为 Unicode 和 ASCII 平台编译。 将 AtlPersistXmlSample.dsw 工作区加载到 Visual Studio 中,构建两个项目并运行。 它演示了整个应用程序的 XML 文件保存/恢复配置,以及动态 XML 字符串生成(包括所有内部类和集合)和可视化。