/*************************************************************************
**
**    OLE 2 Container Sample Code
**
**    cntrinpl.c
**
**    This file contains all interfaces, methods and related support
**    functions for an In-Place Container application (aka. Visual
**    Editing). The in-place Container application includes the following
**    implementation objects:
**
**    ContainerApp Object
**      exposed interfaces:
**          IOleInPlaceFrame
**
**    ContainerDoc Object
**      support functions only
**      (ICntrOtl is an SDI app; it doesn't support a Doc level IOleUIWindow)
**
**    ContainerLin Object
**      exposed interfaces:
**          IOleInPlaceSite
**
**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved
**
*************************************************************************/

#include "outline.h"
#if defined( USE_STATUSBAR )
#include "status.h"
#endif

OLEDBGDATA

extern LPOUTLINEAPP g_lpApp;
extern BOOL g_fInsideOutContainer;
extern RECT g_rectNull;

/*************************************************************************
** ContainerApp::IOleInPlaceFrame interface implementation
*************************************************************************/

// IOleInPlaceFrame::QueryInterface
STDMETHODIMP CntrApp_IPFrame_QueryInterface(
      LPOLEINPLACEFRAME   lpThis,
      REFIID              riid,
      LPVOID FAR*         lplpvObj
)
{
   SCODE sc = E_NOINTERFACE;
   LPCONTAINERAPP lpContainerApp =
         ((struct COleInPlaceFrameImpl FAR*)lpThis)->lpContainerApp;

   /* The object should not be able to access the other interfaces
   ** of our App object by doing QI on this interface.
   */
   *lplpvObj = NULL;
   if (IsEqualIID(riid, &IID_IUnknown) ||
      IsEqualIID(riid, &IID_IOleWindow) ||
      IsEqualIID(riid, &IID_IOleInPlaceUIWindow) ||
      IsEqualIID(riid, &IID_IOleInPlaceFrame)) {
      OleDbgOut4("CntrApp_IPFrame_QueryInterface: IOleInPlaceFrame* RETURNED\r\n");
      *lplpvObj = (LPVOID) &lpContainerApp->m_OleInPlaceFrame;
      OleApp_AddRef((LPOLEAPP)lpContainerApp);
      sc = S_OK;
   }

   OleDbgQueryInterfaceMethod(*lplpvObj);

   return ResultFromScode(sc);
}


// IOleInPlaceFrame::AddRef
STDMETHODIMP_(ULONG) CntrApp_IPFrame_AddRef(LPOLEINPLACEFRAME lpThis)
{
   OleDbgAddRefMethod(lpThis, "IOleInPlaceFrame");

   return OleApp_AddRef((LPOLEAPP)g_lpApp);
}


// IOleInPlaceFrame::Release
STDMETHODIMP_(ULONG) CntrApp_IPFrame_Release(LPOLEINPLACEFRAME lpThis)
{
   OleDbgReleaseMethod(lpThis, "IOleInPlaceFrame");

   return OleApp_Release((LPOLEAPP)g_lpApp);
}


// IOleInPlaceFrame::GetWindow
STDMETHODIMP CntrApp_IPFrame_GetWindow(
   LPOLEINPLACEFRAME   lpThis,
   HWND FAR*           lphwnd
)
{
   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   OLEDBG_BEGIN2("CntrApp_IPFrame_GetWindow\r\n")
   *lphwnd = lpOutlineApp->m_hWndApp;
   OLEDBG_END2
   return NOERROR;
}


// IOleInPlaceFrame::ContextSensitiveHelp
STDMETHODIMP CntrApp_IPFrame_ContextSensitiveHelp(
   LPOLEINPLACEFRAME   lpThis,
   BOOL                fEnterMode
)
{
   LPCONTAINERAPP lpContainerApp =
         ((struct COleInPlaceFrameImpl FAR*)lpThis)->lpContainerApp;

   // artificial AddRef in case object is destroyed during call
   CntrApp_IPFrame_AddRef(lpThis);

   OleDbgOut("CntrApp_IPFrame_ContextSensitiveHelp\r\n");
   /* OLE2NOTE: see context sensitive help technote (CSHELP.DOC)
   **    This method is called when F1 is pressed when a menu item is
   **    selected. We set the frame's m_fMenuMode flag here. later,
   **    in WM_COMMAND processing in the AppWndProc, if this flag is
   **    set then the command is NOT executed and help is given
   **    instead.
   */
   lpContainerApp->m_fMenuHelpMode = fEnterMode;

   // release artificial AddRef
   CntrApp_IPFrame_Release(lpThis);

   return NOERROR;
}


// IOleInPlaceFrame::GetBorder
STDMETHODIMP CntrApp_IPFrame_GetBorder(
   LPOLEINPLACEFRAME   lpThis,
   LPRECT              lprectBorder
)
{
   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   // artificial AddRef in case object is destroyed during call
   CntrApp_IPFrame_AddRef(lpThis);

   OLEDBG_BEGIN2("CntrApp_IPFrame_GetBorder\r\n")

   OutlineApp_GetFrameRect(lpOutlineApp, lprectBorder);

   OLEDBG_END2
   // release artificial AddRef
   CntrApp_IPFrame_Release(lpThis);
   return NOERROR;
}


// IOleInPlaceFrame::RequestBorderSpace
STDMETHODIMP CntrApp_IPFrame_RequestBorderSpace(
   LPOLEINPLACEFRAME   lpThis,
   LPCBORDERWIDTHS     lpWidths
)
{
#if defined( _DEBUG )
   OleDbgOut2("CntrApp_IPFrame_RequestBorderSpace\r\n");

   {
      /* FOR DEBUGING PURPOSES ONLY -- we will fail to allow to an
      **    object to get any frame border space for frame tools if
      **    our own frame tools are poped up in the tool pallet. this
      **    is NOT recommended UI behavior but it allows us to test
      **    in the condition when the frame does not give border
      **    space for the object. an object in this situation must
      **    then either popup its tools in a floating pallet, do
      **    without the tools, or fail to in-place activate.
      */
      LPCONTAINERAPP lpContainerApp =
            ((struct COleInPlaceFrameImpl FAR*)lpThis)->lpContainerApp;
      LPFRAMETOOLS lpft = OutlineApp_GetFrameTools(
            (LPOUTLINEAPP)lpContainerApp);

      if (lpft->m_ButtonBar.m_nState == BARSTATE_POPUP &&
         lpft->m_FormulaBar.m_nState == BARSTATE_POPUP) {
         OleDbgOut3(
               "CntrApp_IPFrame_RequestBorderSpace: allow NO SPACE\r\n");
         return ResultFromScode(E_FAIL);
      }
   }
#endif  // _DEBUG

   /* OLE2NOTE: we allow the object to have as much border space as it
   **    wants.
   */
   return NOERROR;
}


// IOleInPlaceFrame::SetBorderSpace
STDMETHODIMP CntrApp_IPFrame_SetBorderSpace(
   LPOLEINPLACEFRAME   lpThis,
   LPCBORDERWIDTHS     lpWidths
)
{
   LPCONTAINERAPP lpContainerApp =
         ((struct COleInPlaceFrameImpl FAR*)lpThis)->lpContainerApp;

   // artificial AddRef in case object is destroyed during call
   CntrApp_IPFrame_AddRef(lpThis);

   OLEDBG_BEGIN2("CntrApp_IPFrame_SetBorderSpace\r\n")

   /* OLE2NOTE: this fMustResizeClientArea flag is used as part of our
   **    defensive programming for frame window resizing. when the
   **    frame window is resized,IOleInPlaceActiveObject::ResizeBorder
   **    is called the object should normally call back to renegotiate
   **    for frame-level tools space. if SetBorderSpace is called then
   **    our client area windows are properly resized. if the in-place
   **    active object does NOT call SetBorderSpace, then the
   **    container must take care to resize its client area windows
   **    itself (see ContainerDoc_FrameWindowResized)
   */
   if (lpContainerApp->m_fMustResizeClientArea)
      lpContainerApp->m_fMustResizeClientArea = FALSE;

   if (lpWidths == NULL) {

      /* OLE2NOTE: IOleInPlaceSite::SetBorderSpace(NULL) is called
      **    when the in-place active object does NOT want any tool
      **    space. in this situation the in-place container should
      **    put up its tools.
      */
      LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpContainerApp;
      LPCONTAINERDOC lpContainerDoc;

      lpContainerDoc =(LPCONTAINERDOC)OutlineApp_GetActiveDoc(lpOutlineApp);
      ContainerDoc_AddFrameLevelTools(lpContainerDoc);
   } else {

      // OLE2NOTE: you could do validation of borderwidths here
#if defined( _DEBUG )
      /* FOR DEBUGING PURPOSES ONLY -- we will fail to allow to an
      **    object to get any frame border space for frame tools if
      **    our own frame tools are poped up in the tool pallet. this
      **    is NOT recommended UI behavior but it allows us to test
      **    in the condition when the frame does not give border
      **    space for the object. an object in this situation must
      **    then either popup its tools in a floating pallet, do
      **    without the tools, or fail to in-place activate.
      */
      LPFRAMETOOLS lpft = OutlineApp_GetFrameTools(
            (LPOUTLINEAPP)lpContainerApp);

      if ((lpft->m_ButtonBar.m_nState == BARSTATE_POPUP &&
         lpft->m_FormulaBar.m_nState == BARSTATE_POPUP) &&
         (lpWidths->top || lpWidths->bottom ||
            lpWidths->left || lpWidths->right) ) {
         OleDbgOut3("CntrApp_IPFrame_SetBorderSpace: allow NO SPACE\r\n");
         OLEDBG_END2

         OutlineApp_SetBorderSpace(
               (LPOUTLINEAPP) lpContainerApp,
               (LPBORDERWIDTHS)&g_rectNull
         );
         OLEDBG_END2
         // release artificial AddRef
         CntrApp_IPFrame_Release(lpThis);

         return ResultFromScode(E_FAIL);
      }
#endif  // _DEBUG

      OutlineApp_SetBorderSpace(
            (LPOUTLINEAPP) lpContainerApp,
            (LPBORDERWIDTHS)lpWidths
      );
   }
   OLEDBG_END2
   // release artificial AddRef
   CntrApp_IPFrame_Release(lpThis);

   return NOERROR;
}


