
The purpose of this topic is to provide guidelines for implementing containers that will interoperate well with other controls and containers. This document defines the minimum set of interfaces, methods, and features that are required of ActiveX containers to accomplish seamless and useful interoperability.
An ActiveX control container must be able to host a minimal ActiveX control as specified in this document. It will also support a number of additional interfaces. A container can optionally support a number of interfaces and methods, which are grouped into functional areas known as component categories. A container can support any combination of component categories. For example, a component category exists for Databinding; a container may or may not support the data-binding functionality, depending on the market needs of the container. If a control needs data-binding support from a container to function, the control will enter this requirement in the registry. This allows a container to offer for insertion only those controls it knows it can successfully host. It is important to note that component categories are specified as part of OLE and are not specific to ActiveX Controls. The controls architecture uses component categories to identify areas of functionality that an OLE component might support. Component categories are not cumulative or exclusive, so a container can support one category without necessarily supporting another.
These guidelines define those interfaces and methods that a control can expect a container to support, although as always a control should check the return values when using QueryInterface or other methods to obtain pointers to these interfaces. A container should not expect a control to support anything more than the IUnknown interface. These guidelines identify what interfaces a control can support and what the presence of a particular interface means.
ActiveX Controls have become the primary architecture for developing programmable software components for use in a variety of different containers, ranging from software development tools to end-user productivity tools. For a control to operate well in a variety of containers, the control must be able to assume some minimum level of functionality that it can rely on in all containers.
By following these guidelines, control and container developers make their controls and containers more reliable and interoperable, and, ultimately, better and more usable components for building component-based solutions.
This document provides guidelines toward good interoperability. It is expected that new interfaces and component categories will develop over time; future versions of this document reflecting these changes will be made readily available through Microsoft. It is important to note that this document does not cover detailed semantics of the OLE interfaces; this is covered by the SDK documentation.
This section states some fundamental rules that apply to all OLE programming. OLE programs should use QueryInterface to acquire interface pointers, and must check the return value. OLE applications cannot safely assume that QueryInterface will succeed; this requirement applies to all OLE applications. If the requested interface is not available (that is, QueryInterface returns E_NOINTERFACE), the control or container must degrade gracefully, even if that means it cannot perform its designated job function.
This release of the guidelines embraces the concept of component categories, which are a part of the OLE specification. In previous versions of this document, component categories were loosely referred to as "function groups" and were used to identify areas of functionality that a container can optionally support. For this version there has been a definition of how component categories work for ActiveX Controls, and some fundamental categories are identified. The use of component categories allows the relaxing of some of the previous rules that identified interfaces as being mandatory, and allows greater flexibility for controls to efficiently target certain areas of functionality without having to provide superfluous additional support in order to qualify as a control. This edition of the guidelines also discusses what the presence or absence of an interface means and what to do in that situation.
ActiveX control containers must provide support for the following features:
The following sections describe the specific interfaces, methods, and other features that are required of ActiveX control containers. The last section describes how to gracefully degrade when a particular control interface is not supported.
The following table lists the ActiveX control container interfaces, denoting which interfaces are optional, and which are mandatory and must be implemented by containers.
| Interface | Support mandatory? | Comments |
| IOleClientSite | Yes | |
| IAdviseSink | No | Only when the container wants data change notifications (controls with IDataObject), view change notification (controls that are not active and have IViewObject[2]), and other notifications from controls acting as standard embedded objects. |
| IOleInPlaceSite | Yes | |
| IOleControlSite | Yes | |
| IOleInPlaceFrame | Yes | |
| IOleContainer | Yes | See Note 1. |
| IDispatch for ambient properties | Yes | See Note 2 and "Ambient Properties" section |
| Control Event Sets | Yes | See Note 2. |
| ISimpleFrameSite | No | This interface and support for nested simple frames is optional. |
| IPropertyNotifySink | No | Only needed for containers that have their own property-editing UI, which would require updating whenever a control changed a property itself, or containers that want to control [requestedit] property changes and other such data-binding features. |
| IErrorInfo | Yes | Mandatory if container supports dual interfaces. See Note 2. |
| IClassFactory2 | No | Support is strongly recommended. |
Notes:
ActiveX control containers must support OLE Automation exceptions. If a container supports dual interfaces, it must capture automation exceptions through IErrorInfo.
An OLE component can implement an interface without implementing all the semantics of every method in the interface, instead returning E_NOTIMPL or S_OK as appropriate. The following table describes those methods that an ActiveX control container is not required to implement (that is, the container can return E_NOTIMPL).
The table also describes optional methods; note that the method must still exist, but can simply return E_NOTIMPL instead of implementing "real" semantics. Note that any method from a mandatory interface that is not listed in the table must be considered mandatory and cannot return E_NOTIMPL.
| Method | Comments |
| IOleClientSite | |
| SaveObject | Necessary for persistence to be successfully supported. |
| GetMoniker | Necessary only if the container supports linking to controls within its own form or document. |
| IOleInPlaceSite | |
| ContextSensitiveHelp | Optional. |
| Scroll | Can return S_FALSE with no action. |
| DiscardUndoState | Can return S_OK with no action. |
| DeactivateAndUndo | Deactivation is mandatory; Undo is optional. |
| IOleControlSite | |
| GetExtendedControl | Necessary for containers that support extended controls. |
| ShowPropertyFrame | Necessary for containers that want to include their own property pages to handle extended control properties in addition to those provided by a control. |
| TranslateAccelerator | Can return S_FALSE with no action. |
| LockInPlaceActive | Optional. |
| IDispatch (ambient properties) | |
| GetTypeInfoCount | Necessary for containers that support nonstandard ambient properties. |
| GetTypeInfo | Necessary for containers that support nonstandard ambient properties. |
| GetIDsOfNames | Necessary for containers that support nonstandard ambient properties. |
| IDispatch (event sink) | |
| GetTypeInfoCount | The control knows its own type information, so it has no need to call this. |
| GetTypeInfo | The control knows its own type information, so it has no need to call this. |
| GetIDsOfNames | The control knows its own type information, so it has no need to call this. |
| IOleInPlaceFrame | |
| ContextSensitiveHelp | |
| GetBorder | Necessary for containers with toolbar UI (which is optional). |
| RequestBorderSpace | Necessary for containers with toolbar UI (which is optional). |
| SetBorderSpace | Necessary for containers with toolbar UI (which is optional). |
| InsertMenus | Necessary for containers with menu UI (which is optional). |
| SetMenu | Necessary for containers with menu UI (which is optional). |
| RemoveMenus | Necessary for containers with menu UI (which is optional). |
| SetStatusText | Necessary only for containers that have a status line. |
| EnableModeless | Optional. |
| TranslateAccelerator | Optional. |
| IOleContainer | |
| ParseDisplayName | Only if linking to controls or other embeddings in the container is supported, as this is necessary for moniker binding. |
| LockContainer | As for ParseDisplayName. |
| EnumObjects | Returns all ActiveX Controls through an enumerator with IEnumUnknown, but not necessarily all objects (since there's no guarantee that all objects are ActiveX Controls; some might be regular Windows® controls). |
ActiveX control containers must recognize and support the following OLEMISC_ status bits.
| Status bit | Support mandatory? | Comments |
| ACTIVATEWHENVISIBLE | Yes | |
| IGNOREACTIVATEWHENVISIBLE | No | Needed for inactive and windowless control support. See Note 1. |
| INSIDEOUT | No | Not generally used with ActiveX Controls but rather with compound document embeddings. Note this is contrary to some SDK documentation that says this bit must be set for the ACTIVATEWHENVISIBLE bit to be set. |
| INVISIBLEATRUNTIME | Yes | Designates a control that should be visible at design time, but invisible at run time. |
| ALWAYSRUN | Yes | |
| ACTSLIKEBUTTON | No | Support is normally mandatory, although it is not necessary for document-style containers. |
| ACTSLIKELABEL | No | Support is normally mandatory, although it is not necessary for document-style containers. |
| NOUIACTIVATE | Yes | |
| ALIGNABLE | No | |
| SIMPLEFRAME | No | |
| SETCLIENTSITEFIRST | No | Support for this bit is recommended but not mandatory. |
| IMEMODE | No |
Notes:
Keyboard handling support for the following functionality is strongly recommended, although it is recognized that it is not applicable to all containers:
Some containers use ActiveX Controls in traditional compound document scenarios. For example, a spreadsheet might allow a user to embed an ActiveX control into a worksheet. In such scenarios, the container would do keyboard handling differently, because the keyboard interface should remain consistent with the user's expectations of a spreadsheet. Documentation for such products should inform users of differences in control handling in these different scenarios. Other containers should endeavor to honor the above functionality correctly, including mnemonic handling.
Containers must be able to support controls that implement IPersistStorage, IPersistStream, or IPersistStreamInit. Optionally, a container can support any other persistence interfaces, such as IPersistMemory, IPersistPropertyBag, and IPersistMoniker, for those controls that provide support.
After an ActiveX control container has chosen and initialized a storage interface to use (IPersistStorage, IPersistStream, IPersistStreamInit, and so on), that storage interface will remain the primary storage interface for the lifetime of the control; that is, the control will remain in possession of the storage. This does not preclude the container from saving to other storage interfaces.
ActiveX control containers do not need to support a "save as text" mechanism, thus using IPersistPropertyBag and the associated container-side interface IPropertyBag are optional.
At a minimum, ActiveX control containers must support the following ambient properties using the standard DISPIDs.
| Ambient property | DISPID | Comments/Conditions |
| LocaleID | -705 | |
| UserMode | -709 | For containers that have different user and run environments. |
| DisplayAsDefault | -713 | For those containers where a default button is relevant. |
ActiveX control containers are not required to support extended controls. However, if the container does support extended properties, it must support the following minimal set:
| Visible |
| Parent |
| Default |
| Cancel |
Currently, extended properties, events, and methods do not have standard DISPIDs.
It is strongly recommended that an ActiveX control container support message reflection. This will result in more efficient operation for subclassed controls. If message reflection is supported, the MessageReflect ambient property must be supported and have a value of TRUE. If a container does not implement message reflection, the OLE CDK creates two windows for every subclassed control, to provide message reflection on behalf on the container.
It is strongly recommended that an ActiveX control container support automatic clipping of its controls. This will result in more efficient operation for most controls. If automatic clipping is supported, the AutoClip ambient property must be supported and have a value of TRUE.
Automatic clipping is the ability of a container to ensure that a control's drawn output goes only to the container's current clipping region. In a container that supports automatic clipping, a control can paint without regard to its clipping region, because the container will automatically clip any painting that occurs outside the control's area. If a container does not support automatic clipping, CDK-generated controls will create an extra parent window if a nonnull clipping region is passed.
Because a control might not support any interface other than IUnknown, a container has to degrade gracefully when it encounters the absence of any particular interface.
One might question the usefulness of a "control" with nothing more than IUnknown. But consider the advantages that a control receives from a container's visual programming environment (such as Microsoft Visual Basic®) when the container recognizes the object as a "control":
When an object isn't recognized as a "control," it potentially loses all of these very powerful and beneficial integration features. For example, in Visual Basic 4.0 it is very difficult to really integrate some random object that is not a "control" in the complete sense, but may still have properties and events. Because Visual Basic 4.0's idea of a control is very restrictive, the object does not gain any of the integration features mentioned previously. But even a control with IUnknown, where the mere lifetime of the control determines the existence of some resource, should be able to gain the integration capabilities described above.
Because current tools require a large set of control interfaces to gain any advantage, controls are generally led to over-implementation, such that they contain more code than they really need. Controls that could be 7K might end up being 25K, which is a big performance problem in areas such as the Internet. This has also led to the perception that one can only implement a control with one tool, such as the CDK, because of the complexity of implementing all the interfaces. This has implications when a large DLL such as Oc30.dll is required for such a control, increasing the working set. If not all interfaces are required, this opens up many developers to writing very small and light controls with straight OLE or with other tools as well, minimizing the overhead for each control.
This is why this document recognizes a "control" as any object with a CLSID and an IUnknown interface. Even with nothing more than IUnknown, a container with a programming environment should be able to provide at least features (3) and (4) from the list above. If the object provides a ToolBoxBitmap32 registry entry, it gains (1) and (2). If the object supplies IConnectionPointContainer (and IProvideClassInfo generally) for some event set, it gains (5), and if it supports IDispatch for properties and methods, it gains (6), as well as better code integration in the container.
In short, an object should be able to implement as little as IDispatch and one event set exposed through IConnectionPointContainer to gain all the visual features above.
With this in mind, the following table describes what a container might do in the absence of any possible interface. Note that only those interfaces are listed that the container will directly obtain through QueryInterface. Other interfaces, such as IOleInPlaceActiveObject, are obtained through other means.
| Interface | Meaning of interface absence |
| IViewObject2 | The control has no visuals that it will draw itself, so has no definite extents to provide. In run time, the container simply doesn't attempt to draw anything when this interface is absent. In design time, the container must at least draw some kind of default rectangle with a name in it for such a control, so a user in a visual programming environment can select the object and check out its properties, methods, and events that exist. Handling the absence of IViewObject2 is critical for good visual programming support. |
| IOleObject | The control doesn't need the site whatsoever, nor does it take part in any embedded object layout negotiation. Any information (such as control extents) that a container might expect from this interface should be filled in with container-provided defaults. |
| IOleInPlaceObject | The control doesn't go in-place active (like a label) and thus never attempts to activate in this manner. Its only activation might be its property pages. |
| IOleControl | Control has no mnemonics and no use of ambient properties, and doesn't care if the container ignores events. In the absence of this interface, the container just doesn't call its members. |
| IDataObject | The control provides no property sets nor any visual renderings that could be cached, so the container would choose to cache some default presentation in the absence of this interface (support for CF_METAFILEPICT, specifically) and disable any property-set related functionality. |
| IDispatch | The control has no custom properties or methods. The container does not need to try to show any control properties in this case, and should disallow any custom method calls that the container doesn't recognize as belonging to its own extended controls (that might support methods and properties). As extended controls generally delegate certain IDispatch calls to the control, an extended control should not expect the control to have IDispatch at all. |
| IConnectionPointContainer | The control has no events, so the container doesn't have to think about handling any. |
| IProvideClassInfo[2] | The control either doesn't have type information or events, or the container needs to go into the control's type information through the control's registry entries. The existence of this interface is an optimization. |
| ISpecifyPropertyPages | The control has no property pages, so if the container has any UI that would invoke them, the container should disable that UI. |
| IPerPropertyBrowsing | The control has no display name itself, no predetermined strings and values, and no property to page mapping. This interface is nearly always used for generating container user interface, so such UI elements would be disabled in the absence of this interface. |
| IPersist* | The control has no persistent state to speak of, so the container doesn't have to worry about saving any control-specific data. The container will, of course, save its own information about the control in its own form or document, but the control itself has nothing to contribute to that information. |
| IOleCache[2] | The object doesn't support caching. A container can still support caching by just creating a data cache itself using CreateDataCache. |
This section describes various features, hints, and tips for ActiveX control and ActiveX control container developers to help ensure good interoperability between controls and containers.
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 (the control is always right, of course). To ensure that it always has the current values for a control's properties, an ActiveX control container can overload the IPropertyNotifySink interface (data binding) and also use it to be notified that a control property has changed. This technique is optional, and is not required of ActiveX control containers or ActiveX Controls.
Note A control should use IPropertyNotifySink::OnRequestEdit only for data binding; it is free to use OnChanged for either or both purposes.
Some containers provide container-specific private interfaces for additional functionality or improved performance. Controls that rely on those container-specific interfaces should, if possible, work without those container-specific interfaces present so that the control functions in different containers. For example, Visual Basic implements private interfaces that provide string formatting functionality to controls. If a control makes use of the Visual Basic private formatting interfaces, it should be able to run with default formatting support if these interfaces are not available. If the control can function without the private interfaces, it should take appropriate action (such as warn the user of reduced functionality) but continue to work. If this is not an option, a component category should be registered as required to ensure that only containers supporting this functionality can host these controls.
Starting with Microsoft Windows 95 and Microsoft Windows NT® 3.51, OLE provides support for multithreaded applications, allowing applications to make OLE calls from multiple threads. This multithreaded support is called the "apartment model"; it is important that all OLE components using multiple threads follow this model. The apartment model requires that interface pointers are marshaled (using CoMarshalInterface and CoUnmarshalInterface) when passed between threads. For more information about apartment model threading, refer to the Platform SDK documentation and the OLEAPT sample (in the Platform SDK).
A container can notify a control that it is not ready to respond to events by calling IOleControl::FreezeEvents(TRUE). It can unfreeze the events by calling IOleControl::FreezeEvents(FALSE). When a container freezes events, it is freezing event processing, not event receiving; that is, 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. No other action is appropriate.
A control should take note of a container's call to IOleControl::FreezeEvents(TRUE) if it is important to the control that an event is not missed. While a container's event processing is frozen, a control should implement one of the following techniques:
Each technique is acceptable and appropriate in different circumstances. The control developer is responsible for determining and implementing the appropriate technique for the control's functionality.
As described previously, container controls are ActiveX Controls that visually contain other controls. The ActiveX Controls architecture specifies the ISimpleFrameSite interface to enable container controls. Containers can also support container controls without supporting ISimpleFrameSite, although the behavior cannot be guaranteed. For this reason, a component category exists for SimpleFrameSite controls where the full functionality of this interface is required.
To support container controls without implementing ISimpleFrameSite, an ActiveX control container must:
A control should not use the WS_GROUP and WS_TABSTOP flags internally; some containers rely on these flags to manage keyboard handling.
A single .ocx DLL can container any number of ActiveX Controls, thus 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 in the package. Including the vendors' names in each control name will enable 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
This method is used to enumerate over all the OLE objects contained in a document or form, returning an interface pointer for each OLE object. The container must return pointers to each OLE 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 pointers 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, and is thus recommended but not required.
Not surprisingly, 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. Enhanced metafiles are not available in 16-bit OLE. OLE supports enhanced metafiles, and includes backward compatibility with standard metafiles and 16-bit applications.
A 32-bit ActiveX control container should use enhanced metafiles instead of standard metafiles.
In order to embed licensed controls successfully, ActiveX control containers must use IClassFactory2 instead of IClassFactory. Several OLE creation and loading helper functions (for example, OleLoad and CoCreateInstance) explicitly call IClassFactory and not IClassFactory2, and therefore cannot be used to create or load licensed ActiveX Controls. ActiveX control containers should explicitly create and load ActiveX Controls using IClassFactory2. In the future, Microsoft will update these standard APIs to use both IClassFactory and IClassFactory2, as appropriate.
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 is used by most tools available today, and offers support for late binding to properties and methods. Vtable binding offers much higher performance because this method is called directly instead of through IDispatch::Invoke. IDispatch offers late bound support, where direct Vtable binding offers a significant 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. Containers can thus choose the most appropriate technique. Support for dual interfaces is strongly recommended for both controls and containers.
IPropertyBag and IPersistPropertyBag optimize "save as text" mechanisms, and therefore are recommended for ActiveX control containers that implement a "save as text" mechanism. IPropertyBag is implemented by a container, and is roughly analogous to IStream. IPersistPropertyBag is implemented by controls, and is roughly analogous to IPersistStream.
| COM Objects for the Internet |
| Monikers, URLs, Security Zones, and Pluggable Protocols |
| Hyperlinks |
© 1997 Microsoft Corporation. All rights reserved. Terms of Use.