改进 ATL-ActiveX 序列化






2.69/5 (10投票s)
2003年6月21日
1分钟阅读

50187
如果一个 ActiveX 容器需要包含多个控件,使用这种技术可以大大加快控件的序列化速度。
引言
我需要创建一个 ActiveX 容器,使其能够包含多个控件(~100、200、600...)。除了绘图方面的考虑和优化之外,当控件数量增加时,保存和加载控件的时间可能会成为一个缺点。为什么呢?如果你查看 ATL 代码中控件属性的序列化部分,你会发现 BEGIN_PROP_MAP()
宏定义了要“逐个”序列化的控件的属性。我的改进就在于此。
控件属性序列化
请参阅以下 ATL 映射示例,其中包含要序列化的控件的属性
BEGIN_PROP_MAP(CMyControl PROP_DATA_ENTRY("_cx", m_sizeExtent.cx, VT_UI4) PROP_DATA_ENTRY("_cy", m_sizeExtent.cy, VT_UI4) PROP_DATA_ENTRY("value", m_nValue, VT_I4) PROP_DATA_ENTRY("mask", m_nMask, VT_I4) PROP_ENTRY("SafFile", DISPID_CTCSafFile, CLSID_NULL) ... etc. END_PROP_MAP()
如你所见,属性的序列化是逐个定义的。当控件保存时,这会被转换为对 IPersistStreamInit::Save()
的内部调用,当控件加载时,也是如此,使用 IPersistStreamInit::Load()
。关键在于,每个 PROP_DATA_ENTRY
宏都对 IPersisteStreamInit::Load()
或 Save()
进行了内在调用(请记住,ATL-ActiveX 控件通过 IPersistStreamInitImpl<>
模板继承并实现了此接口)。
如果你同时需要保存数百个控件,并且它们有多个属性通过每次调用 IPersistStreamInit
接口来保存或加载每个属性,这可能会花费大量时间。可以通过以下代码进行改进
BEGIN_PROP_MAP(CMyControl) // (you left empty de properties map) END_PROP_MAP() typedef struct CONTROLPROPERTIES { // Define here the control properties } CONTROLPROPERTIES; CONTROLPROPERTIES m_properties; // IPersistStreamInit public: STDMETHOD(Load)( LPSTREAM pStm ) { if ( pStm == NULL ) return( E_POINTER ); pStm->Read( &m_properties, sizeof(m_properties), NULL ); return( S_OK ); } STDMETHOD(Save)( LPSTREAM pStm, BOOL fClearDirty ) { if ( pStm == NULL ) return( E_POINTER ); pStm->Write( &m_properties, sizeof(m_properties), NULL ); if ( fClearDirty ) SetDirty(FALSE); return( S_OK ); }
通过这种保存和加载方式,每个控件都通过一次 IPersistStreamInit::Save()
或 Load()
调用来保存或加载,而不是每个属性一次调用,从而节省时间!