// IOleInPlaceFrame::SetActiveObject
STDMETHODIMP CntrApp_IPFrame_SetActiveObject(
   LPOLEINPLACEFRAME           lpThis,
   LPOLEINPLACEACTIVEOBJECT    lpActiveObject,
   LPCOLESTR                   lpszObjName
)
{
   LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp;
   // artificial AddRef in case object is destroyed during call
   CntrApp_IPFrame_AddRef(lpThis);

   OLEDBG_BEGIN2("CntrApp_IPFrame_SetActiveObject\r\n")

   lpContainerApp->m_hWndUIActiveObj = NULL;

   if (lpContainerApp->m_lpIPActiveObj)
      lpContainerApp->m_lpIPActiveObj->lpVtbl->Release(lpContainerApp->m_lpIPActiveObj);

   if ((lpContainerApp->m_lpIPActiveObj = lpActiveObject) != NULL) {
      lpContainerApp->m_lpIPActiveObj->lpVtbl->AddRef(
            lpContainerApp->m_lpIPActiveObj);

      OLEDBG_BEGIN2("IOleInPlaceActiveObject::GetWindow called\r\n")
      lpActiveObject->lpVtbl->GetWindow(
            lpActiveObject,
            (HWND FAR*)&lpContainerApp->m_hWndUIActiveObj
      );
      OLEDBG_END2

      /* OLE2NOTE: see comment for ContainerDoc_ForwardPaletteChangedMsg */
      /* No need to do this if you don't allow object to own the palette */
      OleApp_QueryNewPalette((LPOLEAPP)lpContainerApp);
   }

   /* OLE2NOTE: the new UI Guidelines recommend that in-place
   **    containers do NOT change their window titles when an object
   **    becomes in-place (UI) active.
   */

   OLEDBG_END2
   // release artificial AddRef
   CntrApp_IPFrame_Release(lpThis);
   return NOERROR;
}


// IOleInPlaceFrame::InsertMenus
STDMETHODIMP CntrApp_IPFrame_InsertMenus(
   LPOLEINPLACEFRAME       lpThis,
   HMENU                   hMenu,
   LPOLEMENUGROUPWIDTHS    lpMenuWidths
)
{
   LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp;
   BOOL    fNoError = TRUE;

   OLEDBG_BEGIN2("CntrApp_IPFrame_InsertMenus\r\n")

   fNoError &= AppendMenu(hMenu, MF_POPUP, (UINT)lpContainerApp->m_hMenuFile,
                  "&File");
   fNoError &= AppendMenu(hMenu, MF_POPUP, (UINT)lpContainerApp->m_hMenuView,
                  "O&utline");
   fNoError &= AppendMenu(hMenu, MF_POPUP,(UINT)lpContainerApp->m_hMenuDebug,
                  "DbgI&Cntr");
   lpMenuWidths->width[0] = 1;
   lpMenuWidths->width[2] = 1;
   lpMenuWidths->width[4] = 1;

   OLEDBG_END2

   return (fNoError ? NOERROR : ResultFromScode(E_FAIL));
}


// IOleInPlaceFrame::SetMenu
STDMETHODIMP CntrApp_IPFrame_SetMenu(
   LPOLEINPLACEFRAME   lpThis,
   HMENU               hMenuShared,
   HOLEMENU            hOleMenu,
   HWND                hwndActiveObject
)
{
   LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp;
   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
   HMENU   hMenu;
   HRESULT hrErr;

   OLEDBG_BEGIN2("CntrApp_IPFrame_InsertMenus\r\n")


   /* OLE2NOTE: either put up the shared menu (combined menu from
   **    in-place server and in-place container) or our container's
   **    normal menu as directed.
   */
   if (hOleMenu && hMenuShared)
      hMenu = hMenuShared;
   else
      hMenu = lpOutlineApp->m_hMenuApp;

   /* OLE2NOTE: SDI apps put menu on frame by calling SetMenu.
   **    MDI apps would send WM_MDISETMENU message instead.
   */
   SetMenu (lpOutlineApp->m_hWndApp, hMenu);
   OLEDBG_BEGIN2("OleSetMenuDescriptor called\r\n")
   hrErr = OleSetMenuDescriptor (hOleMenu, lpOutlineApp->m_hWndApp,
               hwndActiveObject, NULL, NULL);
   OLEDBG_END2

   OLEDBG_END2
   return hrErr;
}


// IOleInPlaceFrame::RemoveMenus
STDMETHODIMP CntrApp_IPFrame_RemoveMenus(
   LPOLEINPLACEFRAME   lpThis,
   HMENU               hMenu
)
{
   LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp;
   BOOL fNoError = TRUE;

   OLEDBG_BEGIN2("CntrApp_IPFrame_RemoveMenus\r\n")

   /* Remove container group menus */
   while (GetMenuItemCount(hMenu))
      fNoError &= RemoveMenu(hMenu, 0, MF_BYPOSITION);

   OleDbgAssert(fNoError == TRUE);

   OLEDBG_END2

   return (fNoError ? NOERROR : ResultFromScode(E_FAIL));
}


// IOleInPlaceFrame::SetStatusText
STDMETHODIMP CntrApp_IPFrame_SetStatusText(
   LPOLEINPLACEFRAME   lpThis,
   LPCOLESTR           lpszStatusText
)
{
#if defined( USE_STATUSBAR )
   LPOUTLINEAPP   lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
   OLECHAR         szMessageHold[128];
   OleDbgOut2("CntrApp_IPFrame_SetStatusText\r\n");

   /* OLE2NOTE: it is important to save a private copy of status text.
   **    lpszStatusText is only valid for the duration of this call.
   */
   OLESTRCPY(szMessageHold, lpszStatusText);
   OutlineApp_SetStatusText(lpOutlineApp, (LPOLESTR)szMessageHold);

   return ResultFromScode(S_OK);
#else
   return ResultFromScode(E_NOTIMPL);
#endif  // USE_STATUSBAR
}


// IOleInPlaceFrame::EnableModeless
STDMETHODIMP CntrApp_IPFrame_EnableModeless(
   LPOLEINPLACEFRAME   lpThis,
   BOOL                fEnable
)
{
   LPOLEAPP lpOleApp = (LPOLEAPP)
         ((struct COleInPlaceFrameImpl FAR*)lpThis)->lpContainerApp;
#if defined( _DEBUG )
   if (fEnable)
      OleDbgOut2("CntrApp_IPFrame_EnableModeless(TRUE)\r\n");
   else
      OleDbgOut2("CntrApp_IPFrame_EnableModeless(FALSE)\r\n");
#endif  // _DEBUG

   /* OLE2NOTE: this method is called when an object puts up a modal
   **    dialog. it tells the top-level in-place container to disable
   **    it modeless dialogs for the duration that the object is
   **    displaying a modal dialog.
   **
   **    ICNTROTL does not use any modeless dialogs, thus we can
   **    ignore this method.
   */
   return NOERROR;
}


// IOleInPlaceFrame::TranslateAccelerator
STDMETHODIMP CntrApp_IPFrame_TranslateAccelerator(
   LPOLEINPLACEFRAME   lpThis,
   LPMSG               lpmsg,
   WORD                wID
)
{
   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
   LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp;
   SCODE sc;

   if (TranslateAccelerator (lpOutlineApp->m_hWndApp,
                  lpContainerApp->m_hAccelIPCntr, lpmsg))
      sc = S_OK;

#if defined (MDI_VERSION)
   else if (TranslateMDISysAccel(lpOutlineApp->m_hWndMDIClient, lpmsg))
      sc = S_OK;
#endif  // MDI_VERSION

   else
      sc = S_FALSE;

   return ResultFromScode(sc);
}



/*************************************************************************
** ContainerDoc Support Functions
*************************************************************************/


/* ContainerDoc_UpdateInPlaceObjectRects
** -------------------------------------
**    Update the PosRect and ClipRect of the currently in-place active
**    object. if there is no object active in-place, then do nothing.
**
**    OLE2NOTE: this function should be called when an action occurs
**    that changes either the position of the object in the document
**    (eg. changing document margins changes PosRect) or the clipRect
**    changes (eg. resizing the document window changes the ClipRect).
*/
void ContainerDoc_UpdateInPlaceObjectRects(LPCONTAINERDOC lpContainerDoc, int nIndex)
{
   LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;
   int i;
   LPLINE lpLine;
   RECT rcClipRect;

   if (g_fInsideOutContainer) {

      if (lpContainerDoc->m_cIPActiveObjects) {

         /* OLE2NOTE: (INSIDE-OUT CONTAINER) we must update the
         **    PosRect/ClipRect for all in-place active objects
         **    starting from line "nIndex".
         */
         ContainerDoc_GetClipRect(lpContainerDoc, (LPRECT)&rcClipRect);

#if defined( _DEBUG )
         OleDbgOutRect3(
               "ContainerDoc_UpdateInPlaceObjectRects (ClipRect)",
               (LPRECT)&rcClipRect
         );
#endif
         for (i = nIndex; i < lpLL->m_nNumLines; i++) {
            lpLine=LineList_GetLine(lpLL, i);

            if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) {
               LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine;
               ContainerLine_UpdateInPlaceObjectRects(
                     lpContainerLine, &rcClipRect);
            }
         }
      }
   }
   else {
      /* OLE2NOTE: (OUTSIDE-IN CONTAINER) if there is a currently
      **    UIActive object, we must inform it that the
      **    PosRect/ClipRect has now changed.
      */
      LPCONTAINERLINE lpLastUIActiveLine =
            lpContainerDoc->m_lpLastUIActiveLine;
      if (lpLastUIActiveLine && lpLastUIActiveLine->m_fUIActive) {
         ContainerDoc_GetClipRect(lpContainerDoc, (LPRECT)&rcClipRect);

         OleDbgOutRect3("OutlineDoc_Resize (ClipRect)",(LPRECT)&rcClipRect);
         ContainerLine_UpdateInPlaceObjectRects(
               lpLastUIActiveLine, &rcClipRect);
      }
   }
}

