OLE Controls and Control Containers Guidelines, Version 1.1
Click here to download the sample file associated with this file from the Downloads Center.
For information on how to use the Verification Software, see the README.TXT file in the project directory.
This tool is not supported by Microsoft Corporation. It is provided "as is" because we believe it may be useful to you. We regret that Microsoft is unable to support or assist you should you have problems using this tool.
The purpose of this document is to provide guidelines for implementing OLE controls and control containers that will interoperate well with other controls and control containers. Specifically, this document defines the minimum set of functionality in terms of interfaces, methods, and features that are required of OLE controls and control containers to accomplish seamless and useful interoperability. Optional features that may provide enhanced capabilities for a control or a container (categorized into "function groups") are discussed as well.
These guidelines define the minimum set of functionality that is required of a control and container; it therefore also describes the minimum set of functionality that a control can expect of a container, and vice versa. This enables controls and container developers to assume a standard set of functionality, and to reasonably rely on the existence of that functionality.
Those features, interfaces, methods, properties, and function groups that are mandatory for OLE controls and control containers are explicitly defined here—those not explicitly stated as mandatory in these guidelines should be considered optional.
Why Are OLE Control and Control Container Guidelines Important?
OLE 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. In order for a control to operate well in a variety of containers, the control must be able to assume some minimum level of functionality—some set of features that it can rely on in all containers. Likewise, a container should be able to expect some minimum standard feature set from all the controls that it contains. Controls and containers will most certainly implement features above this minimal set; these guidelines define the minimum common set of features.
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.
The rest of this document is divided into three sections. The first discusses control guidelines, the second discusses container guidelines, and the third discusses general guidelines, relevant to both OLE control and control container developers.
What to Do When an Interface You Need Is Not Available
Although these guidelines will help ensure that required functionality will be present, there will always be instances in which a control does not support a feature requested by the container, or vice versa. It is important for all OLE applications to be written to handle these situations. More specifically, OLE applications must use IUnknown::QueryInterface to acquire interface pointers (see Note 1 at the end of Table 1), and applications must always follow the standard OLE return-checking conventions required of all OLE applications—it cannot be safely assumed that IUnknown::QueryInterface will always succeed.
If the requested interface is not available (for example, IUnknown::QueryInterface returns E_NOINTERFACE), the control or container must degrade gracefully, even if it means that it must shut down.
What's New in Version 1.1?
This is the second release of the guidelines, and we've called it version 1.1 because only a small number of things have changed and a few "bug fixes" have been made. These are primarily interfaces or methods that in version 1.0 were marked as mandatory but that are now better expressed as optional. Items that are new or changed in this version are marked accordingly.
An OLE control is an embeddable OLE object that has additional support for OLE controls interfaces.
This section describes the specific interfaces, methods, and other features that are required of OLE Controls. Required interfaces, optional methods, properties, property pages, ambient properties, automation methods, events, and self registration are addressed in the following subsections.
Table 1 (below) lists the OLE Control interfaces. It denotes which interfaces are mandatory and must be implemented by controls, and which are optional.
| ||Support |
|IOleInPlaceActiveObject||No||Mandatory for controls with user interface (UI).|
|IOleControl||No||Mandatory for controls with mnemonics and/or controls that use ambient properties.|
|IDataObject||Yes||Mandatory for controls with property sets. Support for CF_METAFILE format is mandatory.|
|IExternalConnection||No||Mandatory for a controls that supports external links to itself, other than from its immediate container.|
|IDispatch||Yes||Not mandatory for controls that have no methods or properties. See Note 1.|
|IConnectionPointContainer||No||Mandatory for controls with events or property notifications.|
|IConnectionPoint||No||See note for IConnectionPointContainer.|
|ISpecifyPropertyPages||No||Mandatory for controls with property pages.|
|IPersistStream||No||See "Storage Interfaces" section.|
|IPersistStreamInit||No||See "Storage Interfaces" section.|
|IPersistStorage||Yes||See "Storage Interfaces" section.|
|IClassFactory2||No||Mandatory for controls with licensing support.|
|No||Mandatory for controls that provide property change notifications.|
|IPersistPropertyBag||No||Strongly recommended (see Note 2).|
- Dual interface support is optional but strongly recommended.
- Support for IPersistPropertyBag is optional but strongly recommended. IPersistPropertyBag is an optimization for containers that implement a "save as text" feature. For more information, see the IPersistPropertyBag section under "General Guidelines."
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. Table 2 describes those methods that a control is not required to implement (that is, the control can return E_NOTIMPL).
Table 2 (below) describes optional methods. Note that the method must still exist, but can simply return E_NOTIMPL instead of implementing "real" semantics. Any method from a mandatory interface that is not listed below must be considered mandatory and may not return E_NOTIMPL.
|GetControlInfo||Mandatory for controls with mnemonics.|
|OnMnemonic||Mandatory for controls with mnemonics.|
|OnAmbientPropertyChange||Mandatory for controls that use ambient properties.|
|SetExtent||Mandatory only for DVASPECT_CONTENT.|
|GetExtent||Mandatory only for DVASPECT_CONTENT.|
|DoVerb||See Note 1.|
|EnumAdvise||New for version 1.1.|
|TranslateAccelerator||New for version 1.1. Mandatory for controls that process accelerator keys.|
|Draw||New for version 1.1. Mandatory for controls visible at run time.|
|GetColorSet||New for version 1.1.|
|GetSizeMax||See Note 2.|
- A control with property pages must support IOleObject::DoVerbs for the OLEIVERB_PROPERTIES and OLEIVERB_PRIMARY verbs. A control that can be active must support IOleObject::DoVerbs for the OLEIVERB_INPLACEACTIVATE verb. A control that can be UI-active must also support IOleObject::DoVerbs for the OLEIVERB_UIACTIVATE verb.
- If a control supports IPersistStream and can return an accurate value, then it should do so.
Interface Method Semantics
Just as OLE controls must implement certain interfaces, and provide non-trivial implementations for most interface methods, there are some interface methods that require specific action. This section lists those methods and the required functionality. (There is currently only one method listed.)
IOleControl::FreezeEvents See "Event Freezing" in the "General Guidelines" section.
Although most controls do have properties, controls are not required to expose any properties, and there are no guidelines for which properties a control should expose.
Support for property pages and per-property browsing is strongly recommended, but not required. New for version 1.1: If a control does implement property pages, those pages should conform to one of the standard sizes: 250 x 62 or 250 x 110 dialog units (DLUs).
OLE Controls must use the following ambient properties, if they are available from the control site.
|LocaleID||If locale is significant to the control (for example, for text output).|
|UserMode||If the control behaves differently in user (design) mode and run mode.|
|UIDead||If the control reacts to UI events, it should honor this ambient property.|
|DisplayAsDefault||Only if the control is marked OLEMISC_ACTSLIKEBUTTON.|
Methods (via OLE Automation)
Although most controls do expose and support several methods, controls are not required to expose or support any methods, and there are no guidelines for which methods a control should expose.
Although most controls do expose and fire several events, they are not required to do so, and there are no guidelines for which events a control should expose.
OLE controls must support self-registration by implementing the DllRegisterServer and DllUnregisterServer functions. OLE controls must register all of the standard registry entries for embeddable objects and automation servers. OLE controls should also register the following three registry keys, which are strongly recommended, but not mandatory:
An OLE control container is an OLE container that supports the following additional features:
- Embedded objects from in-process servers
- In-place activation
- Inside-out activation
OLE Control Containers must provide support for all of these features.
Note that support for local servers is currently not required, because OLE controls are currently only implemented in-process.
This section describes the specific interfaces, methods, and other features that are required of OLE Control Containers. Required interfaces, optional methods, miscellaneous status bits support, keyboard handling, storage interfaces, ambient properties, extended properties, events, methods, message reflection, and automatic clipping are addressed in the following sections.
Table 4 (below) lists the OLE Control Container interfaces, and denotes which interfaces are mandatory and must be implemented by control containers, and which are optional.
| ||Support |
|IAdviseSink||Yes||Except where it is not needed, such as where controls are always active.|
|IOleContainer||Yes||See Note 1.|
|IDispatch for ambient properties||Yes||See Note 2 and "Ambient Properties" section.|
|IDispatch for events||Yes||See Note 2.|
|ISimpleFrameSite||No||ISimpleFrameSite and support for nested simple frames are optional.|
|IErrorInfo||Yes||Mandatory if container supports dual interfaces.|
|IClassFactory2||Yes||New for version 1.1. Needs to be supported so that a container can honor a control's licensing scheme.|
- IOleContainer is implemented on the document or form object (or appropriate analog) that holds the container sites. Controls use IOleContainer to navigate to other controls in the same document or form.
- Support for dual interfaces is not mandatory, but is strongly recommended. The OLE Controls Developers Kit does not currently support dual interfaces. However, writing your OLE Control Containers to take advantage of dual interfaces will afford you better performance now with controls that have expressly added dual interface support, and with controls that explicitly add dual interface support.
OLE control containers must support OLE Automation exceptions. If a control 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 OLE control container is not required to implement (that is, the control container can return E_NOTIMPL).
Table 5 (below) describes optional methods; note that the method must still exist, but can simply return E_NOTIMPL instead of implementing "real" semantics. Note also that any method from a mandatory interface that is not listed below must be considered mandatory and may not return E_NOTIMPL.
|Scroll||May return S_FALSE with no action.|
|DiscardUndoState||Can return S_OK with no action.|
|DeactivateAndUndo||Deactivation is mandatory; Undo is optional.|
|GetExtendedControl||Mandatory for containers that support extended controls.|
|ShowPropertyFrame||A control calls this method to display property pages.|
|TranslateAccelerator||New for version 1.1.|
|LockInPlaceActive||New for version 1.1. Very difficult to implement in native language containers (for example, C++) because the developer has complete control.|
|IDispatch (Ambient properties)|
|GetTypeInfoCount||Mandatory for containers that support non-standard ambient properties.|
|GetTypeInfo||Mandatory for containers that support non-standard ambient properties.|
|GetIDsOfNames||Mandatory for containers that support non-standard 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.|
|GetBorder||Mandatory for controls with toolbar UI (which is optional).|
|RequestBorderSpace||Mandatory for controls with toolbar UI (which is optional).|
|SetBorderSpace||Mandatory for controls with toolbar UI (which is optional).|
|InsertMenus||Mandatory for controls with menu UI (which is optional).|
|SetMenu||Mandatory for controls with menu UI (which is optional).|
|RemoveMenus||Mandatory for controls with menu UI (which is optional).|
|TranslateAccelerator||New for version 1.1.|
|EnumObjects||Mandatory, returns all OLE Controls, but not necessarily all objects. (Because there's no guarantee that all objects are OLE controls; some may be regular Windows controls.)|
|OnDataChange||OnDataChange returns void instead of an HRESULT.|
Miscellaneous Status Bits Support
OLE Control Containers must recognize and support the following OLEMISCSTATUS bits (Table 6).
| ||Support |
|ACTIVATEWHENVISIBLE||Yes||Mandatory only at run time. There may be other times when a container will not activate controls, such as during design time. This is dependent on the container.|
|INVISIBLEATRUNTIME||Yes||Designates a control that should be visible at design time, but invisible at run time.|
|ACTSLIKEBUTTON||Yes||Designates a control that behaves as a button. The control can identify itself as the default button. (Container support for default button functionality is optional.)|
|ACTSLIKELABEL||Yes||Designates that a control behaves like a label, indicating that it should not become UI-active, and should never receive the focus. (Focus should bypass labels, and continue to the next control in the tabbing order.)|
|SIMPLEFRAME||No||See "Container Controls" under "General Guidelines" below.|
OLE Control Containers implement keyboard handling by calling the controls' IOleControl interfaces. OLE control containers must support the following:
- Default button handling
- Mnemonic handling
- Tab handling, including tab order
Optionally, an OLE control container can allow a developer to designate an OLE control to act as the cancel button. In this case, the container treats the Escape key as a click on the designated control.
OLE controls must support IPersistStorage, and any container can rely on support for this interface. Additionally, controls can optionally implement stream persistence using either IPersistStream or IPersistStreamInit. Support for IPersistStreamInit is strongly recommended.
Once an OLE Control Container has chosen a storage interface to use (either IPersistStorage, IPersistStream, or IPersistStreamInit), the control container must use the same interface for the lifetime of the control.
OLE Control Containers do not need to support a "save as text" mechanism.
At a minimum, OLE control containers must support the following ambient properties (Table 7).
|UserMode||For containers that have different user and run environments.|
|SupportsMnemonics||Which must always be TRUE, according to the "Keyboard Handling" section.|
|DisplayAsDefault||For those containers where a default button makes sense.|
Extended Properties, Events, and Methods
OLE Control Containers are not required to support extended controls. However, if the control container does support extended properties, then it must support the following minimal set:
OLE Control Containers are not required to support extended events or methods. Currently, extended properties, events, and methods do not have standard Dispatch IDs.
It is strongly recommended that an OLE 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 Control Developer's Kit (CDK) creates two windows for every subclassed control, to provide message reflection on behalf of the control container.
It is strongly recommended that an OLE 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 non-null clipping region is passed.
This section describes various features, hints, and tips for developers of OLE controls and OLE control containers.
There are many optional features that OLE controls and OLE control containers can implement, in addition to the minimal set defined by these guidelines. These optional features may or may not be essential to correct operation of the control or container. Some optional features are grouped into "function groups." A control or a control container can implement any of these function groups. Function groups are not cumulative, so a control or container can support one function group without necessarily supporting another. It is important for a control or container to degrade gracefully if a feature or function group it uses is not available. If an optional feature that is essential for correct operation is not available, then the control or container should alert the user and/or should not instantiate itself.
It is important for controls and containers that require optional features, or features specific to a certain container, to be marketed and packaged as such. For example, a control that requires the Visual Basic® data-bound list box should be marketed as a Visual Basic–specific control, because it cannot run in other containers.
Currently, the following two function groups have been defined:
- Data binding
- "Simple frame" container controls
The OLE Controls architecture defines a data binding mechanism, whereby an OLE Control can specify that one or more of its properties is bindable. In most cases, a data-bound control should not absolutely require data binding, so that it could be inserted into a container that does not support data binding. Obviously, in such a situation, the functionality of the control may be reduced.
"Simple Frame" Container Controls
A container control is an OLE control that visually contains (not using standard OLE control containment) other controls. A group box that contains a collection of radio buttons is an example of a container control. Container controls should set the OLEMISC_SIMPLEFRAME status bit, and should call its container's ISimpleFrameSite implementation. An OLE control container that supports container controls must implement ISimpleFrameSite.
Many OLE 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 OLE control container can implement the IPropertyNotifySink interface (data binding) and use it also to be notified that a control property has changed. This technique is optional, and is not required of OLE control containers or OLE controls.
Note that a control should use IPropertyNotifySink::OnRequestEdit only for data binding; it is free to use OnChanged for either or both purposes.
Container-Specific Private Interfaces
Some containers provide container-specific private interfaces for additional functionality or improved performance. Controls that rely on those container-specific interfaces must either only instantiate themselves in that container, or work without those container-specific interfaces in different containers. For example, Microsoft® Visual Basic® implements private interfaces that provide string formatting functionality to controls. If a control requires Visual Basic's private interfaces to run, it should destroy itself gracefully when the private interfaces are not available. If the control can function without the private interfaces, it should take appropriate action (such as warning the user of reduced functionality) but should continue to work.
Starting with Microsoft Windows® 95 and Windows NT™ version 3.51, OLE provides support for multithreading applications, allowing applications to make OLE calls from multiple threads. This multithreaded support is called the "apartment model." The apartment model requires that interface pointers be marshalled (using CoMarshallInterface, and CoUnmarshallInterface) when passed between threads. For more information about apartment-model threading, refer to the Microsoft Win32® Software Development Kit (SDK) documentation, and the OLEAPT sample in the Win32 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 always honor a container's call to IOleControl::FreezeEvents(TRUE), and not fire events until the container calls IOleControl::FreezeEvents(FALSE). While a container's event processing is frozen, a control should implement one of the following techniques:
- Discard all events that the control would have fired.
- Queue up all pending events and fire them after the container has called IOleControl::FreezeEvents(FALSE).
- Queue up only relevant or important events and fire them after the container has called IOleControl::FreezeEvents(FALSE).
Each technique is accepted and appropriate in different circumstances. The control developer is responsible for determining and implementing the appropriate technique.
As described above, container controls are OLE Controls that visually contain other controls. The OLE Controls Architecture specifies the ISimpleFrameSite interface to enable container controls. Containers can also support container controls without supporting ISimpleFrameSite.
In order to support container controls without implementing ISimpleFrameSite, an OLE control container must:
- Activate all controls at all times.
- Re-parent the contained controls to the hWnd of the containing control.
- Remain the parent of the container control.
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 dynamic-link library (DLL) can contain any number of OLE 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 enumerated 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-OLE controls and then return pointers to these extender controls as a form is enumerated. This behavior enables OLE controls and OLE control containers to integrate well with non-OLE controls, and is thus recommended, but not required.
Not surprisingly, enhanced metafiles provide more functionality than standard metafiles, and 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 backwards compatibility with standard metafiles and 16-bit applications.
32-bit OLE control containers should use enhanced metafiles instead of standard metafiles.
In order to embed licensed controls successfully, OLE control containers must use IClassFactory2 instead of IClassFactory. Several OLE creation and loading helper functions (for example, OleLoad and CoCreateInsteance) explicitly call IClassFactory and not IClassFactory2, and therefore cannot be used to create or load licensed OLE controls. OLE control containers should explicitly create and load OLE 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: via the IDispatch interface, and through direct OLE vtable (pronounced vee-table) 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 method is called directly instead of through IDispatch::Invoke. IDispatch offers late binding support; 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 either be used via 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
IPropertyBag and IPersistPropertyBag optimize "save as text" mechanisms, and therefore are recommended for OLE 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.
Guideline Relaxation for "Document-Style" Use of OLE Controls
Some containers will use OLE controls in traditional compound document scenarios. For example, a spreadsheet may allow a user to embed an OLE 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. Consequently, OLE control containers that use OLE controls in compound document scenarios may relax the keyboard handling requirements described previously, according the following guidelines:
- Support for OLEMISC_ACTSLIKELABEL and OLEMISC_ACTSLIKEBUTTON is not required.
- Implementing the DisplayAsDefault ambient property is not required. (If it exists, it can return FALSE.)
- Implementing tab handling for buttons is not required.
Documentation for such products should inform users of differences in control handling in these different scenarios.