Click to return to the Component Development home page    
Web Workshop  |  Component Development

ActiveX Control Containers


This article is an overview for ActiveX® control containers. The following sections explain how to implement and program ActiveX control containers that will function well with other controls and containers.

Introduction

An ActiveX control container supplies an environment in which an ActiveX control can run. Additionally, control containers manipulate, manage, and provide services to all the controls they contain. For example, containers supply controls with event handlers and deal with properties. At a minimum, a container must be able to host an ActiveX control. Additionally, it may support component categories, which are sets of interfaces grouped into areas of functionality and assigned a GUID. For example, data binding is a component category. A container may or may not support data binding depending on the needs of its ActiveX control. If a control needs data binding support from a container, the control enters this requirement in the registry. By using the registry information, the container offers for insertion only those controls that it can support.

ActiveX controls have become the primary architecture for developing software components for use in a variety of containers. For a control to operate well in different containers, it must be able to rely on a minimum level of container functionality.

ActiveX control containers must provide support for the following:

Container Requirements

This section addresses the requirements for interfaces, methods, status bits, and special features of ActiveX control containers.

Required and Optional Interfaces

Specific interfaces are used to program ActiveX control containers. The following table lists those interfaces and shows which are optional and which are mandatory.

InterfaceSupport Comments
IAdviseSinkOptionalThis interface is required only when the container requires notifications, such as data change notifications from controls with IDataObject, view change notifications from controls that are not active and have IViewObject2, and other notifications from controls acting as standard embedded objects.
IClassFactory2OptionalThis interface is not required but supporting it is recommended.
IDispatch for ambient propertiesRequired
IErrorInfoRequiredIErrorInfo is mandatory if a container supports dual interfaces.
IOleClientSiteRequired
IOleContainerRequiredIOleContainer is implemented on the document or form object that holds the container sites. Controls use the IOleContainer to navigate to other controls in the same document or form.
IOleControlSiteRequired
IOleInPlaceFrameRequired
IOleInPlaceSiteRequired
IPropertyNotifySinkOptionalThis interface is only needed for containers that have their own property-editing UI.
ISimpleFrameSiteOptionalThis interface, as well as support for nested simple frames is optional.

Not Required and Optional Methods

An ActiveX control container can implement an interface without implementing every method in the interface. For methods that are not mandatory the container may simply return E_NOTIMPL, S_FALSE, or S_OK, as appropriate. There are two types of nonmandatory methods; not required and optional. Methods that are not required do not need to be implemented. Optional methods must be implemented but may return E_NOTIMPL.

The following table identifies and describes the not required and optional methods. Except for the methods listed in the table, all methods from the required ActiveX control container interfaces must be implemented and cannot return E_NOTIMPL.

InterfaceMethod Comments
IDispatch for ambient propertiesGetIDsOfNamesNot required. This method is necessary only for containers that support nonstandard ambient properties.
GetTypeInfoNot required. This method is necessary only for containers that support nonstandard ambient properties.
GetTypeInfoCountNot required. This method is necessary only for containers that support nonstandard ambient properties.
IDispatch for an event sink GetIDsOfNamesNot required. This method is not necessary for an event sink.
GetTypeInfoNot required. This method is not necessary for an event sink.
GetTypeInfoCountNot required. This method is not necessary for an event sink.
IOleClientSiteGetMonikerNot required. This method is necessary only if the container supports linking to controls within its own form or document.
SaveObjectNot required. This method is necessary only if persistence is supported.
IOleContainerEnumObjectsNot required. This method is only necessary to enumerate ActiveX controls.
LockContainerNot required. This method is only necessary for containers that link to controls or other embedded objects.
ParseDisplayNameNot required. This method is only necessary for containers that link to controls or other embedded objects.
IOleControlSiteGetExtendedControlNot required. This method is only necessary for containers that support extended controls.
LockInPlaceActiveOptional
ShowPropertyFrameNot required. This method is necessary only for containers that want to include their own property pages to handle extended control properties in addition to those provided by a control.
TranslateAcceleratorNot required. This method can return S_FALSE and perform no action.
IOleInPlaceFrameContextSensitiveHelpOptional
EnableModelessOptional
GetBorderNot required. This method is necessary only for containers with toolbar UI.
InsertMenusNot required. This method is necessary only for containers with menu UI.
RemoveMenusNot required. This method is necessary only for containers with menu UI.
RequestBorderSpaceNot required. This method is necessary only for containers with toolbar UI.
SetBorderSpaceNot required. This method is necessary only for containers with toolbar UI.
SetMenusNot required. This method is necessary only for containers with menu UI.
SetStatusTextNot required. This method is necessary only for containers that have a status line.
TranslateAcceleratorOptional
IOleInPlaceSiteContextSensitiveHelpOptional
DeactivateAndUndoNot required. This method must implement deactivation, but undo is optional.
DiscardUndoStateNot required. This method can return S_OK and perform no action.
ScrollNot required. This method can return S_FALSE and perform no action.