/* ContainerDoc_IsUIDeactivateNeeded
** ---------------------------------
**    Check if it is necessary to UIDeactivate an in-place active
**    object upon a mouse LBUTTONDOWN event. The position of the button
**    down click is given by "pt".
**    If there is not currently an in-place active line, then
**    UIDeactivate is NOT needed.
**    If there is a current in-place active line, then check if the
**    point position is outside of the object extents on the screen. If
**    so, then the object should be UIDeactivated, otherwise not.
*/
BOOL ContainerDoc_IsUIDeactivateNeeded(
      LPCONTAINERDOC  lpContainerDoc,
      POINT           pt
)
{
   LPCONTAINERLINE lpUIActiveLine=lpContainerDoc->m_lpLastUIActiveLine;
   RECT rect;

   if (! lpUIActiveLine || ! lpUIActiveLine->m_fUIActive)
      return FALSE;

   ContainerLine_GetPosRect(
         lpUIActiveLine,
         (LPRECT) &rect
   );

   if (! PtInRect((LPRECT) &rect, pt))
      return TRUE;

   return FALSE;
}


/* ContainerDoc_ShutDownLastInPlaceServerIfNotNeeded
** -------------------------------------------------
**    OLE2NOTE: this function ONLY applies for OUTSIDE-IN containers
**
**    If there is a previous in-place active server still running and
**    this server will not be needed to support the next OLE object
**    about to be activated, then shut it down.
**    in this way we manage a policy of having at most one in-place
**    server running at a time. we do not imediately shut down the
**    in-place server when the object is UIDeactivated because we want
**    it to be fast if the server decides to re-activate the object
**    in-place.
**
**    shutting down the server is achieved by forcing the object to
**    transition from running to loaded by calling IOleObject::Close.
*/
void ContainerDoc_ShutDownLastInPlaceServerIfNotNeeded(
      LPCONTAINERDOC          lpContainerDoc,
      LPCONTAINERLINE         lpNextActiveLine
)
{
   LPCONTAINERLINE lpLastIpActiveLine = lpContainerDoc->m_lpLastIpActiveLine;
   BOOL fEnableServerShutDown = TRUE;
   LPMONIKER lpmkLinkSrc;
   LPMONIKER lpmkLastActiveObj;
   LPMONIKER lpmkCommonPrefix;
   LPOLELINK lpOleLink;
   HRESULT hrErr;

   /* OLE2NOTE: an inside-out style container can NOT use this scheme
   **    to shut down in-place servers. it would have to have a more
   **    sophistocated mechanism by which it keeps track of which
   **    objects are on screen and which were the last recently used.
   */
   if (g_fInsideOutContainer)
      return;


   if (lpLastIpActiveLine != lpNextActiveLine) {
      if (lpLastIpActiveLine) {

         /* OLE2NOTE: if the object which is about to be activated is
         **    actually a link to the OLE object in last activated line,
         **    then we do NOT want to shut down the last activated
         **    server because it is about to be used. when activating a
         **    linked object, the source of the link gets activated.
         */
         lpOleLink = (LPOLELINK)ContainerLine_GetOleObject(
               lpNextActiveLine,
               &IID_IOleLink
         );
         if (lpOleLink) {
            OLEDBG_BEGIN2("IOleObject::GetSourceMoniker called\r\n")
            lpOleLink->lpVtbl->GetSourceMoniker(
                  lpOleLink,
                  (LPMONIKER FAR*)&lpmkLinkSrc
            );
            OLEDBG_END2

            if (lpmkLinkSrc) {
               lpmkLastActiveObj = ContainerLine_GetFullMoniker(
                     lpLastIpActiveLine,
                     GETMONIKER_ONLYIFTHERE
               );
               if (lpmkLastActiveObj) {
                  hrErr = lpmkLinkSrc->lpVtbl->CommonPrefixWith(
                        lpmkLinkSrc,
                        lpmkLastActiveObj,
                        &lpmkCommonPrefix

                  );
                  if (GetScode(hrErr) == MK_S_HIM ||
                                hrErr == NOERROR ||
                        GetScode(hrErr) == MK_S_US) {
                     /* the link source IS to the object
                     **    contained in the last activated
                     **    line of the document; disable the
                     **    attempt to shut down the last
                     **    running in-place server.
                     */
                     fEnableServerShutDown = FALSE;
                  }
                  if (lpmkCommonPrefix)
                     OleStdRelease((LPUNKNOWN)lpmkCommonPrefix);
                  OleStdRelease((LPUNKNOWN)lpmkLastActiveObj);
               }
               OleStdRelease((LPUNKNOWN)lpmkLinkSrc);
            }
            OleStdRelease((LPUNKNOWN)lpOleLink);
         }

         /* if it is OK to shut down the previous in-place server
         **    and one is still running, then shut it down. shutting
         **    down the server is accomplished by forcing the OLE
         **    object to close. this forces the object to transition
         **    from running to loaded. if the object is actually
         **    only loaded then this is a NOP.
         */
         if (fEnableServerShutDown &&
               lpLastIpActiveLine->m_fIpServerRunning) {

            OleDbgOut1("@@@ previous in-place server SHUT DOWN\r\n");
            ContainerLine_CloseOleObject(
                  lpLastIpActiveLine, OLECLOSE_SAVEIFDIRTY);

            // we can now forget this last in-place active line.
            lpContainerDoc->m_lpLastIpActiveLine = NULL;
         }
      }
   }
}


/* ContainerDoc_GetUIActiveWindow
** ------------------------------
**    If there is an UIActive object, then return its HWND.
*/
HWND ContainerDoc_GetUIActiveWindow(LPCONTAINERDOC lpContainerDoc)
{
   return lpContainerDoc->m_hWndUIActiveObj;
}


/* ContainerDoc_GetClipRect
** ------------------------
**    Get the ClipRect in client coordinates.
**
** OLE2NOTE: the ClipRect is defined as the maximum window rectangle
**    that the in-place active object must be clipped to. this
**    rectangle MUST be described in Client Coordinates of the window
**    that is used as the Parent of the in-place active object's
**    window. in our case, the LineList ListBox window is both the
**    parent of the in-place active object AND defines precisely the
**    clipping rectangle.
*/
void ContainerDoc_GetClipRect(
      LPCONTAINERDOC      lpContainerDoc,
      LPRECT              lprcClipRect
)
{
   /* OLE2NOTE: the ClipRect can be used to ensure that the in-place
   **    server does not overwrite areas of the window that the
   **    container paints into but which should never be overwritten
   **    (eg. if an app were to paint row and col headings directly in
   **    the same window that is the parent of the in-place window.
   **    whenever the window size changes or gets scrolled, in-place
   **    active object must be informed of the new clip rect.
   **
   **    normally an app would pass the rect returned from GetClientRect.
   **    but because CntrOutl uses separate windows for row/column
   **    headings, status line, formula/tool bars, etc. it is NOT
   **    necessary to pass a constrained clip rect. Windows standard
   **    window clipping will automatically take care of all clipping
   **    that is necessary. thus we can take a short cut of passing an
   **    "infinite" clip rect, and then we do NOT need to call
   **    IOleInPlaceObject::SetObjectRects when our document is scrolled.
   */

   lprcClipRect->top = -32767;
   lprcClipRect->left = -32767;
   lprcClipRect->right = 32767;
   lprcClipRect->bottom = 32767;
}


/* ContainerDoc_GetTopInPlaceFrame
** -------------------------------
**    returns NON-AddRef'ed pointer to Top In-Place Frame interface
*/
LPOLEINPLACEFRAME ContainerDoc_GetTopInPlaceFrame(
      LPCONTAINERDOC      lpContainerDoc
)
{
#if defined( INPLACE_CNTRSVR )
   return lpContainerDoc->m_lpTopIPFrame;
#else
   return (LPOLEINPLACEFRAME)&((LPCONTAINERAPP)g_lpApp)->m_OleInPlaceFrame;
#endif
}

void ContainerDoc_GetSharedMenuHandles(
      LPCONTAINERDOC  lpContainerDoc,
      HMENU FAR*      lphSharedMenu,
      HOLEMENU FAR*   lphOleMenu
)
{
#if defined( INPLACE_CNTRSVR )
   if (lpContainerDoc->m_DocType == DOCTYPE_EMEBEDDEDOBJECT) {
      *lphSharedMenu = lpContainerDoc->m_hSharedMenu;
      *lphOleMenu = lpContainerDoc->m_hOleMenu;
      return;
   }
#endif

   *lphSharedMenu = NULL;
   *lphOleMenu = NULL;
}


