У меня есть пользовательский элемент управления кнопки, созданный с использованием 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: - (