Status Bit Support

ActiveX control containers must also recognize and support certain status bits of the OLEMISC enumeration. The following table shows which of the OLEMISC status bits are required and which are optional.

Status bitSupport Comments
ACTIVATEWHENVISIBLERequired
IGNOREACTIVATEWHENVISIBLEOptionalThis bit is set for containers hosting inactive and windowless controls.
INSIDEOUTOptional
INVISIBLEATRUNTIMERequiredThis bit designates a control that should be visible at design time, but invisible at run time.
ALWAYSRUNRequired
ACTSLIKEBUTTONOptionalSupport for this bit is normally required, although it is not necessary for document-style containers.
ACTSLIKELABELOptionalSupport for this bit is normally required, although it is not necessary for document-style containers.
NOUIACTIVATERequired
ALIGNABLEOptional
SIMPLEFRAMEOptional
SETCLIENTSITEFIRSTOptionalSupport for this bit is recommended but is not required.
SIMPLEFRAMEOptional
IMEMODEOptional

Requirements for Special Features

In addition to the mandatory interfaces, methods, and status bits, special features like keyboard handling and automatic clipping require certain functionalities for implementation. The following table lists some special feature requirements.

FeatureRequirements
Keyboard Handling The following are required for a container to support a keyboard:
  • Support for the OLEMISC status bits OLEMISC_ACTSLIKELABEL and OLEMISC_ACTSLIKEBUTTON.
  • Implementation of the DisplayAsDefault ambient property (if it exists, it can return FALSE).
  • Implementation of tab handling, including tab order.
Storage Interfaces Containers must be able to support controls that implement IPersistStorage, IPersistStream, or IPersistStreamInit. Optionally, a container can support any other persistence interface, such as IPersistMemory, IPersistPropertyBag, and IPersistMoniker.

After an ActiveX control container has selected and initialized a storage interface, the storage interface will remain the primary storage interface for the life of the control. This does not preclude the container from saving to other storage interfaces.

ActiveX control containers are not required to support IPersistPropertyBag and IPropertyBag because the "save as text" mechanism is not required.

Ambient Properties At a minimum, ActiveX control containers must support the following ambient properties using the standard DISPIDs.

Ambient PropertyDISPIDComments
LocaleID-705This property is necessary if the locale is significant to the container—for example, for formatting text output.
UserMode-709This property is necessary for containers that have different user and run environments.
DisplayAsDefault-713This property is necessary for containers that have a default button.
Extended Controls ActiveX control containers are not required to support extended controls. However, if the container does support extended controls, it must support the following:

  • Visible
  • Parent
  • Default
  • Cancel
Message Reflection ActiveX control containers are not required to support message reflection. Message reflection is the ability of a subclassed control to handle notification messages itself, rather than have them handled by the container.

Using controls that can handle their own messages results in more efficient controls. If a container supports message reflection, the MessageReflect ambient property must be supported and set to TRUE.

Automatic Clipping ActiveX control containers are not required to support automatic clipping. Automatic clipping is the ability of a container to ensure that a control's visual output goes only to the container's current clipping region.

Using containers that support automatic clipping results in more efficient controls because a control can paint without regard to its clipping region. The container will automatically clip any painting that occurs outside the control's area. If a container supports automatic clipping, the AutoClip property must be supported and set to TRUE.

Degrading When an Interface Is Not Supported

All controls do not support all interfaces. In fact, there are controls that support only the IUnknown interface. When a container encounters a control that does not support a required interface, the container must degrade.

Unsupported Interfaces

The following table describes what a container might do in the absence of a particular interface. Note that the table lists only those interfaces that a container can obtain through IUnknown::QueryInterface.

InterfaceComments
IViewObject2 If the IViewObject2 interface is unsupported, a control has no extents and at run time draws nothing. At design time, the container draws a default rectangle, so a user in a visual programming environment can select the object and check its properties, methods, and events. Your application should be prepared to handle the lack of a visual control.
IOleObject Any information (such as control extents) that a container might expect from this interface should be filled in with container-provided defaults.
IOleInPlaceObject If this interface is absent, the control does not attempt to activate in-place. Therefore no handling is required.
IOleControl In the absence of this interface, the container does not call its members.
IDataObject The control provides no property sets or visual renderings that can be cached, so in the absence of this interface the container should cache some default data.
IDispatch The control has no custom properties or methods. Therefore the container does not need to show any control properties and should not allow any custom method calls.
IConnectionPointContainer The control has no events, so the container does not have to handle events.
IProvideClassInfo2 If this interface is missing, the control either does not have type information or events, or the container must obtain the control's type information from the control's registry entries.
ISpecifyPropertyPages The control has no property pages. Therefore if the container has any UI that invokes property pages, the container should disable the UI.
IPerPropertyBrowsing The control has no display name, no predetermined strings and values, and no property-to-page mapping. This interface is used to generate a container user interface. Therefore in the absence of this interface, UI elements should be disabled.
IPersist* The control has no persistent state, so the container does not have to save any control-specific data.
IOleCache2 The control does not support caching.