#if defined( USE_FRAMETOOLS )
void ContainerDoc_RemoveFrameLevelTools(LPCONTAINERDOC lpContainerDoc)
{
   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerDoc;
   OleDbgAssert(lpOutlineDoc->m_lpFrameTools != NULL);

   FrameTools_Enable(lpOutlineDoc->m_lpFrameTools, FALSE);
}
#endif


void ContainerDoc_AddFrameLevelUI(LPCONTAINERDOC lpContainerDoc)
{
   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerDoc;
   LPOLEINPLACEFRAME lpTopIPFrame = ContainerDoc_GetTopInPlaceFrame(
         lpContainerDoc);
   HMENU           hSharedMenu;            // combined obj/cntr menu
   HOLEMENU        hOleMenu;               // returned by OleCreateMenuDesc.

   ContainerDoc_GetSharedMenuHandles(
         lpContainerDoc,
         &hSharedMenu,
         &hOleMenu
   );

   lpTopIPFrame->lpVtbl->SetMenu(
         lpTopIPFrame,
         hSharedMenu,
         hOleMenu,
         lpOutlineDoc->m_hWndDoc
   );

   /* OLE2NOTE: even if our app does NOT use FrameTools, we must still
   **    call IOleInPlaceFrame::SetBorderSpace.
   */
   ContainerDoc_AddFrameLevelTools(lpContainerDoc);
}


void ContainerDoc_AddFrameLevelTools(LPCONTAINERDOC lpContainerDoc)
{
   LPOLEINPLACEFRAME lpTopIPFrame = ContainerDoc_GetTopInPlaceFrame(
         lpContainerDoc);
   LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp;
   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerDoc;


   OleDbgAssert(lpTopIPFrame != NULL);

#if defined( USE_FRAMETOOLS )

   FrameTools_Enable(lpOutlineDoc->m_lpFrameTools, TRUE);
   OutlineDoc_UpdateFrameToolButtons(lpOutlineDoc);

   FrameTools_NegotiateForSpaceAndShow(
         lpOutlineDoc->m_lpFrameTools,
         NULL,
         lpTopIPFrame
   );

#else   // ! USE_FRAMETOOLS

#if defined( INPLACE_CNTRSVR )
   if (lpContainerDoc->m_DocType == DOCTYPE_EMBEDDEDOBJECT) {
      /* this says i do not need space, so the top Frame should
      **    leave its tools behind
      */
      OLEDBG_BEGIN2("IOleInPlaceFrame::SetBorderSpace(NULL) called\r\n")
      lpTopIPFrame->lpVtbl->SetBorderSpace(lpTopIPFrame, NULL);
      OLEDBG_END2
      return;
   }
#else   // INPLACE_CNTR && ! USE_FRAMETOOLS

   OLEDBG_BEGIN2("IOleInPlaceFrame::SetBorderSpace(0,0,0,0) called\r\n")
   lpTopIPFrame->lpVtbl->SetBorderSpace(
         lpTopIPFrame,
         (LPCBORDERWIDTHS)&g_rectNull
   );
   OLEDBG_END2

#endif  // INPLACE_CNTR && ! USE_FRAMETOOLS
#endif  // ! USE_FRAMETOOLS

}


void ContainerDoc_FrameWindowResized(LPCONTAINERDOC lpContainerDoc)
{
   LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp;


   if (lpContainerApp->m_lpIPActiveObj) {
      RECT rcFrameRect;

      /* OLE2NOTE: this fMustResizeClientArea flag is used as part of
      **    our defensive programming for frame window resizing. when
      **    the frame window is
      **    resized, IOleInPlaceActiveObject::ResizeBorder is called
      **    the object should normally call back to renegotiate
      **    for frame-level tools space. if SetBorderSpace is called
      **    then our client area windows are properly resized.
      **    CntrApp_IPFrame_SetBorderSpace clears this flag. if the
      **    in-place active object does NOT call SetBorderSpace, then
      **    the container must take care to resize its client area
      **    windows itself.
      */
      lpContainerApp->m_fMustResizeClientArea = TRUE;

      OutlineApp_GetFrameRect(g_lpApp, (LPRECT)&rcFrameRect);

      OLEDBG_BEGIN2("IOleInPlaceActiveObject::ResizeBorder called\r\n")
      lpContainerApp->m_lpIPActiveObj->lpVtbl->ResizeBorder(
            lpContainerApp->m_lpIPActiveObj,
            (LPCRECT)&rcFrameRect,
            (LPOLEINPLACEUIWINDOW)&lpContainerApp->m_OleInPlaceFrame,
            TRUE    /* fFrameWindow */
      );
      OLEDBG_END2

      /* the object did NOT call IOleInPlaceUIWindow::SetBorderSpace
      **    therefore we must resize our client area windows ourself.
      */
      if (lpContainerApp->m_fMustResizeClientArea) {
         lpContainerApp->m_fMustResizeClientArea = FALSE;
         OutlineApp_ResizeClientArea(g_lpApp);
      }
   }

#if defined( USE_FRAMETOOLS )
   else {
      ContainerDoc_AddFrameLevelTools(lpContainerDoc);
   }
#endif
}


#if defined( INPLACE_CNTRSVR ) || defined( INPLACE_MDICNTR )

/* ContainerDoc_GetTopInPlaceDoc
**    returns NON-AddRef'ed pointer to Top In-Place Doc interface
*/
LPOLEINPLACEUIWINDOW ContainerDoc_GetTopInPlaceDoc(
      LPCONTAINERDOC      lpContainerDoc
)
{
#if defined( INPLACE_CNTRSVR )
   return lpContainerDoc->m_lpTopIPDoc;
#else
   return (LPOLEINPLACEUIWINDOW)&lpContainerDoc->m_OleInPlaceDoc;
#endif
}


void ContainerDoc_RemoveDocLevelTools(LPCONTAINERDOC lpContainerDoc);
{
   LPOLEINPLACEUIWINDOW lpTopIPDoc = ContainerDoc_GetTopInPlaceDoc(
         lpContainerDoc);

   if (lpTopIPDoc && lpContainerDoc->m_fMyToolsOnDoc) {
      lpContainerDoc->m_fMyToolsOnDoc = FALSE;

      // if we had doc tools we would HIDE them here;
      //   but NOT call SetBorderSpace(NULL)

   }
}

void ContainerDoc_AddDocLevelTools(LPCONTAINERDOC lpContainerDoc)
{
   LPOLEINPLACEUIWINDOW lpTopIPDoc = ContainerDoc_GetTopInPlaceDoc(
         lpContainerDoc);

   if (! lpTopIPDoc)
      return;


#if defined( USE_DOCTOOLS )
   if (lpTopIPDoc && ! lpContainerDoc->m_fMyToolsOnDoc) {

      /* if we had doc tools we would negotiate for toolbar space at
      **    doc level and SHOW them.
      */

      /* we do NOT have doc level tools, so we just call
      **    SetBorderSpace() to indicate to the top doc that
      **    our object does not need tool space.
      */

      lpContainerDoc->m_fMyToolsOnDoc = TRUE;
      return;
   }
#else   // ! USE_DOCTOOLS

#if defined( INPLACE_CNTRSVR )
   if (lpContainerDoc->m_DocType == DOCTYPE_EMBEDDEDOBJECT) {
      /* this says i do not need space, so the top doc should
      **    leave its tools behind
      */
      lpTopIPDoc->lpVtbl->SetBorderSpace(lpTopIPDoc, NULL);
      return;
   }
#else
   lpTopIPDoc->lpVtbl->SetBorderSpace(
         lpTopIPDoc,
         (LPCBORDERWIDTHS)&g_rectNull
   );

#endif
#endif  // ! USE_DOCTOOLS
}

#endif  // INPLACE_CNTRSVR || INPLACE_MDICNTR


/* ContainerDoc_ContextSensitiveHelp
** ---------------------------------
**    forward the ContextSensitiveHelp mode on to any in-place objects
**    that currently have their window visible. this informs the
**    objects whether to give help or take action on subsequent mouse
**    clicks and menu commands. this function is called from our
**    IOleInPlaceSite::ContextSensitiveHelp implementation.
**
** OLE2NOTE: see context sensitive help technote (CSHELP.DOC).
**    This function is called when SHIFT-F1 context sensitive help is
**    entered. the cursor should then change to a question mark
**    cursor and the app should enter a modal state where the next
**    mouse click does not perform its normal action but rather
**    gives help corresponding to the location clicked. if the app
**    does not implement a help system, it should at least eat the
**    click and do nothing.
*/
void ContainerDoc_ContextSensitiveHelp(
      LPCONTAINERDOC  lpContainerDoc,
      BOOL            fEnterMode,
      BOOL            fInitiatedByObj
)
{
   LPOLEDOC lpOleDoc = (LPOLEDOC)lpContainerDoc;
   LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;
   int i;
   LPLINE lpLine;

   lpOleDoc->m_fCSHelpMode = fEnterMode;

   if (g_fInsideOutContainer) {

      if (lpContainerDoc->m_cIPActiveObjects) {
         for (i = 0; i < lpLL->m_nNumLines; i++) {
            lpLine=LineList_GetLine(lpLL, i);

            if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) {
               LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine;
               ContainerLine_ContextSensitiveHelp(
                     lpContainerLine, fEnterMode);
            }
         }
      }
   }
   else if (! fInitiatedByObj) {
      /* OLE2NOTE: (OUTSIDE-IN CONTAINER) if there is a currently
      **    UIActive object (ie. its window is visible), we must
      **    forward the ContextSensitiveHelp mode on to the
      **    object--assuming it was not the object that initiated the
      **    context sensitve help mode.
      */
      LPCONTAINERLINE lpLastUIActiveLine =
            lpContainerDoc->m_lpLastUIActiveLine;
      if (lpLastUIActiveLine && lpLastUIActiveLine->m_fUIActive) {
         ContainerLine_ContextSensitiveHelp(lpLastUIActiveLine,fEnterMode);
      }
   }
}

