Your Window or Your Life

Besides the container's other interface pointers, IOleInPlaceSite::GetWindowContext also returns two rectangles: a position rectangle that describes where the object must initially appear in the container window and a clipping rectangle that describes the space in which the container can display anything. With this information, the object takes whatever editing window it has (Cosmo's Polyline window, for example) and physically moves it to the container by calling the Windows API function SetParent. The parent window handle is obtained by calling IOleInPlaceSite::GetWindow. The object then moves the editing window to the position rectangle, clips it to the size of the clipping rectangle, and makes it visible. Because the position rectangle is usually the same as the rectangle occupied by the site, the editing window appears on top of the site.

Now that this window is visible, it gets whatever messages are generated by various mouse actions performed in it. If the user clicks the mouse—presto! WM_LBUTTONDOWN comes into the editing window's message procedure. Cosmo's Polyline window adds a point to its figure on such an event. Certainly, the user could do a lot with the object in its window at this time. But as shown in Figure 22-5, the only visual changes are the absence of the container's selection handles and a possible change in the mouse cursor. Compare Figures 22-4 and 22-5. What is different? Did anything happen? Not much—not enough to let users know that they're now supposed to be working on the figure and not on the container. We need some subtle indications that something changed, in addition to potential changes in the menus and toolbars.

To solve this problem, we need to indicate that the object has changed from the loaded state to the in-place–active state. The user interface guidelines for OLE Documents recommend that an object create a small hatched border around itself in the container, which can also include object-managed grab handles, as shown in Figure 22-6. To create this border, an object typically creates a special hatch window that is larger than the object's position rectangle on all sides by the width of the border.2 The object uses this window

Figure 22-5.

What Patron would look like if all that Cosmo did for in-place activation was move its Polyline window into Patron. There's no magic here!

as the parent of the editing window and then places the hatch window itself into the container, offset left and up from the position rectangle by the border width. The object occupies exactly the position rectangle, leaving the hatch window with a small space in which to draw the hatching and grab handles. Mouse clicks in the hatch window are always mouse clicks in the hatched border or on the grab handles, which the object can manage as necessary.

Figure 22-6.

The hatched border that an object creates around itself when activated in place, with and without sizing handles.

If an object resizes itself with these grab handles while in place, it should call IOleInPlaceSite::OnPosRectChange, which in turn calls IOleInPlaceObject::SetObjectRects with an updated position and clipping rectangle. As we'll see in Chapter 23, a hatch window helps the in-place object manage this clipping rectangle and the one it obtains from IOleInPlaceSite::GetWindowContext. In any case, what the user will now see is something such as that shown in Figure 22-7.

Figure 22-7.

What Patron looks like after Cosmo has created its hatching around the object.

At this point, an object is completely in the in-place–active state. This is as far as we go if we're handling OLEIVERB_INPLACEACTIVATE. If we're fully activating the user interface, the object now calls IOleInPlaceSite::OnUIActivate to warn the container. The object passes its IOleInPlaceActiveObject pointer to the container by calling IOleInPlaceFrame::SetActiveObject and, if the container has a document, IOleInPlaceUIWindow::SetActiveObject.3 Because the container cannot query for this interface through the object itself, these calls to SetActiveObject are the only way the container obtains this pointer. Through this pointer, it must now notify the UI-active object of various events.

To complete UI activation, the object now creates a shared menu and displays its tools in the container. The next two sections describe the processes involved.

2 The border width is read from the [windows] section of WIN.INI using the key OleInPlaceBorderWidth. The default value is 4 pixels.

3 The pszObjName argument to SetActiveObject is not used and can be NULL. Some time ago, the user interface guidelines recommended that a container display this string in its document or frame caption bar. This is no longer the case, although you might still see applications that use the older form of the UI. The container should now ignore the argument completely.