Palette Management for ActiveX Objects

This document describes palette management for Microsoft ActiveX objects, specifically ActiveX Controls and Active Document objects. The palette management rules described herein allow multiple controls inside a form or an HTML page to display correctly, while still leaving enough flexibility to allow a control to demand palette control. In general, containers are responsible for palette management, and contained objects (for example, controls) should only realize their palettes in the background.

  • Palette Management for ActiveX Controls and Containers
    • Palette Selection
    • Ambient Palette Property
    • Palette Change Notification
    • IViewObject2::GetColorSet
    • Realizing the Palette
  • Palette Management for Active Document Objects
    • Responsibilities of the Document Object
    • Single Document Case
    • Multiple Document Object Case

Palette Management for ActiveX Controls and Containers

This section describes how ActiveX controls and containers should manage the palette.

Palette Selection

Because there may be more than one control on a page or form, it is up to the container to choose a common palette, and every control should realize its palette in the background. Anything else would result in chaos as each control realized its palette while painting. The display would flicker madly and most controls would look awful.

Ultimately it is the container's responsibility to choose the common palette. Some containers might use the UI active object's palette; others might compute the palette at run-time.

Ambient Palette Property

The container makes its palette available to contained controls through an ambient property: DISPID_AMBIENT_PALETTE. This property is defined as part of the OLE Controls 96 specification and is implemented by Windows Internet Explorer. Controls can receive the value of this ambient initially by implementing IOleObject::SetClientSite or IObjectWithSite::SetSite, then querying the container client site for IDispatch, and finally calling IDispatch::Invoke on the property to obtain its value. Afterward, controls can receive notification of changes to this property by implementing IOleControl::OnAmbientPropertyChange.

Containers should realize the ambient palette before calling this function or IViewObject::Draw. Older containers that do not implement this property will typically iterate through their controls, forwarding the WM_QUERYNEWPALETTE message until a control returns TRUE (indicating it has realized a palette). Containers that implement DISPID_AMBIENT_PALETTE should never send WM_QUERYNEWPALETTE to their controls.

Palette Change Notification

Palette-aware controls that need to be notified of changes to the ambient palette should implement IOleControl::OnAmbientPropertyChange and handle DISPID_AMBIENT_PALETTE and DISPID_UNKNOWN. DISPID_UNKNOWN is sent when the values of more than one ambient property change. When this happens, controls should explicitly check for a changed palette.

Older containers that do not define an ambient palette will send WM_PALETTECHANGED messages. Controls are encouraged to handle this message as well.

Note that controls can still realize a different palette (in the background). The ambient palette property is useful only if a control needs to optimize its display to the palette of the container. If this is not necessary, the control should ignore the ambient palette property.

IViewObject2::GetColorSet

All palette-aware controls should implement IViewObject2::GetColorSet if they want to specify a palette preference. Containers can use the return value to determine if a control is palette-aware. Containers can also use the color information returned to choose what palette to realize.

E_NOTIMPL The control is not palette-aware.
S_FALSE The control is palette-aware but does not have a palette at this time.
S_OK The control is palette-aware and has returned its palette to the container.

 

It should be noted that the container does not have to call IViewObject2::GetColorSet. The container can determine its palette independently of its controls.

Realizing the Palette

Older OLE guidelines allowed the UI active object to realize its own palette in the foreground. Revised guidelines disallow this practice.

Controls should realize their palette in the foreground only when receiving a WM_QUERYNEWPALETTE message. In every other situation, the control must realize its palette in the background. Containers that implement DISPID_AMBIENT_PALETTE will never send this message.

Summary

  • Containers determine the palette.
  • Containers can choose to implement DISPID_AMBIENT_PALETTE.
  • Containers must realize the ambient palette before calling IViewObject::Draw or IOleControl::OnAmbientPropertyChange.
  • Controls must always realize their palette in the background. The only exception is when receiving a WM_QUERYNEWPALETTE message.
  • Controls should implement IViewObject2::GetColorSet if they want to tell the container about their palette preferences.
  • Controls should implement IOleControl::OnAmbientPropertyChange if they want to be notified about changes in the ambient palette property in order to optimize their display to the container's palette.

Palette Management for Active Document Objects

The following sections describe issues related to palette management by OLE document objects. In general, the palette management scheme for document objects is the same as the scheme used for controls, except that document objects do not receive ambient properties from their container.

Responsibilities of the Document Object

Palette management for document objects is similar to palette management for controls. The following are the responsibilities of the document object:

  • Document objects should implement IViewObject2::GetColorSet if interested in notifying the container about the palette they want to display. This is exactly the same as the corresponding responsibility for controls (as previously discussed).
  • Document objects should realize their palette in the background except when handling WM_QUERYNEWPALETTE messages (forwarded from the container). Again, this is exactly the same as the corresponding responsibility for controls.

The only difference between the responsibilities of controls and document objects is that document objects do not handle the DISPID_AMBIENT_PALETTE property.

Single Document Case

In the most common cases, a document object container will activate only one document object at a time. In such a situation, it is acceptable that the activated document object should have complete control over the palette, which includes managing palette issues for any controls or content within that document.

The document object container in this case has nothing to do with palettes and need not be concerned with palette issues. It should leave palette handling up to the document object—in other words, it should forward all Windows palette management messages on to the document object.

The following is example code for the window procedure of the document object host.

case WM_PALETTECHANGED:
case WM_QUERYNEWPALETTE:
{
    HWND hwnd;
    IOleWindow *pOleWindow;
    if (pDocObj && SUCCEEDED(pDocObj->QueryInterface(IID_IOleWindow, 
            (LPVOID*)&pOleWindow))) {
        LRESULT lres = 0;
        if (SUCCEEDED(pOleWindow->GetWindow(&hwnd))) {
            lres = SendMessage(hwnd, uMsg, wParam, lParam);
        }
        pOleWindow->Release();
        return lres;
    }
    break;
}

Multiple Document Object Case

In rare cases, a document object container might be able to activate more than one document object at a time within multiple container frames. While this user interface is discouraged at this time, it can be achieved.

However, no palette-management solution exists for this scenario because there is currently no protocol for communicating palettes between a document object and its container. Therefore, the container cannot create a palette suitable to all document objects that it has activated.

Because of this, the activated document object in the foreground has control over the palette and should use foreground palette rendering. Other activated document objects in the background use background palette rendering. The document object container itself does not participate in palette management at all.