/* ContainerDoc_ForwardPaletteChangedMsg
** -------------------------------------
**    forward the WM_PALETTECHANGED message (via SendMessage) to any
**    in-place objects that currently have their window visible. this
**    gives these objects the chance to select their palette as a
**    BACKGROUND palette.
**
**    SEE THE TECHNOTE FOR DETAILED INFORMATION ON PALETTE COORDINATION
**
**    OLE2NOTE: For containers and objects to manage palettes properly
**    (when objects are getting inplace edited) they should follow a
**    set of rules.
**
**    Rule 1: The Container can decide if it wants to own the palette or
**    it wants to allow its UIActive object to own the palette.
**    a) If the container wants to let its UIActive object own the
**    palette then it should forward WM_QUERYNEWPALETTE to the object
**    when it is received to the top frame window. also it should send
**    WM_QUERYNEWPALETTE to the object in its
**    IOleInPlaceFrame::SetActiveObject implementation. if the object
**    is given ownership of the palette, then it owns the palette until
**    it is UIDeactivated.
**    b) If the container wants to own the palette it should NOT send
**    WM_QUERYNEWPALETTE to the UIActive object.
**
**    Rule 2: Whether the container wants to own the palette or not, it
**    should forward the WM_PALETTECHANGED to the immediate child
**    inplace active objects in its documents. if it is an inside-out
**    style container then it must forward it to ALL objects that
**    currently have their windows visible. When the object recives the
**    WM_PALETTECHANGED message it must select its color palette as the
**    background palette. When the objects are in loaded state they will be
**    drawn by (OLE) by selecting their palettes as background palettes
**    anyway.
**
**    Note: IOleObject::SetColorScheme is not related to the palette
**    issue.
*/
void ContainerDoc_ForwardPaletteChangedMsg(
      LPCONTAINERDOC  lpContainerDoc,
      HWND            hwndPalChg
)
{
   LPLINELIST lpLL;
   int i;
   LPLINE lpLine;

   if (!lpContainerDoc)
      return;

   lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;
   if (g_fInsideOutContainer) {

      if (lpContainerDoc->m_cIPActiveObjects) {
         for (i = 0; i < lpLL->m_nNumLines; i++) {
            lpLine=LineList_GetLine(lpLL, i);

            if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) {
               LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine;
               ContainerLine_ForwardPaletteChangedMsg(
                     lpContainerLine, hwndPalChg);
            }
         }
      }
   }
   else {
      /* OLE2NOTE: (OUTSIDE-IN CONTAINER) if there is a currently
      **    UIActive object (ie. its window is visible), we must
      **    forward it the WM_PALETTECHANGED message.
      */
      LPCONTAINERLINE lpLastUIActiveLine =
            lpContainerDoc->m_lpLastUIActiveLine;
      if (lpLastUIActiveLine && lpLastUIActiveLine->m_fUIActive) {
         ContainerLine_ForwardPaletteChangedMsg(
               lpLastUIActiveLine, hwndPalChg);
      }
   }
}


/*************************************************************************
** ContainerLine Support Functions and Interfaces
*************************************************************************/


/* ContainerLine_UIDeactivate
** --------------------------
**    tell the OLE object associated with the ContainerLine to
**    UIDeactivate. this informs the in-place server to tear down
**    the UI and window that it put up for the object. it will remove
**    its active editor menus and any frame and object adornments
**    (eg. toolbars, rulers, etc.).
*/
void ContainerLine_UIDeactivate(LPCONTAINERLINE lpContainerLine)
{
   HRESULT hrErr;

   if (!lpContainerLine || !lpContainerLine->m_fUIActive)
      return;

   OLEDBG_BEGIN2("IOleInPlaceObject::UIDeactivate called\r\n")
   hrErr = lpContainerLine->m_lpOleIPObj->lpVtbl->UIDeactivate(
         lpContainerLine->m_lpOleIPObj);
   OLEDBG_END2

   if (hrErr != NOERROR) {
      OleDbgOutHResult("IOleInPlaceObject::UIDeactivate returned", hrErr);
   }
}



/* ContainerLine_UpdateInPlaceObjectRects
** -------------------------------------
**    Update the PosRect and ClipRect of the given line
**    currently in-place active
**    object. if there is no object active in-place, then do nothing.
**
**    OLE2NOTE: this function should be called when an action occurs
**    that changes either the position of the object in the document
**    (eg. changing document margins changes PosRect) or the clipRect
**    changes (eg. resizing the document window changes the ClipRect).
*/
void ContainerLine_UpdateInPlaceObjectRects(
      LPCONTAINERLINE lpContainerLine,
      LPRECT          lprcClipRect
)
{
   LPCONTAINERDOC lpContainerDoc = lpContainerLine->m_lpDoc;
   RECT rcClipRect;
   RECT rcPosRect;

   if (! lpContainerLine->m_fIpVisible)
      return;

   if (! lprcClipRect) {
      ContainerDoc_GetClipRect(lpContainerDoc, (LPRECT)&rcClipRect);
      lprcClipRect = (LPRECT)&rcClipRect;
   }

#if defined( _DEBUG )
   OleDbgOutRect3(
         "ContainerLine_UpdateInPlaceObjectRects (ClipRect)",
         (LPRECT)&rcClipRect
   );
#endif
   ContainerLine_GetPosRect(lpContainerLine,(LPRECT)&rcPosRect);

#if defined( _DEBUG )
   OleDbgOutRect3(
      "ContainerLine_UpdateInPlaceObjectRects (PosRect)",(LPRECT)&rcPosRect);
#endif

   OLEDBG_BEGIN2("IOleInPlaceObject::SetObjectRects called\r\n")
   lpContainerLine->m_lpOleIPObj->lpVtbl->SetObjectRects(
         lpContainerLine->m_lpOleIPObj,
         (LPRECT)&rcPosRect,
         lprcClipRect
   );
   OLEDBG_END2
}


/* ContainerLine_ContextSensitveHelp
** ---------------------------------
**    forward the ContextSensitiveHelp mode on to the in-place object
**    if it currently has its window visible. this informs the
**    object whether to give help or take action on subsequent mouse
**    clicks and menu commands.
**
**    this function is called from ContainerDoc_ContextSensitiveHelp
**    function as a result of a call to
**    IOleInPlaceSite::ContextSensitiveHelp if the in-place container
**    is operating as an in-side out container.
*/
void ContainerLine_ContextSensitiveHelp(
      LPCONTAINERLINE lpContainerLine,
      BOOL            fEnterMode
)
{
   if (! lpContainerLine->m_fIpVisible)
      return;

   OLEDBG_BEGIN2("IOleInPlaceObject::ContextSensitiveHelp called\r\n")
   lpContainerLine->m_lpOleIPObj->lpVtbl->ContextSensitiveHelp(
         lpContainerLine->m_lpOleIPObj, fEnterMode);
   OLEDBG_END2
}


/* ContainerLine_ForwardPaletteChangedMsg
** --------------------------------------
**    forward it the WM_PALETTECHANGED message (via SendMessage) to the
**    in-place object if it currently has its window visible. this
**    gives the object the chance to select its palette as a BACKGROUND
**    palette if it doesn't own the palette--or as the
**    foreground palette if it currently DOES own the palette.
**
**    SEE THE TECHNOTE FOR DETAILED INFORMATION ON PALETTE COORDINATION
*/
void ContainerLine_ForwardPaletteChangedMsg(
      LPCONTAINERLINE lpContainerLine,
      HWND             hwndPalChg
)
{
   if (! lpContainerLine->m_fIpVisible)
      return;

   if (lpContainerLine->m_hWndIpObject)
   {
       SendMessage(
             lpContainerLine->m_hWndIpObject,
             WM_PALETTECHANGED,
             (WPARAM)hwndPalChg,
             0L
       );
   }
}



/*************************************************************************
** ContainerLine::IOleInPlaceSite interface implementation
*************************************************************************/

STDMETHODIMP CntrLine_IPSite_QueryInterface(
      LPOLEINPLACESITE    lpThis,
      REFIID              riid,
      LPVOID FAR*         lplpvObj
)
{
   LPCONTAINERLINE lpContainerLine =
         ((struct COleInPlaceSiteImpl FAR*)lpThis)->lpContainerLine;

   return ContainerLine_QueryInterface(lpContainerLine, riid, lplpvObj);
}


STDMETHODIMP_(ULONG) CntrLine_IPSite_AddRef(LPOLEINPLACESITE lpThis)
{
   LPCONTAINERLINE lpContainerLine =
         ((struct COleInPlaceSiteImpl FAR*)lpThis)->lpContainerLine;

   OleDbgAddRefMethod(lpThis, "IOleInPlaceSite");

   return ContainerLine_AddRef(lpContainerLine);
}


STDMETHODIMP_(ULONG) CntrLine_IPSite_Release(LPOLEINPLACESITE lpThis)
{
   LPCONTAINERLINE lpContainerLine =
         ((struct COleInPlaceSiteImpl FAR*)lpThis)->lpContainerLine;

   OleDbgReleaseMethod(lpThis, "IOleInPlaceSite");

   return ContainerLine_Release(lpContainerLine);
}


