1941 lines
61 KiB
C
1941 lines
61 KiB
C
/*************************************************************************
|
|
**
|
|
** 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_SetActiveObjectA(
|
|
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;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CntrApp_IPFrame_SetActiveObject(
|
|
LPOLEINPLACEFRAME lpThis,
|
|
LPOLEINPLACEACTIVEOBJECT lpActiveObject,
|
|
LPCOLESTR lpszObjName
|
|
)
|
|
{
|
|
CREATESTR(pstr, lpszObjName)
|
|
|
|
HRESULT hr = CntrApp_IPFrame_SetActiveObjectA(lpThis, lpActiveObject, pstr);
|
|
|
|
FREESTR(pstr)
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
// 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_SetStatusTextA(
|
|
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
|
|
}
|
|
|
|
|
|
STDMETHODIMP CntrApp_IPFrame_SetStatusText(
|
|
LPOLEINPLACEFRAME lpThis,
|
|
LPCOLESTR lpszStatusText
|
|
)
|
|
{
|
|
CREATESTR(pstr, lpszStatusText)
|
|
|
|
HRESULT hr = CntrApp_IPFrame_SetStatusTextA(lpThis, pstr);
|
|
|
|
FREESTR(pstr)
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
// 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;
|
|
}
|