65.9K
CodeProject 正在变化。 阅读更多。
Home

改进 ATL-ActiveX 序列化

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.69/5 (10投票s)

2003年6月21日

1分钟阅读

viewsIcon

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() 调用来保存或加载,而不是每个属性一次调用,从而节省时间!

© . All rights reserved.