As described earlier, any call to IOleObject::DoVerb, except for OLEIVERB_OPEN, can start in-place activation. To fully support in-place objects, a container needs to include a MSG structure telling the object what mouse message caused the activation. In Patron, activating an object with a double click occurs in CPage::OnLeftDoubleClick (in PAGEMOUS.CPP), which creates a MSG structure with WM_LBUTTONDBLCLK in it. This structure is sent to CTenant::ActivateObject along with OLEIVERB_PRIMARY, which then sends the structure to IOleObject::DoVerb. Because Patron also supports inside-out objects, it sends a WM_LBUTTONDOWN message with OLEIVERB_UIACTIVATE within CTenant::Select (which is called whenever the user clicks on a tenant to select it).
In other activation cases, such as those in response to menu commands, we don't need to send a message structure at all. This also applies for objects marked OLEMISC_ACTIVATEWHENVISIBLE. As you can see in CTenant::Load, Patron will call DoVerb(OLEIVERB_INPLACEACTIVATE) for such an object so that it is always at least in-place active. In this case, we do not need to send a message to DoVerb either.
So now how do we deactivate the object? This should happen whenever the user clicks either mouse button outside the object. Patron picks up these events in CPage::OnLeftDown or CPage::OnRightDown (in PAGEMOUS.CPP). The appropriate function then calls CTenant::DeactivateInPlaceObject, which in turn calls IOleInPlaceObject:: InPlaceDeactivate, as shown in the code on the following page.
void CTenant::DeactivateInPlaceObject(BOOL fFull)
{
if (NULL!=m_pIOleIPObject)
{
if ((OLEMISC_ACTIVATEWHENVISIBLE & m_grfMisc) && !fFull)
m_pIOleIPObject->UIDeactivate();
else
m_pIOleIPObject->InPlaceDeactivate();
}
return;
}
InPlaceDeactivate, unless told otherwise, only deactivates the UI for an object marked OLEMISC_ACTIVATEWHENVISIBLE, which leaves it in-place active only. Otherwise, we deactivate the object, returning it to the running state. (See the following sidebar.)
Clicking outside the object is not the only event that can cause deactivation. Basically, you should deactivate if any event occurs that would create or activate a different object (such as a drag-and-drop operation) or that would require the object to be in the loaded state (such as closing the document or application). This latter case is handled in CTenant::Close, which calls CTenant::DeactivateInPlaceObject before calling IOleObject::Close.
When the user clicks inside an object with the activate-when-visible property, the object will call the container's IOleInPlaceSite::OnUIActivate function, at which time you should deactivate the object that was UI active. If that other object has the activate-when-visible property, you call only its IOleInPlaceObject::UIDeactivate function, as shown in the preceding code.
After you deactivate an in-place object, that object will still be in the running state, not the loaded state. IOleObject::Close is required to change the state. OLE does this to ensure quick reactivation by eliminating server load time. Therefore, the object's state is not reset between in-place activations. If you crash your container while debugging it, a local server might remain in memory with an undetermined state and a hidden window. You'll need to use a tool such as PVIEW to terminate the server so that you can run your container again with a fresh state.