/*************************************************************************
**
**    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;

	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;

	return NOERROR;
}


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

	OLEDBG_BEGIN2("CntrApp_IPFrame_GetBorder\r\n")

	OutlineApp_GetFrameRect(lpOutlineApp, lprectBorder);

	OLEDBG_END2
	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;
	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
			return ResultFromScode(E_FAIL);
		}
#endif  // _DEBUG

		OutlineApp_SetBorderSpace(
				(LPOUTLINEAPP) lpContainerApp,
				(LPBORDERWIDTHS)lpWidths
		);
	}
	OLEDBG_END2
	return NOERROR;
}


// IOleInPlaceFrame::SetActiveObject
STDMETHODIMP CntrApp_IPFrame_SetActiveObject(
	LPOLEINPLACEFRAME           lpThis,
	LPOLEINPLACEACTIVEOBJECT    lpActiveObject,
	LPCSTR                      lpszObjName
)
{
	LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp;
	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
	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,
	LPCSTR              lpszStatusText
)
{
#if defined( USE_STATUSBAR )
	LPOUTLINEAPP   lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
	static char 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.
	*/
	LSTRCPYN(szMessageHold, lpszStatusText, sizeof(szMessageHold));
	OutlineApp_SetStatusText(lpOutlineApp, (LPSTR)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);
		return;
	}
}



/* 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;

	OleDbgAssert(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;
	OleDbgOut2("CntrLine_IPSite_GetWindow\r\n");

	*lphwnd = LineList_GetWindow(
			&((LPOUTLINEDOC)lpContainerLine->m_lpDoc)->m_LineList);
	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;
	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*/);

	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;

	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
		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
	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;

	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
			return NOERROR;
		}
	}

	lpContainerDoc->m_hWndUIActiveObj = lpContainerLine->m_hWndIpObject;

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

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

	OLEDBG_END2
	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;

	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
	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;
	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
	return NOERROR;
}


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

	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
	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;
	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
	return NOERROR;
}