STDMETHODIMP CntrLine_IPSite_GetWindow(
   LPOLEINPLACESITE    lpThis,
   HWND FAR*           lphwnd
)
{
   LPCONTAINERLINE lpContainerLine =
         ((struct COleInPlaceSiteImpl FAR*)lpThis)->lpContainerLine;

   // artificial AddRef in case object is destroyed during call
   CntrLine_IPSite_AddRef(lpThis);

   OleDbgOut2("CntrLine_IPSite_GetWindow\r\n");

   *lphwnd = LineList_GetWindow(
         &((LPOUTLINEDOC)lpContainerLine->m_lpDoc)->m_LineList);

   // release artificial AddRef
   CntrLine_IPSite_Release(lpThis);

   return NOERROR;
}

// IOleInPlaceSite::ContextSensitiveHelp
STDMETHODIMP CntrLine_IPSite_ContextSensitiveHelp(
   LPOLEINPLACESITE    lpThis,
   BOOL                fEnterMode
)
{
   LPCONTAINERLINE lpContainerLine =
         ((struct COleInPlaceSiteImpl FAR*)lpThis)->lpContainerLine;
   LPOLEDOC lpOleDoc = (LPOLEDOC)lpContainerLine->m_lpDoc;

   // artificial AddRef in case object is destroyed during call
   CntrLine_IPSite_AddRef(lpThis);

   OleDbgOut2("CntrLine_IPSite_ContextSensitiveHelp\r\n");

   /* OLE2NOTE: see context sensitive help technote (CSHELP.DOC).
   **    This method is called when SHIFT-F1 context sensitive help is
   **    entered. the cursor should then change to a question mark
   **    cursor and the app should enter a modal state where the next
   **    mouse click does not perform its normal action but rather
   **    gives help corresponding to the location clicked. if the app
   **    does not implement a help system, it should at least eat the
   **    click and do nothing.
   **
   **    NOTE: the implementation here is specific to an SDI simple
   **    container. an MDI container or container/server application
   **    would have additional work to do (see the technote).
   **
   **    NOTE: (INSIDE-OUT CONTAINER) if there are currently
   **    any in-place objects active with their windows visible
   **    (ie. fIpVisible), we must forward the
   **    ContextSensitiveHelp mode on to these objects.
   */
   ContainerDoc_ContextSensitiveHelp(
            lpContainerLine->m_lpDoc,fEnterMode,TRUE /*InitiatedByObj*/);

   // release artificial AddRef
   CntrLine_IPSite_Release(lpThis);
   return NOERROR;
}


STDMETHODIMP CntrLine_IPSite_CanInPlaceActivate(LPOLEINPLACESITE lpThis)
{
   LPCONTAINERLINE lpContainerLine =
         ((struct COleInPlaceSiteImpl FAR*)lpThis)->lpContainerLine;
   OleDbgOut2("CntrLine_IPSite_CanInPlaceActivate\r\n");

   /* OLE2NOTE: the container can NOT allow in-place activation if it
   **    is currently displaying the object as an ICON
   **    (DVASPECT_ICON). it can ONLY do in-place activation if it is
   **    displaying the DVASPECT_CONTENT of the OLE object.
   */
   if (lpContainerLine->m_dwDrawAspect == DVASPECT_CONTENT)
      return NOERROR;
   else
      return ResultFromScode(S_FALSE);
}

STDMETHODIMP CntrLine_IPSite_OnInPlaceActivate(LPOLEINPLACESITE lpThis)
{
   LPCONTAINERLINE lpContainerLine =
         ((struct COleInPlaceSiteImpl FAR*)lpThis)->lpContainerLine;
   LPCONTAINERDOC lpContainerDoc = lpContainerLine->m_lpDoc;
   SCODE sc = S_OK;

   // artificial AddRef in case object is destroyed during call
   CntrLine_IPSite_AddRef(lpThis);
   OLEDBG_BEGIN2("CntrLine_IPSite_OnInPlaceActivate\r\n");

   /* OLE2NOTE: (OUTSIDE-IN CONTAINER) as a policy for managing
   **    running in-place servers, we will keep only 1 inplace server
   **    active at any given time. so when we start to inp-place activate
   **    another line, then we want to shut down the previously
   **    activated server. in this way we keep at most one inplace
   **    server active at a time. this is NOT a required policy. apps
   **    may choose to have a more sophisticated strategy. inside-out
   **    containers will HAVE to have a more sophisticated strategy,
   **    because they need (at a minimum) to keep all visible object
   **    servers running.
   **
   **    if the in-place activation is the result of activating a
   **    linked object in another container, then we may arrive at
   **    this method while another object is currently active.
   **    normally, if the object is in-place activated by
   **    double-clicking or Edit.<verb> from our own container, then
   **    the previous in-place object would have been de-activated in
   **    ContainerLine_DoVerb method.
   */
   if (!g_fInsideOutContainer) {
      if (lpContainerDoc->m_lpLastIpActiveLine) {
         ContainerDoc_ShutDownLastInPlaceServerIfNotNeeded(
               lpContainerDoc, lpContainerLine);
      }
      lpContainerDoc->m_lpLastIpActiveLine = lpContainerLine;
   }

   /* OLE2NOTE: to avoid LRPC problems it is important to cache the
   **    IOleInPlaceObject* pointer and NOT to call QueryInterface
   **    each time it is needed.
   */
   lpContainerLine->m_lpOleIPObj = (LPOLEINPLACEOBJECT)
         ContainerLine_GetOleObject(lpContainerLine,&IID_IOleInPlaceObject);

   if (! lpContainerLine->m_lpOleIPObj) {
#if defined( _DEBUG )
      OleDbgAssertSz(
            lpContainerLine->m_lpOleIPObj!=NULL,
            "OLE object must support IOleInPlaceObject"
      );
#endif
      // release artificial AddRef
      CntrLine_IPSite_Release(lpThis);
      return ResultFromScode(E_FAIL); // ERROR: refuse to in-place activate
   }

   lpContainerLine->m_fIpActive        = TRUE;
   lpContainerLine->m_fIpVisible       = TRUE;

   OLEDBG_BEGIN2("IOleInPlaceObject::GetWindow called\r\n")
   lpContainerLine->m_lpOleIPObj->lpVtbl->GetWindow(
         lpContainerLine->m_lpOleIPObj,
         (HWND FAR*)&lpContainerLine->m_hWndIpObject
   );
   OLEDBG_END2

   if (! lpContainerLine->m_fIpServerRunning) {
      /* OLE2NOTE: it is VERY important that an in-place container
      **    that also support linking to embeddings properly manage
      **    the running of its in-place objects. in an outside-in
      **    style in-place container, when the user clicks
      **    outside of the in-place active object, the object gets
      **    UIDeactivated and the object hides its window. in order
      **    to make the object fast to reactivate, the container
      **    deliberately does not call IOleObject::Close. the object
      **    stays running in the invisible unlocked state. the idea
      **    here is if the user simply clicks outside of the object
      **    and then wants to double click again to re-activate the
      **    object, we do not want this to be slow. if we want to
      **    keep the object running, however, we MUST Lock it
      **    running. otherwise the object will be in an unstable
      **    state where if a linking client does a "silent-update"
      **    (eg. UpdateNow from the Links dialog), then the in-place
      **    server will shut down even before the object has a chance
      **    to be saved back in its container. this saving normally
      **    occurs when the in-place container closes the object. also
      **    keeping the object in the unstable, hidden, running,
      **    not-locked state can cause problems in some scenarios.
      **    ICntrOtl keeps only one object running. if the user
      **    intiates a DoVerb on another object, then that last
      **    running in-place active object is closed. a more
      **    sophistocated in-place container may keep more object running.
      **    this lock gets unlocked in ContainerLine_CloseOleObject.
      */
      lpContainerLine->m_fIpServerRunning = TRUE;

      OLEDBG_BEGIN2("OleLockRunning(TRUE, 0) called\r\n")
      OleLockRunning((LPUNKNOWN)lpContainerLine->m_lpOleIPObj, TRUE, 0);
      OLEDBG_END2
   }

   lpContainerLine->m_lpDoc->m_cIPActiveObjects++;

   OLEDBG_END2
   // release artificial AddRef
   CntrLine_IPSite_Release(lpThis);
   return NOERROR;
}


STDMETHODIMP CntrLine_IPSite_OnUIActivate (LPOLEINPLACESITE lpThis)
{
   LPCONTAINERLINE lpContainerLine =
         ((struct COleInPlaceSiteImpl FAR*)lpThis)->lpContainerLine;
   LPCONTAINERDOC lpContainerDoc = lpContainerLine->m_lpDoc;
   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc;
   LPCONTAINERLINE lpLastUIActiveLine = lpContainerDoc->m_lpLastUIActiveLine;

   // artificial AddRef in case object is destroyed during call
   CntrLine_IPSite_AddRef(lpThis);

   OLEDBG_BEGIN2("CntrLine_IPSite_OnUIActivate\r\n");

   lpContainerLine->m_fUIActive        = TRUE;
   lpContainerDoc->m_fAddMyUI          = FALSE;
   lpContainerDoc->m_lpLastUIActiveLine = lpContainerLine;

   if (g_fInsideOutContainer) {
      /* OLE2NOTE: (INSIDE-OUT CONTAINER) an inside-out style
      **    container must UIDeactivate the previous UIActive object
      **    when a new object is going UIActive. since the inside-out
      **    objects have their own windows visible, it is possible
      **    that a click directly in an another server window will
      **    cause it to UIActivate. OnUIActivate is the containers
      **    notification that such has occured. it must then
      **    UIDeactivate the other because at most one object can be
      **    UIActive at a time.
      */
      if (lpLastUIActiveLine && (lpLastUIActiveLine!=lpContainerLine)) {
         ContainerLine_UIDeactivate(lpLastUIActiveLine);

         // Make sure new UIActive window is on top of all others
         SetWindowPos(
               lpContainerLine->m_hWndIpObject,
               HWND_TOPMOST,
               0,0,0,0,
               SWP_NOMOVE | SWP_NOSIZE
         );

         OLEDBG_END2
         goto cleanup;
      }
   }

   lpContainerDoc->m_hWndUIActiveObj = lpContainerLine->m_hWndIpObject;

#if defined( USE_FRAMETOOLS )
   ContainerDoc_RemoveFrameLevelTools(lpContainerDoc);
#endif

#if defined( USE_DOCTOOLS )
   ContainerDoc_RemoveDocLevelTools(lpContainerDoc);
#endif

   OLEDBG_END2
cleanup:
   // release artificial AddRef
   CntrLine_IPSite_Release(lpThis);

   return NOERROR;
}


