Handle Iconic Presentations (Cache Control)

I admit that when I first looked at the handling of iconic aspects, I was so intimidated that I wanted to defer it to a later chapter. After whacking myself in the head a few times with the 40-ounce Louisville Slugger I keep in my office, I got myself to write about it in this chapter. It really didn't turn out to be all that hard.

The trick to iconic aspects is a special case of the more general issue of controlling the object's cached presentations through IOleCache. When we come back from either the Insert Object dialog or the Paste Special dialog with the Display As Icon box checked, we need to draw the object as DVASPECT_ICON instead of DVASPECT_CONTENT. The trouble is that most servers do not supply an iconic representation themselves, so in order to make this work, a container has to put one in the cache directly. What goes in the cache is a metafile with the iconic representation that both the Insert Object and Paste Special dialogs will create for us. This metafile contains both an icon and a label. Again, the helper function INOLE_MetafilePictIconFree will clean up one of these metafiles for us.

Inside CTenant::Create and CTenant::ObjectInitialize, we detect whether the chosen display aspect is DVASPECT_ICON. If so, we need to put the icon in the cache. We saw the code for this earlier:


if (DVASPECT_ICON & m_fe.dwAspect)
{
DWORD dw=DVASPECT_CONTENT;
IAdviseSink *pSink;

pSink=(NULL==dwData) ? NULL : m_pImpIAdviseSink;

INOLE_SwitchDisplayAspect(m_pIOleObject, &dw
, DVASPECT_ICON, (HGLOBAL)(UINT)dwData, FALSE
, (NULL!=dwData), pSink, NULL);
}

The helper function INOLE_SwitchDisplayAspect (in INOLE\HELPERS.CPP) removes any DVASPECT_CONTENT information from the cache, stores the icon as the cache for DVASPECT_ICON, and sets up a new advisory connection for that view aspect. All this is simply standard cache manipulation.

With this cache set, we need to be sure to pass DVASPECT_ICON to IViewObject2::Draw, which happens in CTenant::Draw. When copying the object to a data object, we have to set this aspect as well so that other containers will know what to paste. We also need to remember the aspect when we save the objects so we can initialize it properly when loading it again.

These considerations for differentiating content and icon aspects apply equally well for managing other aspects, including other device-specific renderings for the same aspect. In all cases, after you tell the cache what to do, OleSave and OleLoad do the appropriate thing. It's mostly a matter of your structures indicating the correct aspect.

The missing piece of this icon story is how you either change the icon at a later time or switch back to viewing DVASPECT_CONTENT for the object. The answer lies in the Convert dialog box, which is the final topic to examine for a basic container.