Extended Controls

To a container, an OLE control is already a convenient package of functionality and content set behind a large group of interfaces used for accessing those features. A control, however, will not maintain properties and support methods that are relevant only to the container. It would be beneficial, then, for the container to have a way to package its own custom properties and methods in a control so that those properties and methods appear as if they were native to the control itself. For example, a control does not maintain any information about its name or position within a container form. A container, however, might like to store this information as properties of that control. In this way, the rest of the container code can treat all properties as if they were native to the control itself.

An extended control is a partial control that wraps around another control through containment and aggregation in order to supply extended functionality that the control itself knows nothing about. In other words, the container provides its own extended control implementation that overrides specific interfaces on another control through containment and exposes the remaining interfaces through aggregation. This relationship is illustrated in Figure 24-3. An extended control typically augments the methods and properties exposed by a control by providing its own IDispatch. This interface implementation filters out container-specific dispIDs before passing the call to the control's IDispatch. If the extended control has its own events as well, it also implements IConnectionPointContainer. Other interfaces are overridden as necessary, in the same way that an in-process handler (as we saw in Chapter 19) overrides specific interfaces from the default handler as it sees fit. Whatever container code then communicates with the extended control sees it as nothing more than an ordinary control with added features.

Figure 24-3.

An extended control wraps around another control through containment and aggregation to support container-specific properties, methods, and events.

This aggregation between control and extended control is one instance in which the extended control would delegate QueryInterface to the real control for all unrecognized interfaces. This allows the control to add new interfaces over time without requiring a change to the container or to the extended control itself. This works because the container, having intimate knowledge of its own extended control, knows exactly which interfaces the extended control will override. The container always knows that when it asks for IDispatch, for example, it will get the extended control's IDispatch.

A container doesn't have to implement extended controls if it has no reason to do so. In that case, IOleControlSite::GetExtendedControl should return E_NOTIMPL. Otherwise, this member function should return the IDispatch interface for the container's extended control managed by the site. A control can then access any properties of the extended control itself. (There are a few standards for this, as we'll see later in this chapter.) A control typically cannot depend on an extended property being present unless the control has intimate knowledge about the containers in which it will be embedded.