STDMETHODIMP CntrLine_IPSite_GetWindowContext(
   LPOLEINPLACESITE            lpThis,
   LPOLEINPLACEFRAME FAR*      lplpFrame,
   LPOLEINPLACEUIWINDOW FAR*   lplpDoc,
   LPRECT                      lprcPosRect,
   LPRECT                      lprcClipRect,
   LPOLEINPLACEFRAMEINFO       lpFrameInfo
)
{
   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
   LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp;
   LPCONTAINERLINE lpContainerLine =
         ((struct COleInPlaceSiteImpl FAR*)lpThis)->lpContainerLine;

   // artificial AddRef in case object is destroyed during call
   CntrLine_IPSite_AddRef(lpThis);

   OLEDBG_BEGIN2("CntrLine_IPSite_GetWindowContext\r\n")

   /* OLE2NOTE: The server should fill in the "cb" field so that the
   **    container can tell what size structure the server is
   **    expecting. this enables this structure to be easily extended
   **    in future releases of OLE. the container should check this
   **    field so that it doesn't try to use fields that do not exist
   **    since the server may be using an old structure definition.
   **    Since this is the first release of OLE2.0, the structure is
   **    guaranteed to be at least large enough for the current
   **    definition of OLEINPLACEFRAMEINFO struct. thus we do NOT need
   **    to consider this an error if the server did not fill in this
   **    field correctly. this server may have trouble in the future,
   **    however, when the structure is extended.
   */
   *lplpFrame = (LPOLEINPLACEFRAME)&lpContainerApp->m_OleInPlaceFrame;
   (*lplpFrame)->lpVtbl->AddRef(*lplpFrame);   // must return AddRef'ed ptr

   // OLE2NOTE: an MDI app would have to provide *lplpDoc
   *lplpDoc  = NULL;

   ContainerLine_GetPosRect(lpContainerLine, lprcPosRect);
   ContainerDoc_GetClipRect(lpContainerLine->m_lpDoc, lprcClipRect);

   OleDbgOutRect3("CntrLine_IPSite_GetWindowContext (PosRect)", lprcPosRect);
   OleDbgOutRect3("CntrLine_IPSite_GetWindowContext (ClipRect)",lprcClipRect);
   lpFrameInfo->hwndFrame      = lpOutlineApp->m_hWndApp;

#if defined( MDI_VERSION )
   lpFrameInfo->fMDIApp        = TRUE;
#else
   lpFrameInfo->fMDIApp        = FALSE;
#endif

   lpFrameInfo->haccel         = lpContainerApp->m_hAccelIPCntr;
   lpFrameInfo->cAccelEntries  =
      GetAccelItemCount(lpContainerApp->m_hAccelIPCntr);

   OLEDBG_END2
   // release artificial AddRef
   CntrLine_IPSite_Release(lpThis);
   return NOERROR;
}


STDMETHODIMP CntrLine_IPSite_Scroll(
   LPOLEINPLACESITE    lpThis,
   SIZE                scrollExtent
)
{
   OleDbgOut2("CntrLine_IPSite_Scroll\r\n");
   return ResultFromScode(E_FAIL);
}


STDMETHODIMP CntrLine_IPSite_OnUIDeactivate(
   LPOLEINPLACESITE    lpThis,
   BOOL                fUndoable
)
{
   LPCONTAINERLINE lpContainerLine =
         ((struct COleInPlaceSiteImpl FAR*)lpThis)->lpContainerLine;
   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc;
   LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP) g_lpApp;
   LPLINELIST lpLL;
   int nIndex;
   MSG msg;
   HRESULT hrErr;

   // artificial AddRef in case object is destroyed during call
   CntrLine_IPSite_AddRef(lpThis);

   OLEDBG_BEGIN2("CntrLine_IPSite_OnUIDeactivate\r\n")

   lpContainerLine->m_fUIActive = FALSE;
   lpContainerLine->m_fIpChangesUndoable = fUndoable;
   lpContainerLine->m_lpDoc->m_hWndUIActiveObj = NULL;

   if (lpContainerLine == lpContainerLine->m_lpDoc->m_lpLastUIActiveLine) {

      lpContainerLine->m_lpDoc->m_lpLastUIActiveLine = NULL;

      /* OLE2NOTE: here we look ahead if there is a DBLCLK sitting in our
      **    message queue. if so, it could result in in-place activating
      **    another object. we want to avoid placing our tools and
      **    repainting if immediately another object is going to do the
      **    same. SO, if there is a DBLCLK in the queue for this document
      **    we will only set the fAddMyUI flag to indicate that this work
      **    is still to be done. if another object actually in-place
      **    activates then this flag will be cleared in
      **    IOleInPlaceSite::OnUIActivate. if it does NOT get cleared,
      **    then at the end of processing the DBLCLK message in our
      **    OutlineDocWndProc we will put our tools back.
      */
      if (! PeekMessage(&msg, lpOutlineDoc->m_hWndDoc,
            WM_LBUTTONDBLCLK, WM_LBUTTONDBLCLK,
            PM_NOREMOVE | PM_NOYIELD)) {

         /* OLE2NOTE: You need to generate QueryNewPalette only if
         **    you own the top level frame (ie. you are a top-level
         **    inplace container).
         */

         OleApp_QueryNewPalette((LPOLEAPP)g_lpApp);

#if defined( USE_DOCTOOLS )
         ContainerDoc_AddDocLevelTools(lpContainerLine->m_lpDoc);
#endif

#if defined( USE_FRAMETOOLS )
         ContainerDoc_AddFrameLevelUI(lpContainerLine->m_lpDoc);
#endif
      } else {
         lpContainerLine->m_lpDoc->m_fAddMyUI = TRUE;
      }

      /* OLE2NOTE: we should re-take focus. the in-place server window
      **    previously had the focus; this window has just been removed.
      */
      SetFocus(OutlineDoc_GetWindow((LPOUTLINEDOC)lpContainerLine->m_lpDoc));

      // force the line to redraw to remove in-place active hatch
      lpLL = OutlineDoc_GetLineList(lpOutlineDoc);
      nIndex = LineList_GetLineIndex(lpLL, (LPLINE)lpContainerLine);
      LineList_ForceLineRedraw(lpLL, nIndex, TRUE);
   }

#if defined( UNDOSUPPORTED )

   /* OLE2NOTE: an outside-in style container that supports UNDO would
   **    call IOleObject::DoVerb(OLEIVERB_HIDE) to make the in-place
   **    object go invisible. when it wants the in-place active object
   **    to discard its undo state, it would call
   **    IOleInPlaceObject::InPlaceDeactivate when it wants the object
   **    to discard its undo state. there is no need for an outside-in
   **    style container to call
   **    IOleObject::DoVerb(OLEIVERB_DISCARDUNDOSTATE). if either the
   **    container or the object do not support UNDO, then the
   **    container might as well immediately call InPlaceDeactivate
   **    instead of calling DoVerb(HIDE).
   **
   **    an inside-out style container that supports UNDO would simply
   **    UIDeactivate the object. it would call
   **    IOleObject::DoVerb(OLEIVERB_DISCARDUNDOSTATE) when it wants
   **    the object discard its undo state. it would call
   **    IOleInPlaceObject::InPlaceDeactivate if it wants the object
   **    to take down its window.
   */
   if (! g_fInsideOutContainer || !lpContainerLine->m_fInsideOutObj) {

      if (lpContainerLine->m_fIpChangesUndoable) {
         ContainerLine_DoVerb(
               lpContainerLine,OLEIVERB_HIDE,NULL,FALSE,FALSE);
      } else {
         lpContainerLine->m_lpOleIPObj->lpVtbl->InPlaceDeactivate(
               lpContainerLine->m_lpOleIPObj);
      }
      lpContainerLine->m_fIpVisible = FALSE;
      lpContainerLine->m_hWndIpObject = NULL;
   }