Programming Considerations

This section describes some guidelines for ActiveX control and ActiveX control container developers.

Programming Guidelines

The following table offers programming suggestions to produce more reliable and interoperable components.

TopicComments
Overloading IPropertyNotifySink Many ActiveX control containers implement a modeless property browsing window. If a control's properties are altered through the control's property pages, the control's properties can get out of sync with the container's view of those properties. To ensure that a container always has the current values for a control's properties, an ActiveX control container can overload the IPropertyNotifySink interface and use it to notify the container that a control property has changed.
Container-Specific private interfaces Some containers provide container-specific private interfaces for additional functionality or improved performance. Controls that rely on container-specific interfaces should, if possible, work without those interfaces so that the control will function in different containers. For example, Microsoft® Visual Basic® implements private interfaces that provide string formatting functionality to controls. If a control makes use of those private interfaces, it should be able to run with default formatting support if the interfaces are not available.
Multithreaded issues ActiveX provides support for multithreaded applications, allowing applications to make ActiveX calls from multiple threads. This multithreaded support is called the "apartment model." It is important that all ActiveX components using multiple threads follow this model. For more information about apartment model threading, refer to the Platform Software Development Kit (SDK) documentation.
Event freezing A container can notify a control that it is not ready to respond to events by calling IOleControl::FreezeEvents(TRUE). When a container freezes events, it is freezing event processing, not event receiving. A container can still receive events while events are frozen. If a container receives an event notification while its events are frozen, the container should ignore the event. If it is important for a control to process an event, the control should take note of an IOleControl::FreezeEvents(TRUE) call. While a container's event processing is frozen, a control should implement one of the following techniques:
  • Fire the events knowing that the container will take no action.
  • Discard all events that the control would fire.
  • Queue up all pending events and fire them after the container calls IOleControl::FreezeEvents(FALSE).
  • Queue up only relevant or important events and fire them after the container calls IOleControl::FreezeEvents(FALSE).
WS_GROUP and WS_TABSTOP flags in controls A control should not use the WS_GROUP and WS_TABSTOP flags internally. Some containers rely on these flags to manage keyboard handling.
Multiple controls in one DLL A single .ocx DLL can contain any number of ActiveX controls, simplifying the distribution and use of a set of related controls. If you ship multiple controls in a single DLL, be sure to include the vendor name in each control name. Including the vendor's name in each control enables users to easily identify controls within a package. For example, if you ship a DLL that implements three controls, Con1, Con2, and Con3, the control names should be:
<Your company name> Con1 Control
<Your company name> Con2 Control
<Your company name> Con3 Control
IOleContainer::EnumObjects This method is used to enumerate all the OLE objects contained in a document or form, returning an interface pointer for each object. The container must return pointers to each ActiveX object that shares the same container. Nested forms or nested controls must also be enumerated.

Some containers implement extender controls, which wrap non-ActiveX controls, and then return a pointer to these extender controls as a form is enumerated. This behavior enables ActiveX controls and ActiveX control containers to integrate well with non-ActiveX controls.

Enhanced metafile Enhanced metafiles provide more functionality than standard metafiles. Using enhanced metafiles generally simplifies rendering code. An enhanced metafile device context (DC) is used in exactly the same way as a standard metafile DC. A 32-bit ActiveX control container should use enhanced metafiles, but 16-bit containers must use standard metafiles. ActiveX supports enhanced metafiles and includes backward compatibility with standard metafiles.
Licensing In order to embed licensed controls successfully, ActiveX control containers must use IClassFactory2 instead of IClassFactory. Several ActiveX creation and loading helper functions, such as OleLoad and CoCreateInstance, call IClassFactory and not IClassFactory2, and therefore cannot be used to create or load licensed ActiveX controls.
Dual interfaces OLE automation enables an object to expose a set of methods in two ways: through the IDispatch interface and through direct OLE Vtable binding. IDispatch offers late binding support, but Vtable binding offers performance gain. Both techniques are valuable and important in different scenarios. By labeling an interface as "dual" in the type library, an OLE Automation interface can be used through IDispatch or it can be bound to directly.
IPropertyBag and IPersistPropertyBag ActiveX control containers that implement a "save as text" mechanism should use IPropertyBag and IPersistPropertyBag. IPropertyBag is implemented by a container and is roughly analogous to IStream. IPersistPropertyBag is implemented by controls, and is roughly analogous to IPersistStream.

Related Topics

The following links provide additional information on the topics presented in this article and sample applications for programming containers.



Back to topBack to top

Did you find this topic useful? Suggestions for other topics? Write us!

© 1999 Microsoft Corporation. All rights reserved. Terms of use.