如何使ATL控制持久性未来证明?

时间:2010-04-08 14:25:33

标签: c++ controls activex atl

我有一个使用ATL创建的自定义按钮控件。某些复合控件和许多对话框使用此控件。我刚刚向按钮控件添加了一些新属性,发现我必须更新所有使用它的控件和对话框。这是一个非常糟糕的情况所以我想知道我是否可以做得更好。

以下是一些相关的代码:

class ATL_NO_VTABLE CSMButton :
    public CComObjectRootEx<CComSingleThreadModel>,
    public CStockPropImpl<CSMButton, ISMButton>,
    public IPersistStreamInitImpl<CSMButton>,
    public IOleControlImpl<CSMButton>,
    public IOleObjectImpl<CSMButton>,
    public IOleInPlaceActiveObjectImpl<CSMButton>,
    public IViewObjectExImpl<CSMButton>,
    public IOleInPlaceObjectWindowlessImpl<CSMButton>,
    public ISupportErrorInfo,
    public IConnectionPointContainerImpl<CSMButton>,
    public IConnectionPointImpl<CSMButton, &DIID__ISMButtonEvents>,
    public CProxy_ISMButtonEvents<CSMButton>,
    public IPersistStorageImpl<CSMButton>,
    public ISpecifyPropertyPagesImpl<CSMButton>,
    public IQuickActivateImpl<CSMButton>,
#ifndef _WIN32_WCE
    public IDataObjectImpl<CSMButton>,
#endif
    public IProvideClassInfo2Impl<&CLSID_SMButton, &__uuidof(_ISMButtonEvents), &LIBID_BaseControlsLib>,
#ifdef _WIN32_WCE // IObjectSafety is required on Windows CE for the control to be loaded correctly
    public IObjectSafetyImpl<CSMButton, INTERFACESAFE_FOR_UNTRUSTED_CALLER>,
#endif
    public CComCoClass<CSMButton, &CLSID_SMButton>,
    public CComControl<CSMButton>
{ 
...
BEGIN_COM_MAP(CSMButton)
    COM_INTERFACE_ENTRY(ISMButton)
    COM_INTERFACE_ENTRY(IDispatch)
    COM_INTERFACE_ENTRY(IViewObjectEx)
    COM_INTERFACE_ENTRY(IViewObject2)
    COM_INTERFACE_ENTRY(IViewObject)
    COM_INTERFACE_ENTRY(IOleInPlaceObjectWindowless)
    COM_INTERFACE_ENTRY(IOleInPlaceObject)
    COM_INTERFACE_ENTRY2(IOleWindow, IOleInPlaceObjectWindowless)
    COM_INTERFACE_ENTRY(IOleInPlaceActiveObject)
    COM_INTERFACE_ENTRY(IOleControl)
    COM_INTERFACE_ENTRY(IOleObject)
    COM_INTERFACE_ENTRY(IPersistStreamInit)
    COM_INTERFACE_ENTRY2(IPersist, IPersistStreamInit)
    COM_INTERFACE_ENTRY(ISupportErrorInfo)
    COM_INTERFACE_ENTRY(IConnectionPointContainer)
    COM_INTERFACE_ENTRY(ISpecifyPropertyPages)
    COM_INTERFACE_ENTRY(IQuickActivate)
    COM_INTERFACE_ENTRY(IPersistStorage)
#ifndef _WIN32_WCE
    COM_INTERFACE_ENTRY(IDataObject)
#endif
    COM_INTERFACE_ENTRY(IProvideClassInfo)
    COM_INTERFACE_ENTRY(IProvideClassInfo2)
#ifdef _WIN32_WCE // IObjectSafety is required on Windows CE for the control to be loaded correctly
    COM_INTERFACE_ENTRY_IID(IID_IObjectSafety, IObjectSafety)
#endif
END_COM_MAP()

BEGIN_PROP_MAP(CSMButton)
    PROP_DATA_ENTRY("_cx", m_sizeExtent.cx, VT_UI4)
    PROP_DATA_ENTRY("_cy", m_sizeExtent.cy, VT_UI4)
    PROP_ENTRY_TYPE("Caption", DISPID_CAPTION, CLSID_NULL, VT_BSTR)
    PROP_ENTRY_TYPE("Colour", DISPID_COLOUR, CLSID_NULL, VT_COLOR)
    PROP_ENTRY_TYPE("ButtonType", DISPID_BUTTONTYPE, CLSID_NULL, VT_I4)
    PROP_ENTRY_TYPE("Toggle", DISPID_TOGGLE, CLSID_NULL, VT_BOOL)
    PROP_ENTRY_TYPE("Down", DISPID_DOWN, CLSID_NULL, VT_BOOL)
    // Example entries
    // PROP_ENTRY_TYPE("Property Name", dispid, clsid, vtType)
    // PROP_PAGE(CLSID_StockColorPage)
END_PROP_MAP()

我添加了两个VT_BOOL。在完成并构建控件之后,我在运行时显示一个对话框时得到一个断言,当我在visual studio中打开对话框时,我收到了一个警告,我不得不重新保存对话框。然后对话框在运行时运行正常。

我认为原因是对话框已将属性保存为资源中的二进制流,并且在添加新属性时,没有足够的数据来完全初始化控件。在这种情况下,我想要的行为是要设置的属性值,并且任何剩余的属性都应该具有默认值。如何实现这一目标?

不,我不能使用.net: - (

1 个答案:

答案 0 :(得分:2)

我曾经稍微修改过ATL持久化类来实现一个简单的事情。从流加载时,在启动每个属性之前,实现会检查我们是否已经在流的末尾,如果是,则它会退出循环,假设默认情况下保留了已卸载的属性。

从那以后,您可以添加新属性并向后兼容。如果您需要删除属性,请不要将其从地图上删除。相反,您需要保留该条目,但您可以将其指向伪属性设置器,这样,如果您具有早期版本控件保存的属性的持久性值,则会丢弃该条目而不会导致任何错误。

希望这有帮助。