#else

   /* OLE2NOTE: an outside-in style container that does NOT support
   **    UNDO would immediately tell the UIDeactivated server (UI
   **    removed) to IOleInPlaceObject::InPlaceDeactivate.
   **
   **    an inside-out style container that does NOT support UNDO
   **    would call IOleObject::DoVerb(OLEIVERB_DISCARDUNDOSTATE) to
   **    tell the object to discard its undo state. it would call
   **    IOleInPlaceObject::InPlaceDeactivate if it wants the object
   **    to take down its window.
   */

   if (g_fInsideOutContainer) {

      if (lpContainerLine->m_fInsideOutObj) {

         if (lpContainerLine->m_fIpChangesUndoable) {
            OLEDBG_BEGIN3("ContainerLine_DoVerb(OLEIVERB_DISCARDUNDOSTATE) called!\r\n")
            ContainerLine_DoVerb(lpContainerLine,
                  OLEIVERB_DISCARDUNDOSTATE,NULL,FALSE,FALSE);
            OLEDBG_END3
         }

      } else {    // !fInsideOutObj

         /* OLE2NOTE: (INSIDEOUT CONTAINER) if the object is not
         **    registered OLEMISC_ACTIVATEWHENVISIBLE, then we will
         **    make the object behave in an outside-in manner. since
         **    we do NOT deal with UNDO we can simply
         **    InPlaceDeactivate the object. it should NOT be
         **    allowed to leave its window visible when
         **    UIDeactivated.
         */
         OLEDBG_BEGIN2("IOleInPlaceObject::InPlaceDeactivate called\r\n")
         hrErr = lpContainerLine->m_lpOleIPObj->lpVtbl->InPlaceDeactivate(
                  lpContainerLine->m_lpOleIPObj);
         OLEDBG_END2
         if (hrErr != NOERROR) {
            OleDbgOutHResult("IOleInPlaceObject::InPlaceDeactivate returned", hrErr);
         }
      }

   } else {

      /* OLE2NOTE: (OUTSIDE-IN CONTAINER) since we do NOT deal with
      **    UNDO we can simply InPlaceDeactivate the object. it
      **    should NOT be allowed to leave its window visible when
      **    UIDeactivated.
        **
        **    NOTE: In-place servers must handle InPlaceDeactivate
        **    being called before its call to
        **    IOleInPlaceSite::OnUIDeactivate returns. in case there
        **    are misbehaving servers out there, one way to work around
        **    this problem is to call
        **    IOleObject::DoVerb(OLEIVERB_HIDE...) here.
      */
      OLEDBG_BEGIN2("IOleInPlaceObject::InPlaceDeactivate called\r\n")
      hrErr = lpContainerLine->m_lpOleIPObj->lpVtbl->InPlaceDeactivate(
            lpContainerLine->m_lpOleIPObj);
      OLEDBG_END2
      if (hrErr != NOERROR) {
         OleDbgOutHResult("IOleInPlaceObject::InPlaceDeactivate returned", hrErr);
      }
   }

#endif // ! UNDOSUPPORTED

   OLEDBG_END2
   // release artificial AddRef
   CntrLine_IPSite_Release(lpThis);
   return NOERROR;
}


STDMETHODIMP CntrLine_IPSite_OnInPlaceDeactivate(LPOLEINPLACESITE lpThis)
{
   LPCONTAINERLINE lpContainerLine =
         ((struct COleInPlaceSiteImpl FAR*)lpThis)->lpContainerLine;

   // artificial AddRef in case object is destroyed during call
   CntrLine_IPSite_AddRef(lpThis);
   OLEDBG_BEGIN2("CntrLine_IPSite_OnInPlaceDeactivate\r\n");

   lpContainerLine->m_fIpActive            = FALSE;
   lpContainerLine->m_fIpVisible           = FALSE;
   lpContainerLine->m_fIpChangesUndoable   = FALSE;
   lpContainerLine->m_hWndIpObject         = NULL;

   OleStdRelease((LPUNKNOWN) lpContainerLine->m_lpOleIPObj);
   lpContainerLine->m_lpOleIPObj = NULL;
   lpContainerLine->m_lpDoc->m_cIPActiveObjects--;

   OLEDBG_END2
   // release artificial AddRef
   CntrLine_IPSite_Release(lpThis);
   return NOERROR;
}


STDMETHODIMP CntrLine_IPSite_DiscardUndoState(LPOLEINPLACESITE lpThis)
{
   OleDbgOut2("CntrLine_IPSite_DiscardUndoState\r\n");
   return NOERROR;
}


STDMETHODIMP CntrLine_IPSite_DeactivateAndUndo(LPOLEINPLACESITE lpThis)
{
   OleDbgOut2("CntrLine_IPSite_DeactivateAndUndo\r\n");
   return NOERROR;
}


STDMETHODIMP CntrLine_IPSite_OnPosRectChange(
   LPOLEINPLACESITE    lpThis,
   LPCRECT             lprcPosRect
)
{
   LPCONTAINERLINE lpContainerLine =
         ((struct COleInPlaceSiteImpl FAR*)lpThis)->lpContainerLine;
   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc;
   LPSCALEFACTOR lpscale = OutlineDoc_GetScaleFactor(lpOutlineDoc);
   LPLINE lpLine = (LPLINE)lpContainerLine;
   LPLINELIST lpLL;
   int nIndex;
   RECT rcClipRect;
   RECT rcNewPosRect;
   SIZEL sizelPix;
   SIZEL sizelHim;
   int nIPObjHeight = lprcPosRect->bottom - lprcPosRect->top;
   int nIPObjWidth = lprcPosRect->right - lprcPosRect->left;

   // artificial AddRef in case object is destroyed during call
   CntrLine_IPSite_AddRef(lpThis);

   OLEDBG_BEGIN2("CntrLine_IPSite_OnPosRectChange\r\n")
   OleDbgOutRect3("CntrLine_IPSite_OnPosRectChange (PosRect --IN)", (LPRECT)lprcPosRect);

   /* OLE2NOTE: if the in-place container does NOT impose any
   **    size contraints on its in-place active objects, then it may
   **    simply grant the size requested by the object by immediately
   **    calling IOleInPlaceObject::SetObjectRects with the
   **    lprcPosRect passed by the in-place object.
   **
   **    Container Outline, however, imposes a size constraint on its
   **    embedded objects (see comment in ContainerLine_UpdateExtent),
   **    thus it is necessary to calculate the size that the in-place
   **    active object is allowed to be.
   **
   **    Here we need to know the new extents of the in-place object.
   **    We can NOT directly ask the object via IOleObject::GetExtent
   **    because this method will retreive the extents of the last
   **    cached metafile. the cache has not yet been updated by this
   **    point. We can not reliably call IOleObject::GetExtent
   **    because, despite the fact that will be delegated to the
   **    object properly, some objects may not have reformated their
   **    object and computed the new extents at the time of calling
   **    OnPosRectChange.
   **
   **    the best we can do to get the new extents of the object is
   **    to determine the scale factor that the object was operating at
   **    prior to the OnPosRect call and scale the new lprcPosRect
   **    using this scale factor back to HIMETRIC units.
   */
   if (lpContainerLine->m_sizeInHimetric.cx > 0 &&
      lpContainerLine->m_sizeInHimetric.cy > 0) {
      sizelHim.cx = lpLine->m_nWidthInHimetric;
      sizelHim.cy = lpLine->m_nHeightInHimetric;
      XformSizeInHimetricToPixels(NULL, &sizelHim, &sizelPix);
      sizelHim.cx = lpContainerLine->m_sizeInHimetric.cx *
               nIPObjWidth / sizelPix.cx;
      sizelHim.cy = lpContainerLine->m_sizeInHimetric.cy *
               nIPObjHeight / sizelPix.cy;

      // Convert size back to 100% zoom
      sizelHim.cx = sizelHim.cx * lpscale->dwSxD / lpscale->dwSxN;
      sizelHim.cy = sizelHim.cy * lpscale->dwSyD / lpscale->dwSyN;
   } else {
      sizelHim.cx = (long)DEFOBJWIDTH;
      sizelHim.cy = (long)DEFOBJHEIGHT;
      XformSizeInHimetricToPixels(NULL, &sizelHim, &sizelPix);
      sizelHim.cx = sizelHim.cx * nIPObjWidth / sizelPix.cx;
      sizelHim.cy = sizelHim.cy * nIPObjHeight / sizelPix.cy;
   }

   ContainerLine_UpdateExtent(lpContainerLine, &sizelHim);
   ContainerLine_GetPosRect(lpContainerLine, (LPRECT)&rcNewPosRect);
   ContainerDoc_GetClipRect(lpContainerLine->m_lpDoc, (LPRECT)&rcClipRect);

#if defined( _DEBUG )
   OleDbgOutRect3("CntrLine_IPSite_OnPosRectChange (PosRect --OUT)",
         (LPRECT)&rcNewPosRect);
   OleDbgOutRect3("CntrLine_IPSite_OnPosRectChange (ClipRect--OUT)",
         (LPRECT)&rcClipRect);
#endif
   OLEDBG_BEGIN2("IOleInPlaceObject::SetObjectRects called\r\n")
   lpContainerLine->m_lpOleIPObj->lpVtbl->SetObjectRects(
         lpContainerLine->m_lpOleIPObj,
         (LPRECT)&rcNewPosRect,
         (LPRECT)&rcClipRect
   );
   OLEDBG_END2

   /* OLE2NOTE: (INSIDEOUT CONTAINER) Because this object just changed
   **    size, this may cause other in-place active objects in the
   **    document to move. in ICNTROTL's case any object below this
   **    object would be affected. in this case it would be necessary
   **    to call SetObjectRects to each affected in-place active object.
   */
   if (g_fInsideOutContainer) {
      lpLL = OutlineDoc_GetLineList(lpOutlineDoc);
      nIndex = LineList_GetLineIndex(lpLL, (LPLINE)lpContainerLine);

      ContainerDoc_UpdateInPlaceObjectRects(
            lpContainerLine->m_lpDoc, nIndex);
   }
   OLEDBG_END2
   // release artificial AddRef
   CntrLine_IPSite_Release(lpThis);
   return NOERROR;
}
