1180 lines
37 KiB
C
1180 lines
37 KiB
C
/*************************************************************************
|
||
**
|
||
** OLE 2 Server Sample Code
|
||
**
|
||
** oledoc.c
|
||
**
|
||
** This file contains general OleDoc methods and related support
|
||
** functions. OleDoc implementation is used by both the Container
|
||
** versions and the Server (Object) versions of the Outline Sample.
|
||
**
|
||
** This file includes general support for the following:
|
||
** 1. show/hide doc window
|
||
** 2. QueryInterface, AddRef, Release
|
||
** 3. document locking (calls CoLockObjectExternal)
|
||
** 4. document shutdown (Close, Destroy)
|
||
** 5. clipboard support
|
||
**
|
||
** OleDoc Object
|
||
** exposed interfaces:
|
||
** IUnknown
|
||
** IPersistFile
|
||
** IOleItemContainer
|
||
** IDataObject
|
||
**
|
||
** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved
|
||
**
|
||
*************************************************************************/
|
||
|
||
|
||
#include "outline.h"
|
||
|
||
OLEDBGDATA
|
||
|
||
extern LPOUTLINEAPP g_lpApp;
|
||
|
||
extern IUnknownVtbl g_OleDoc_UnknownVtbl;
|
||
extern IPersistFileVtbl g_OleDoc_PersistFileVtbl;
|
||
extern IOleItemContainerVtbl g_OleDoc_OleItemContainerVtbl;
|
||
extern IExternalConnectionVtbl g_OleDoc_ExternalConnectionVtbl;
|
||
extern IDataObjectVtbl g_OleDoc_DataObjectVtbl;
|
||
|
||
#if defined( USE_DRAGDROP )
|
||
extern IDropTargetVtbl g_OleDoc_DropTargetVtbl;
|
||
extern IDropSourceVtbl g_OleDoc_DropSourceVtbl;
|
||
#endif // USE_DRAGDROP
|
||
|
||
#if defined( INPLACE_CNTR )
|
||
extern BOOL g_fInsideOutContainer;
|
||
#endif
|
||
|
||
|
||
/* OleDoc_Init
|
||
* -----------
|
||
*
|
||
* Initialize the fields of a new OleDoc object. The object is initially
|
||
* not associated with a file or an (Untitled) document. This function sets
|
||
* the docInitType to DOCTYPE_UNKNOWN. After calling this function the
|
||
* caller should call:
|
||
* 1.) Doc_InitNewFile to set the OleDoc to (Untitled)
|
||
* 2.) Doc_LoadFromFile to associate the OleDoc with a file.
|
||
* This function creates a new window for the document.
|
||
*
|
||
* NOTE: the window is initially created with a NIL size. it must be
|
||
* sized and positioned by the caller. also the document is initially
|
||
* created invisible. the caller must call OutlineDoc_ShowWindow
|
||
* after sizing it to make the document window visible.
|
||
*/
|
||
BOOL OleDoc_Init(LPOLEDOC lpOleDoc, BOOL fDataTransferDoc)
|
||
{
|
||
LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;
|
||
LPLINELIST lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList;
|
||
|
||
lpOleDoc->m_cRef = 0;
|
||
lpOleDoc->m_dwStrongExtConn = 0;
|
||
#if defined( _DEBUG )
|
||
lpOleDoc->m_cCntrLock = 0;
|
||
#endif
|
||
lpOleDoc->m_lpStg = NULL;
|
||
lpOleDoc->m_lpLLStm = NULL;
|
||
lpOleDoc->m_lpNTStm = NULL;
|
||
lpOleDoc->m_dwRegROT = 0;
|
||
lpOleDoc->m_lpFileMoniker = NULL;
|
||
lpOleDoc->m_fLinkSourceAvail = FALSE;
|
||
lpOleDoc->m_lpSrcDocOfCopy = NULL;
|
||
lpOleDoc->m_fObjIsClosing = FALSE;
|
||
lpOleDoc->m_fObjIsDestroying = FALSE;
|
||
lpOleDoc->m_fUpdateEditMenu = FALSE;
|
||
|
||
#if defined( USE_DRAGDROP )
|
||
lpOleDoc->m_dwTimeEnterScrollArea = 0L;
|
||
lpOleDoc->m_dwNextScrollTime = 0L;
|
||
lpOleDoc->m_dwLastScrollDir = SCROLLDIR_NULL;
|
||
lpOleDoc->m_fRegDragDrop = FALSE;
|
||
lpOleDoc->m_fLocalDrag = FALSE;
|
||
lpOleDoc->m_fCanDropCopy = FALSE;
|
||
lpOleDoc->m_fCanDropLink = FALSE;
|
||
lpOleDoc->m_fLocalDrop = FALSE;
|
||
lpOleDoc->m_fDragLeave = FALSE;
|
||
lpOleDoc->m_fPendingDrag = FALSE;
|
||
#endif
|
||
#if defined( INPLACE_SVR ) || defined( INPLACE_CNTR )
|
||
lpOleDoc->m_fCSHelpMode = FALSE; // Shift-F1 context
|
||
// sensitive help mode
|
||
#endif
|
||
|
||
INIT_INTERFACEIMPL(
|
||
&lpOleDoc->m_Unknown,
|
||
&g_OleDoc_UnknownVtbl,
|
||
lpOleDoc
|
||
);
|
||
|
||
INIT_INTERFACEIMPL(
|
||
&lpOleDoc->m_PersistFile,
|
||
&g_OleDoc_PersistFileVtbl,
|
||
lpOleDoc
|
||
);
|
||
|
||
INIT_INTERFACEIMPL(
|
||
&lpOleDoc->m_OleItemContainer,
|
||
&g_OleDoc_OleItemContainerVtbl,
|
||
lpOleDoc
|
||
);
|
||
|
||
INIT_INTERFACEIMPL(
|
||
&lpOleDoc->m_ExternalConnection,
|
||
&g_OleDoc_ExternalConnectionVtbl,
|
||
lpOleDoc
|
||
);
|
||
|
||
INIT_INTERFACEIMPL(
|
||
&lpOleDoc->m_DataObject,
|
||
&g_OleDoc_DataObjectVtbl,
|
||
lpOleDoc
|
||
);
|
||
|
||
#if defined( USE_DRAGDROP )
|
||
INIT_INTERFACEIMPL(
|
||
&lpOleDoc->m_DropSource,
|
||
&g_OleDoc_DropSourceVtbl,
|
||
lpOleDoc
|
||
);
|
||
|
||
INIT_INTERFACEIMPL(
|
||
&lpOleDoc->m_DropTarget,
|
||
&g_OleDoc_DropTargetVtbl,
|
||
lpOleDoc
|
||
);
|
||
#endif // USE_DRAGDROP
|
||
|
||
/*
|
||
** OLE2NOTE: each user level document addref's the app object in
|
||
** order to guarentee that the app does not shut down while the
|
||
** doc is still open.
|
||
*/
|
||
|
||
// OLE2NOTE: data transfer documents should not hold the app alive
|
||
if (! fDataTransferDoc)
|
||
OleApp_DocLockApp(lpOleApp);
|
||
|
||
#if defined( OLE_SERVER )
|
||
/* OLE2NOTE: perform initialization specific for an OLE server */
|
||
if (! ServerDoc_Init((LPSERVERDOC)lpOleDoc, fDataTransferDoc))
|
||
return FALSE;
|
||
#endif
|
||
#if defined( OLE_CNTR )
|
||
|
||
/* OLE2NOTE: perform initialization specific for an OLE container */
|
||
if (! ContainerDoc_Init((LPCONTAINERDOC)lpOleDoc, fDataTransferDoc))
|
||
return FALSE;
|
||
#endif
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
|
||
/* OleDoc_InitNewFile
|
||
* ------------------
|
||
*
|
||
* Initialize the document to be a new (Untitled) document.
|
||
* This function sets the docInitType to DOCTYPE_NEW.
|
||
*
|
||
* OLE2NOTE: if this is a visible user document then generate a unique
|
||
* untitled name that we can use to register in the RunningObjectTable.
|
||
* We need a unique name so that clients can link to data in this document
|
||
* even when the document is in the un-saved (untitled) state. it would be
|
||
* ambiguous to register two documents titled "Outline1" in the ROT. we
|
||
* thus generate the lowest numbered document that is not already
|
||
* registered in the ROT.
|
||
*/
|
||
BOOL OleDoc_InitNewFile(LPOLEDOC lpOleDoc)
|
||
{
|
||
LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;
|
||
|
||
static UINT uUnique = 1;
|
||
|
||
OleDbgAssert(lpOutlineDoc->m_docInitType == DOCTYPE_UNKNOWN);
|
||
|
||
#if defined( OLE_CNTR )
|
||
{
|
||
LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOleDoc;
|
||
#if defined( _DEBUG )
|
||
OleDbgAssertSz(lpOleDoc->m_lpStg == NULL,
|
||
"Setting to untitled with current file open"
|
||
);
|
||
#endif
|
||
|
||
/* Create a temp, (delete-on-release) file base storage
|
||
** for the untitled document.
|
||
*/
|
||
lpOleDoc->m_lpStg = OleStdCreateRootStorage(
|
||
NULL,
|
||
STGM_SHARE_EXCLUSIVE
|
||
);
|
||
if (! lpOleDoc->m_lpStg) return FALSE;
|
||
}
|
||
#endif
|
||
|
||
lpOutlineDoc->m_docInitType = DOCTYPE_NEW;
|
||
|
||
if (! lpOutlineDoc->m_fDataTransferDoc) {
|
||
/* OLE2NOTE: choose a unique name for a Moniker so that
|
||
** potential clients can link to our new, untitled document.
|
||
** if links are established (and currently are connected),
|
||
** then they will be notified that we have been renamed when
|
||
** this document is saved to a file.
|
||
*/
|
||
|
||
lpOleDoc->m_fLinkSourceAvail = TRUE;
|
||
|
||
// REVIEW: should load UNTITLED string from string resource
|
||
OleStdCreateTempFileMoniker(
|
||
UNTITLED,
|
||
(UINT FAR*)&uUnique,
|
||
lpOutlineDoc->m_szFileName,
|
||
&lpOleDoc->m_lpFileMoniker
|
||
);
|
||
|
||
OLEDBG_BEGIN3("OleStdRegisterAsRunning called\r\n")
|
||
OleStdRegisterAsRunning(
|
||
(LPUNKNOWN)&lpOleDoc->m_PersistFile,
|
||
(LPMONIKER)lpOleDoc->m_lpFileMoniker,
|
||
&lpOleDoc->m_dwRegROT
|
||
);
|
||
OLEDBG_END3
|
||
|
||
lpOutlineDoc->m_lpszDocTitle = lpOutlineDoc->m_szFileName;
|
||
OutlineDoc_SetTitle(lpOutlineDoc, FALSE /*fMakeUpperCase*/);
|
||
} else {
|
||
lstrcpy(lpOutlineDoc->m_szFileName, UNTITLED);
|
||
lpOutlineDoc->m_lpszDocTitle = lpOutlineDoc->m_szFileName;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
/* OleDoc_ShowWindow
|
||
* -----------------
|
||
*
|
||
* Show the window of the document to the user.
|
||
* make sure app window is visible and bring the document to the top.
|
||
* if the document is a file-based document or a new untitled
|
||
* document, give the user the control over the life-time of the doc.
|
||
*/
|
||
void OleDoc_ShowWindow(LPOLEDOC lpOleDoc)
|
||
{
|
||
LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
|
||
LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;
|
||
LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;
|
||
LPLINELIST lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList;
|
||
#if defined( OLE_SERVER )
|
||
LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOleDoc;
|
||
#endif // OLE_SERVER
|
||
|
||
OLEDBG_BEGIN3("OleDoc_ShowWindow\r\n")
|
||
|
||
/* OLE2NOTE: while the document is visible, we do NOT want it to be
|
||
** prematurely destroyed when a linking client disconnects. thus
|
||
** we must inform OLE to hold an external lock on our document.
|
||
** this arranges that OLE holds at least 1 reference to our
|
||
** document that will NOT be released until we release this
|
||
** external lock. later, when the document window is hidden, we
|
||
** will release this external lock.
|
||
*/
|
||
if (! IsWindowVisible(lpOutlineDoc->m_hWndDoc))
|
||
OleDoc_Lock(lpOleDoc, TRUE /* fLock */, 0 /* not applicable */);
|
||
|
||
#if defined( USE_DRAGDROP )
|
||
/* OLE2NOTE: since our window is now being made visible, we will
|
||
** register our window as a potential drop target. when the
|
||
** window is hidden there is no reason to be registered as a
|
||
** drop target.
|
||
*/
|
||
if (! lpOleDoc->m_fRegDragDrop) {
|
||
OLEDBG_BEGIN2("RegisterDragDrop called\r\n")
|
||
RegisterDragDrop(
|
||
LineList_GetWindow(lpLL),
|
||
(LPDROPTARGET)&lpOleDoc->m_DropTarget
|
||
);
|
||
OLEDBG_END2
|
||
lpOleDoc->m_fRegDragDrop = TRUE;
|
||
}
|
||
#endif // USE_DRAGDROP
|
||
|
||
#if defined( USE_FRAMETOOLS )
|
||
{
|
||
/* OLE2NOTE: we need to enable our frame level tools
|
||
*/
|
||
FrameTools_Enable(lpOutlineDoc->m_lpFrameTools, TRUE);
|
||
}
|
||
#endif // USE_FRAMETOOLS
|
||
|
||
#if defined( OLE_SERVER )
|
||
|
||
if (lpOutlineDoc->m_docInitType == DOCTYPE_EMBEDDED &&
|
||
lpServerDoc->m_lpOleClientSite != NULL) {
|
||
|
||
/* OLE2NOTE: we must also ask our container to show itself if
|
||
** it is not already visible and to scroll us into view. we
|
||
** must make sure to call this BEFORE showing our server's
|
||
** window and taking focus. we do not want our container's
|
||
** window to end up on top.
|
||
*/
|
||
OLEDBG_BEGIN2("IOleClientSite::ShowObject called\r\n");
|
||
lpServerDoc->m_lpOleClientSite->lpVtbl->ShowObject(
|
||
lpServerDoc->m_lpOleClientSite
|
||
);
|
||
OLEDBG_END2
|
||
|
||
/* OLE2NOTE: if we are an embedded object and we are not
|
||
** in-place active in our containers window, we must inform our
|
||
** embedding container that our window is opening.
|
||
** the container must now hatch our object.
|
||
*/
|
||
|
||
#if defined( INPLACE_SVR )
|
||
if (! lpServerDoc->m_fInPlaceActive)
|
||
#endif
|
||
{
|
||
OLEDBG_BEGIN2("IOleClientSite::OnShowWindow(TRUE) called\r\n");
|
||
lpServerDoc->m_lpOleClientSite->lpVtbl->OnShowWindow(
|
||
lpServerDoc->m_lpOleClientSite,
|
||
TRUE
|
||
);
|
||
OLEDBG_END2
|
||
}
|
||
|
||
/* OLE2NOTE: the life-time of our document is controlled by our
|
||
** client and NOT by the user. we are not an independent
|
||
** file-level object. we simply want to show our window here.
|
||
**
|
||
** if we are not in-place active (ie. we are opening
|
||
** our own window), we must make sure our main app window is
|
||
** visible. we do not, however, want to give the user
|
||
** control of the App window; we do not want OleApp_ShowWindow
|
||
** to call OleApp_Lock on behalf of the user.
|
||
*/
|
||
if (! IsWindowVisible(lpOutlineApp->m_hWndApp) ||
|
||
IsIconic(lpOutlineApp->m_hWndApp)) {
|
||
#if defined( INPLACE_SVR )
|
||
if (! ((LPSERVERDOC)lpOleDoc)->m_fInPlaceActive)
|
||
#endif
|
||
OleApp_ShowWindow(lpOleApp, FALSE /* fGiveUserCtrl */);
|
||
SetFocus(lpOutlineDoc->m_hWndDoc);
|
||
}
|
||
|
||
} else
|
||
#endif // OLE_SERVER
|
||
|
||
{ // DOCTYPE_NEW || DOCTYPE_FROMFILE
|
||
|
||
// we must make sure our app window is visible
|
||
OleApp_ShowWindow(lpOleApp, TRUE /* fGiveUserCtrl */);
|
||
}
|
||
|
||
// make document window visible and make sure it is not minimized
|
||
ShowWindow(lpOutlineDoc->m_hWndDoc, SW_SHOWNORMAL);
|
||
SetFocus(lpOutlineDoc->m_hWndDoc);
|
||
|
||
OLEDBG_END3
|
||
}
|
||
|
||
|
||
/* OleDoc_HideWindow
|
||
* -----------------
|
||
*
|
||
* Hide the window of the document from the user.
|
||
* take away the control of the document by the user.
|
||
*/
|
||
void OleDoc_HideWindow(LPOLEDOC lpOleDoc, BOOL fShutdown)
|
||
{
|
||
LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;
|
||
LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;
|
||
LPLINELIST lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList;
|
||
|
||
if (! IsWindowVisible(lpOutlineDoc->m_hWndDoc))
|
||
return; // already visible
|
||
|
||
OLEDBG_BEGIN3("OleDoc_HideWindow\r\n")
|
||
|
||
#if defined( USE_DRAGDROP )
|
||
// The document's window is being hidden, revoke it as a DropTarget
|
||
if (lpOleDoc->m_fRegDragDrop) {
|
||
OLEDBG_BEGIN2("RevokeDragDrop called\r\n");
|
||
RevokeDragDrop(LineList_GetWindow(lpLL));
|
||
OLEDBG_END2
|
||
|
||
lpOleDoc->m_fRegDragDrop = FALSE ;
|
||
}
|
||
#endif // USE_DRAGDROP
|
||
|
||
/* OLE2NOTE: the document is now being hidden, so we must release
|
||
** the external lock made when the document was made visible.
|
||
** if this is a shutdown situation (fShutdown==TRUE), then OLE
|
||
** is instructed to release our document. if this is that last
|
||
** external lock on our document, thus enabling our document to
|
||
** complete its shutdown operation. If This is not a shutdown
|
||
** situation (eg. in-place server hiding its window when
|
||
** UIDeactivating or IOleObject::DoVerb(OLEVERB_HIDE) is called),
|
||
** then OLE is told to NOT immediately release the document.
|
||
** this leaves the document in an unstable state where the next
|
||
** Lock/Unlock sequence will shut the document down (eg. a
|
||
** linking client connecting and disconnecting).
|
||
*/
|
||
if (IsWindowVisible(lpOutlineDoc->m_hWndDoc))
|
||
OleDoc_Lock(lpOleDoc, FALSE /* fLock */, fShutdown);
|
||
|
||
ShowWindow(((LPOUTLINEDOC)lpOleDoc)->m_hWndDoc, SW_HIDE);
|
||
|
||
#if defined( OLE_SERVER )
|
||
{
|
||
LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOleDoc;
|
||
|
||
/* OLE2NOTE: if we are an embedded object and we are not
|
||
** in-place active, we must inform our
|
||
** embedding container that our window is hiding (closing
|
||
** from the user's perspective). the container must now
|
||
** un-hatch our object.
|
||
*/
|
||
if (lpServerDoc->m_lpOleClientSite != NULL
|
||
#if defined( INPLACE_SVR )
|
||
&& !lpServerDoc->m_fInPlaceVisible
|
||
#endif
|
||
) {
|
||
OLEDBG_BEGIN2("IOleClientSite::OnShowWindow(FALSE) called\r\n");
|
||
lpServerDoc->m_lpOleClientSite->lpVtbl->OnShowWindow(
|
||
lpServerDoc->m_lpOleClientSite,
|
||
FALSE
|
||
);
|
||
OLEDBG_END2
|
||
}
|
||
}
|
||
#endif
|
||
|
||
/* OLE2NOTE: if there are no more documents visible to the user.
|
||
** and the app itself is not under user control, then
|
||
** it has no reason to stay visible. we thus should hide the
|
||
** app. we can not directly destroy the app, because it may be
|
||
** validly being used programatically by another client
|
||
** application and should remain running. it should simply be
|
||
** hidded from the user.
|
||
*/
|
||
OleApp_HideIfNoReasonToStayVisible(lpOleApp);
|
||
OLEDBG_END3
|
||
}
|
||
|
||
|
||
/* OleDoc_Lock
|
||
** -----------
|
||
** Lock/Unlock the Doc object. if the last lock is unlocked and
|
||
** fLastUnlockReleases == TRUE, then the Doc object will shut down
|
||
** (ie. it will recieve its final release and its refcnt will go to 0).
|
||
*/
|
||
HRESULT OleDoc_Lock(LPOLEDOC lpOleDoc, BOOL fLock, BOOL fLastUnlockReleases)
|
||
{
|
||
HRESULT hrErr;
|
||
|
||
#if defined( _DEBUG )
|
||
if (fLock) {
|
||
OLEDBG_BEGIN2("CoLockObjectExternal(lpDoc,TRUE) called\r\n")
|
||
} else {
|
||
if (fLastUnlockReleases)
|
||
OLEDBG_BEGIN2("CoLockObjectExternal(lpDoc,FALSE,TRUE) called\r\n")
|
||
else
|
||
OLEDBG_BEGIN2("CoLockObjectExternal(lpDoc,FALSE,FALSE) called\r\n")
|
||
}
|
||
#endif // _DEBUG
|
||
|
||
hrErr = CoLockObjectExternal(
|
||
(LPUNKNOWN)&lpOleDoc->m_Unknown, fLock, fLastUnlockReleases);
|
||
|
||
OLEDBG_END2
|
||
return hrErr;
|
||
}
|
||
|
||
|
||
/* OleDoc_AddRef
|
||
** -------------
|
||
**
|
||
** increment the ref count of the document object.
|
||
**
|
||
** Returns the new ref count on the object
|
||
*/
|
||
ULONG OleDoc_AddRef(LPOLEDOC lpOleDoc)
|
||
{
|
||
++lpOleDoc->m_cRef;
|
||
|
||
#if defined( _DEBUG )
|
||
OleDbgOutRefCnt4(
|
||
"OleDoc_AddRef: cRef++\r\n",
|
||
lpOleDoc,
|
||
lpOleDoc->m_cRef
|
||
);
|
||
#endif
|
||
return lpOleDoc->m_cRef;
|
||
}
|
||
|
||
|
||
/* OleDoc_Release
|
||
** --------------
|
||
**
|
||
** decrement the ref count of the document object.
|
||
** if the ref count goes to 0, then the document is destroyed.
|
||
**
|
||
** Returns the remaining ref count on the object
|
||
*/
|
||
ULONG OleDoc_Release (LPOLEDOC lpOleDoc)
|
||
{
|
||
ULONG cRef;
|
||
LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
|
||
LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;
|
||
|
||
/*********************************************************************
|
||
** OLE2NOTE: when the obj refcnt == 0, then destroy the object. **
|
||
** otherwise the object is still in use. **
|
||
*********************************************************************/
|
||
|
||
cRef = --lpOleDoc->m_cRef;
|
||
|
||
#if defined( _DEBUG )
|
||
OleDbgAssertSz (lpOleDoc->m_cRef >= 0, "Release called with cRef == 0");
|
||
|
||
OleDbgOutRefCnt4(
|
||
"OleDoc_Release: cRef--\r\n", lpOleDoc, cRef);
|
||
#endif
|
||
if (cRef == 0)
|
||
OutlineDoc_Destroy((LPOUTLINEDOC)lpOleDoc);
|
||
|
||
return cRef;
|
||
}
|
||
|
||
|
||
/* OleDoc_QueryInterface
|
||
** ---------------------
|
||
**
|
||
** Retrieve a pointer to an interface on the document object.
|
||
**
|
||
** OLE2NOTE: this function will AddRef the ref cnt of the object.
|
||
**
|
||
** Returns S_OK if interface is successfully retrieved.
|
||
** E_NOINTERFACE if the interface is not supported
|
||
*/
|
||
HRESULT OleDoc_QueryInterface(
|
||
LPOLEDOC lpOleDoc,
|
||
REFIID riid,
|
||
LPVOID FAR* lplpvObj
|
||
)
|
||
{
|
||
LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;
|
||
SCODE sc = E_NOINTERFACE;
|
||
|
||
/* OLE2NOTE: we must make sure to set all out ptr parameters to NULL. */
|
||
*lplpvObj = NULL;
|
||
|
||
if (IsEqualIID(riid, &IID_IUnknown)) {
|
||
OleDbgOut4("OleDoc_QueryInterface: IUnknown* RETURNED\r\n");
|
||
|
||
*lplpvObj = (LPVOID) &lpOleDoc->m_Unknown;
|
||
OleDoc_AddRef(lpOleDoc);
|
||
sc = S_OK;
|
||
}
|
||
else if(lpOutlineDoc->m_fDataTransferDoc
|
||
&& IsEqualIID(riid, &IID_IDataObject)) {
|
||
OleDbgOut4("OleDoc_QueryInterface: IDataObject* RETURNED\r\n");
|
||
|
||
*lplpvObj = (LPVOID) &lpOleDoc->m_DataObject;
|
||
OleDoc_AddRef(lpOleDoc);
|
||
sc = S_OK;
|
||
}
|
||
|
||
/* OLE2NOTE: if this document is a DataTransferDocument used to
|
||
** support a clipboard or drag/drop operation, then it should
|
||
** only expose IUnknown, IDataObject, and IDropSource
|
||
** interfaces. if the document is a normal user document, then
|
||
** we will also continue to consider our other interfaces.
|
||
*/
|
||
if (lpOutlineDoc->m_fDataTransferDoc)
|
||
goto done;
|
||
|
||
if(IsEqualIID(riid,&IID_IPersist) || IsEqualIID(riid,&IID_IPersistFile)) {
|
||
OleDbgOut4("OleDoc_QueryInterface: IPersistFile* RETURNED\r\n");
|
||
|
||
*lplpvObj = (LPVOID) &lpOleDoc->m_PersistFile;
|
||
OleDoc_AddRef(lpOleDoc);
|
||
sc = S_OK;
|
||
}
|
||
else if(IsEqualIID(riid, &IID_IOleItemContainer) ||
|
||
IsEqualIID(riid, &IID_IOleContainer) ||
|
||
IsEqualIID(riid, &IID_IParseDisplayName) ) {
|
||
OleDbgOut4("OleDoc_QueryInterface: IOleItemContainer* RETURNED\r\n");
|
||
|
||
*lplpvObj = (LPVOID) &lpOleDoc->m_OleItemContainer;
|
||
OleDoc_AddRef(lpOleDoc);
|
||
sc = S_OK;
|
||
}
|
||
else if(IsEqualIID(riid, &IID_IExternalConnection)) {
|
||
OleDbgOut4("OleDoc_QueryInterface: IExternalConnection* RETURNED\r\n");
|
||
|
||
*lplpvObj = (LPVOID) &lpOleDoc->m_ExternalConnection;
|
||
OleDoc_AddRef(lpOleDoc);
|
||
sc = S_OK;
|
||
}
|
||
|
||
#if defined( USE_DRAGDROP )
|
||
else if(IsEqualIID(riid, &IID_IDropTarget)) {
|
||
OleDbgOut4("OleDoc_QueryInterface: IDropTarget* RETURNED\r\n");
|
||
|
||
*lplpvObj = (LPVOID) &lpOleDoc->m_DropTarget;
|
||
OleDoc_AddRef(lpOleDoc);
|
||
sc = S_OK;
|
||
}
|
||
else if(IsEqualIID(riid, &IID_IDropSource)) {
|
||
OleDbgOut4("OleDoc_QueryInterface: IDropSource* RETURNED\r\n");
|
||
|
||
*lplpvObj = (LPVOID) &lpOleDoc->m_DropSource;
|
||
OleDoc_AddRef(lpOleDoc);
|
||
sc = S_OK;
|
||
}
|
||
#endif
|
||
|
||
#if defined( OLE_CNTR )
|
||
else if (IsEqualIID(riid, &IID_IOleUILinkContainer)) {
|
||
OleDbgOut4("OleDoc_QueryInterface: IOleUILinkContainer* RETURNED\r\n");
|
||
|
||
*lplpvObj=(LPVOID)&((LPCONTAINERDOC)lpOleDoc)->m_OleUILinkContainer;
|
||
OleDoc_AddRef(lpOleDoc);
|
||
sc = S_OK;
|
||
}
|
||
#endif
|
||
|
||
#if defined( OLE_SERVER )
|
||
|
||
/* OLE2NOTE: if OLE server version, than also offer the server
|
||
** specific interfaces: IOleObject and IPersistStorage.
|
||
*/
|
||
else if (IsEqualIID(riid, &IID_IOleObject)) {
|
||
OleDbgOut4("OleDoc_QueryInterface: IOleObject* RETURNED\r\n");
|
||
|
||
*lplpvObj = (LPVOID) &((LPSERVERDOC)lpOleDoc)->m_OleObject;
|
||
OleDoc_AddRef(lpOleDoc);
|
||
sc = S_OK;
|
||
}
|
||
else if(IsEqualIID(riid, &IID_IPersistStorage)) {
|
||
OleDbgOut4("OleDoc_QueryInterface: IPersistStorage* RETURNED\r\n");
|
||
|
||
*lplpvObj = (LPVOID) &((LPSERVERDOC)lpOleDoc)->m_PersistStorage;
|
||
OleDoc_AddRef(lpOleDoc);
|
||
sc = S_OK;
|
||
}
|
||
else if(IsEqualIID(riid, &IID_IDataObject)) {
|
||
OleDbgOut4("OleDoc_QueryInterface: IDataObject* RETURNED\r\n");
|
||
|
||
*lplpvObj = (LPVOID) &lpOleDoc->m_DataObject;
|
||
OleDoc_AddRef(lpOleDoc);
|
||
sc = S_OK;
|
||
}
|
||
|
||
#if defined( SVR_TREATAS )
|
||
else if(IsEqualIID(riid, &IID_IStdMarshalInfo)) {
|
||
OleDbgOut4("OleDoc_QueryInterface: IStdMarshalInfo* RETURNED\r\n");
|
||
|
||
*lplpvObj = (LPVOID) &((LPSERVERDOC)lpOleDoc)->m_StdMarshalInfo;
|
||
OleDoc_AddRef(lpOleDoc);
|
||
sc = S_OK;
|
||
}
|
||
#endif // SVR_TREATAS
|
||
|
||
#if defined( INPLACE_SVR )
|
||
else if (IsEqualIID(riid, &IID_IOleWindow) ||
|
||
IsEqualIID(riid, &IID_IOleInPlaceObject)) {
|
||
OleDbgOut4("OleDoc_QueryInterface: IOleInPlaceObject* RETURNED\r\n");
|
||
|
||
*lplpvObj = (LPVOID) &((LPSERVERDOC)lpOleDoc)->m_OleInPlaceObject;
|
||
OleDoc_AddRef(lpOleDoc);
|
||
sc = S_OK;
|
||
}
|
||
#endif // INPLACE_SVR
|
||
#endif // OLE_SERVER
|
||
|
||
done:
|
||
OleDbgQueryInterfaceMethod(*lplpvObj);
|
||
|
||
return ResultFromScode(sc);
|
||
}
|
||
|
||
|
||
/* OleDoc_Close
|
||
* ------------
|
||
*
|
||
* Close the document.
|
||
* This functions performs the actions that are in common to all
|
||
* document types which derive from OleDoc (eg. ContainerDoc and
|
||
* ServerDoc) which are required to close a document.
|
||
*
|
||
* Returns:
|
||
* FALSE -- user canceled the closing of the doc.
|
||
* TRUE -- the doc was successfully closed
|
||
*/
|
||
|
||
BOOL OleDoc_Close(LPOLEDOC lpOleDoc, DWORD dwSaveOption)
|
||
{
|
||
LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;
|
||
LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
|
||
LPOLEDOC lpClipboardDoc;
|
||
LPLINELIST lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList;
|
||
BOOL fAbortIfSaveCanceled = (dwSaveOption == OLECLOSE_PROMPTSAVE);
|
||
|
||
if (! lpOleDoc)
|
||
return TRUE; // active doc's are already destroyed
|
||
|
||
if (lpOleDoc->m_fObjIsClosing)
|
||
return TRUE; // Closing is already in progress
|
||
|
||
OLEDBG_BEGIN3("OleDoc_Close\r\n")
|
||
|
||
if (! OutlineDoc_CheckSaveChanges((LPOUTLINEDOC)lpOleDoc,&dwSaveOption)
|
||
&& fAbortIfSaveCanceled) {
|
||
OLEDBG_END3
|
||
return FALSE; // cancel closing the doc
|
||
}
|
||
|
||
lpOleDoc->m_fObjIsClosing = TRUE; // guard against recursive call
|
||
|
||
/* OLE2NOTE: in order to have a stable app and doc during the
|
||
** process of closing, we intially AddRef the App and Doc ref
|
||
** cnts and later Release them. These initial AddRefs are
|
||
** artificial; they simply guarantee that these objects do not
|
||
** get destroyed until the end of this routine.
|
||
*/
|
||
OleApp_AddRef(lpOleApp);
|
||
OleDoc_AddRef(lpOleDoc);
|
||
|
||
#if defined( OLE_CNTR )
|
||
{
|
||
LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOleDoc;
|
||
|
||
/* OLE2NOTE: force all OLE objects to close. this forces all
|
||
** OLE object to transition from running to loaded. we can
|
||
** NOT exit if any embeddings are still running.
|
||
** if an object can't be closed and this close operation was
|
||
** started by the user, then we will abort closing our document.
|
||
*/
|
||
if (! ContainerDoc_CloseAllOleObjects(lpContainerDoc, OLECLOSE_NOSAVE)
|
||
&& fAbortIfSaveCanceled) {
|
||
OleDoc_Release(lpOleDoc); // release artificial AddRef above
|
||
OleApp_Release(lpOleApp); // release artificial AddRef above
|
||
lpOleDoc->m_fObjIsClosing = FALSE; // clear recursion guard
|
||
|
||
OLEDBG_END3
|
||
return FALSE; // Closing is aborted
|
||
}
|
||
}
|
||
#endif
|
||
|
||
#if defined( INPLACE_SVR )
|
||
/* OLE2NOTE: if the server is currently in-place active we must
|
||
** deactivate it now before closing
|
||
*/
|
||
ServerDoc_DoInPlaceDeactivate((LPSERVERDOC)lpOleDoc);
|
||
#endif
|
||
|
||
/* OLE2NOTE: if this document is the source of data for the
|
||
** clipboard, then flush the clipboard. it is important to flush
|
||
** the clipboard BEFORE calling sending any notifications to
|
||
** clients (eg. IOleClientSite::OnShowWindow(FALSE)) which could
|
||
** give them a chance to run and try to get our clipboard data
|
||
** object that we want to destroy. (eg. our app tries to
|
||
** update the paste button of the toolbar when
|
||
** WM_ACTIVATEAPP is received.)
|
||
*/
|
||
lpClipboardDoc = (LPOLEDOC)lpOutlineApp->m_lpClipboardDoc;
|
||
if (lpClipboardDoc &&
|
||
lpClipboardDoc->m_lpSrcDocOfCopy == lpOleDoc) {
|
||
OleApp_FlushClipboard(lpOleApp);
|
||
}
|
||
|
||
/* OLE2NOTE: Revoke the object from the Running Object Table. it is
|
||
** best if the object is revoke prior to calling
|
||
** COLockObjectExternal(FALSE,TRUE) which is called when the
|
||
** document window is hidden from the user.
|
||
*/
|
||
OLEDBG_BEGIN3("OleStdRevokeAsRunning called\r\n")
|
||
OleStdRevokeAsRunning(&lpOleDoc->m_dwRegROT);
|
||
OLEDBG_END3
|
||
|
||
/* OLE2NOTE: if the user is in control of the document, the user
|
||
** accounts for one refcnt on the document. Closing the
|
||
** document is achieved by releasing the object on behalf of
|
||
** the user. if the document is not referenced by any other
|
||
** clients, then the document will also be destroyed. if it
|
||
** is referenced by other clients, then it will remain until
|
||
** they release it. it is important to hide the window and call
|
||
** IOleClientSite::OnShowWindow(FALSE) BEFORE sending OnClose
|
||
** notification.
|
||
*/
|
||
OleDoc_HideWindow(lpOleDoc, TRUE);
|
||
|
||
#if defined( OLE_SERVER )
|
||
{
|
||
LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOleDoc;
|
||
LPSERVERNAMETABLE lpServerNameTable =
|
||
(LPSERVERNAMETABLE)((LPOUTLINEDOC)lpOleDoc)->m_lpNameTable;
|
||
|
||
/* OLE2NOTE: force all pseudo objects to close. this informs all
|
||
** linking clients of pseudo objects to release their PseudoObj.
|
||
*/
|
||
ServerNameTable_CloseAllPseudoObjs(lpServerNameTable);
|
||
|
||
/* OLE2NOTE: send last OnDataChange notification to clients
|
||
** that have registered for data notifications when object
|
||
** stops running (ADVF_DATAONSTOP), if the data in our
|
||
** object has ever changed. it is best to only send this
|
||
** notification if necessary.
|
||
*/
|
||
if (lpServerDoc->m_lpDataAdviseHldr) {
|
||
if (lpServerDoc->m_fSendDataOnStop) {
|
||
ServerDoc_SendAdvise(
|
||
(LPSERVERDOC)lpOleDoc,
|
||
OLE_ONDATACHANGE,
|
||
NULL, /* lpmkDoc -- not relevant here */
|
||
ADVF_DATAONSTOP
|
||
);
|
||
}
|
||
/* OLE2NOTE: we just sent the last data notification that we
|
||
** need to send; release our DataAdviseHolder. we SHOULD be
|
||
** the only one using it.
|
||
*/
|
||
|
||
OleStdVerifyRelease(
|
||
(LPUNKNOWN)lpServerDoc->m_lpDataAdviseHldr,
|
||
"DataAdviseHldr not released properly"
|
||
);
|
||
lpServerDoc->m_lpDataAdviseHldr = NULL;
|
||
}
|
||
|
||
// OLE2NOTE: inform all of our linking clients that we are closing.
|
||
|
||
|
||
if (lpServerDoc->m_lpOleAdviseHldr) {
|
||
ServerDoc_SendAdvise(
|
||
(LPSERVERDOC)lpOleDoc,
|
||
OLE_ONCLOSE,
|
||
NULL, /* lpmkDoc -- not relevant here */
|
||
0 /* advf -- not relevant here */
|
||
);
|
||
|
||
/* OLE2NOTE: OnClose is the last notification that we need to
|
||
** send; release our OleAdviseHolder. we SHOULD be the only
|
||
** one using it. this will make our destructor realize that
|
||
** OnClose notification has already been sent.
|
||
*/
|
||
OleStdVerifyRelease(
|
||
(LPUNKNOWN)lpServerDoc->m_lpOleAdviseHldr,
|
||
"OleAdviseHldr not released properly"
|
||
);
|
||
lpServerDoc->m_lpOleAdviseHldr = NULL;
|
||
}
|
||
|
||
/* release our Container's ClientSite. */
|
||
if(lpServerDoc->m_lpOleClientSite) {
|
||
OleStdRelease((LPUNKNOWN)lpServerDoc->m_lpOleClientSite);
|
||
lpServerDoc->m_lpOleClientSite = NULL;
|
||
}
|
||
}
|
||
#endif
|
||
|
||
if (lpOleDoc->m_lpLLStm) {
|
||
/* release our LineList stream. */
|
||
OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpLLStm);
|
||
lpOleDoc->m_lpLLStm = NULL;
|
||
}
|
||
|
||
if (lpOleDoc->m_lpNTStm) {
|
||
/* release our NameTable stream. */
|
||
OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpNTStm);
|
||
lpOleDoc->m_lpNTStm = NULL;
|
||
}
|
||
|
||
if (lpOleDoc->m_lpStg) {
|
||
/* release our doc storage. */
|
||
OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpStg);
|
||
lpOleDoc->m_lpStg = NULL;
|
||
}
|
||
|
||
if (lpOleDoc->m_lpFileMoniker) {
|
||
OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpFileMoniker);
|
||
lpOleDoc->m_lpFileMoniker = NULL;
|
||
}
|
||
|
||
/* OLE2NOTE: this call forces all external connections to our
|
||
** object to close down and therefore guarantees that we receive
|
||
** all releases associated with those external connections.
|
||
*/
|
||
OLEDBG_BEGIN2("CoDisconnectObject(lpDoc) called\r\n")
|
||
CoDisconnectObject((LPUNKNOWN)&lpOleDoc->m_Unknown, 0);
|
||
OLEDBG_END2
|
||
|
||
OleDoc_Release(lpOleDoc); // release artificial AddRef above
|
||
OleApp_Release(lpOleApp); // release artificial AddRef above
|
||
|
||
OLEDBG_END3
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
/* OleDoc_Destroy
|
||
* --------------
|
||
*
|
||
* Free all OLE related resources that had been allocated for a document.
|
||
*/
|
||
void OleDoc_Destroy(LPOLEDOC lpOleDoc)
|
||
{
|
||
LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
|
||
LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;
|
||
|
||
if (lpOleDoc->m_fObjIsDestroying)
|
||
return; // Doc destruction is already in progress
|
||
|
||
lpOleDoc->m_fObjIsDestroying = TRUE; // guard against recursive call
|
||
|
||
#if defined( OLE_SERVER )
|
||
|
||
/* OLE2NOTE: it is ALWAYS necessary to make sure that the work we
|
||
** do in our OleDoc_Close function is performed before we
|
||
** destroy our document object. this includes revoking from the
|
||
** Running Object Table (ROT), sending OnClose notification,
|
||
** revoking from Drag/Drop, closing all pseudo objects, etc.
|
||
** There are some tricky scenarios involving linking and
|
||
** when IOleObject::Close is called versus when we get our
|
||
** final release causing us to call our OleDoc_Destroy
|
||
** (destructor) function.
|
||
**
|
||
** SCENARIO 1 -- closing from server (File.Exit or File.Close)
|
||
** OleDoc_Close function is called directly by the
|
||
** server in response to the menu command
|
||
** (WM_COMMAND processing).
|
||
**
|
||
** SCENARIO 2 -- closed by embedding container
|
||
** our embedding container calls IOleObject::Close
|
||
** directly.
|
||
**
|
||
** SCENARIO 3 -- silent-update final release
|
||
** THIS IS THE TRICKY ONE!!!
|
||
** in the case that our object is launched because
|
||
** a linking client calls IOleObject::Update on
|
||
** its link, then our object will be run
|
||
** invisibly, typically GetData will be called,
|
||
** and then the connection from the linking client
|
||
** will be released. the release of this last
|
||
** linking connection should cause our object to
|
||
** shut down.
|
||
** there are 2 strategies to deal with this scenario:
|
||
**
|
||
** STRATEGY 1 -- implement IExternalConnection.
|
||
** IExternalConnection::AddConnection will be
|
||
** called (by the StubManager) every time that an
|
||
** external (linking) connection is created or
|
||
** CoLockObjectExternal is called. the object
|
||
** should maintain a count of strong connections
|
||
** (m_dwStrongExtConn). IExternalConnection::
|
||
** ReleaseConnection will be called when these
|
||
** connections are released. when the
|
||
** m_dwStrongExtConn transistions to 0, the object
|
||
** should call its IOleObject::Close function.
|
||
** this assumes that CoLockObjectExternal is used
|
||
** to manage locks by the object itself (eg. when
|
||
** the object is visible to the user--fUserCtrl,
|
||
** and when PseudoObjects are created, etc.)
|
||
** this is the strategy implemented by SVROUTL.
|
||
**
|
||
** STRATEGY 2 -- guard both the destructor
|
||
** function and the Close function. if the
|
||
** destructor is called directly without Close
|
||
** first being called, then call Close before
|
||
** proceeding with the destruction code.
|
||
** previously SVROUTL was organized in this
|
||
** manner. that old code is conditionaly compiled
|
||
** away with "#ifdef OBSOLETE" below. this
|
||
** method has the disadvantage that external
|
||
** remoting is no longer possible by the time the
|
||
** Close is called making it impossible for
|
||
** the object to ask its container to save the
|
||
** object if the object is dirty. this can result
|
||
** in data loss. thus STRATEGY 1 is safer.
|
||
** consider the scenario where an in-place
|
||
** container UIDeactivates an object but does NOT
|
||
** keep the object locked running (this is
|
||
** required--see CntrLine_IPSite_OnInPlaceActivate
|
||
** in cntrline.c), then, if a linking client binds
|
||
** and unbinds from the object, the object will be
|
||
** destroyed and will NOT have an opportunity to
|
||
** be saved. by implementing IExternalConnection,
|
||
** a server can insulate itself from a poorly
|
||
** written container.
|
||
*/
|
||
#if defined( _DEBUG )
|
||
|
||
#ifndef WIN32
|
||
// this is not a valid assert in Ole32; if file moniker binding
|
||
// fails, for example, we will only get releases coming in
|
||
// (no external connections are involved because OLE32 does a
|
||
// private rpc to the server (us) where the IPersistFile::Load is
|
||
// done.
|
||
|
||
OleDbgAssertSz(
|
||
(lpOutlineDoc->m_fDataTransferDoc || lpOleDoc->m_fObjIsClosing),
|
||
"Destroy called without Close being called\r\n"
|
||
);
|
||
#endif //!WIN32
|
||
|
||
#endif // _DEBUG
|
||
#if defined( OBSOLETE )
|
||
/* OLE2NOTE: if the document destructor is called directly because
|
||
** the object's refcnt went to 0 (ie. without OleDoc_Close first
|
||
** being called), then we need to make sure that the document is
|
||
** properly closed before destroying the object. this scenario
|
||
** could arise during a silent-update of a link. calling
|
||
** OleDoc_Close here guarantees that the clipboard will be
|
||
** properly flushed, the doc's moniker will be properly revoked,
|
||
** the document will be saved if necessary, etc.
|
||
*/
|
||
if (!lpOutlineDoc->m_fDataTransferDoc && !lpOleDoc->m_fObjIsClosing)
|
||
OleDoc_Close(lpOleDoc, OLECLOSE_NOSAVE);
|
||
#endif
|
||
|
||
{
|
||
LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOleDoc;
|
||
/* OLE2NOTE: perform processing specific for an OLE server */
|
||
|
||
#if defined( SVR_TREATAS )
|
||
if (lpServerDoc->m_lpszTreatAsType) {
|
||
OleStdFreeString(lpServerDoc->m_lpszTreatAsType, NULL);
|
||
lpServerDoc->m_lpszTreatAsType = NULL;
|
||
}
|
||
#endif // SVR_TREATAS
|
||
|
||
#if defined( INPLACE_SVR )
|
||
if (IsWindow(lpServerDoc->m_hWndHatch))
|
||
DestroyWindow(lpServerDoc->m_hWndHatch);
|
||
#endif // INPLACE_SVR
|
||
}
|
||
#endif // OLE_SERVER
|
||
|
||
if (lpOleDoc->m_lpLLStm) {
|
||
/* release our LineList stream. */
|
||
OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpLLStm);
|
||
lpOleDoc->m_lpLLStm = NULL;
|
||
}
|
||
|
||
if (lpOleDoc->m_lpNTStm) {
|
||
/* release our NameTable stream. */
|
||
OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpNTStm);
|
||
lpOleDoc->m_lpNTStm = NULL;
|
||
}
|
||
|
||
if (lpOleDoc->m_lpStg) {
|
||
/* release our doc storage. */
|
||
OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpStg);
|
||
lpOleDoc->m_lpStg = NULL;
|
||
}
|
||
|
||
if (lpOleDoc->m_lpFileMoniker) {
|
||
OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpFileMoniker);
|
||
lpOleDoc->m_lpFileMoniker = NULL;
|
||
}
|
||
|
||
/*****************************************************************
|
||
** OLE2NOTE: each document addref's the app object in order to **
|
||
** guarentee that the app does not shut down while the doc **
|
||
** is still open. since this doc is now destroyed, we will **
|
||
** release this refcnt now. if there are now more open **
|
||
** documents AND the app is not under the control of the **
|
||
** user (ie. launched by OLE) then the app will revoke its **
|
||
** ClassFactory. if there are no more references to the **
|
||
** ClassFactory after it is revoked, then the app will shut **
|
||
** down. this whole procedure is triggered by calling **
|
||
** OutlineApp_DocUnlockApp. **
|
||
*****************************************************************/
|
||
|
||
OutlineApp_DocUnlockApp(lpOutlineApp, lpOutlineDoc);
|
||
}
|
||
|
||
|
||
/* OleDoc_SetUpdateEditMenuFlag
|
||
* ----------------------------
|
||
*
|
||
* Purpose:
|
||
* Set/clear the UpdateEditMenuFlag in OleDoc.
|
||
*
|
||
* Parameters:
|
||
* fUpdate new value of the flag
|
||
*
|
||
* Returns:
|
||
*/
|
||
void OleDoc_SetUpdateEditMenuFlag(LPOLEDOC lpOleDoc, BOOL fUpdate)
|
||
{
|
||
if (!lpOleDoc)
|
||
return;
|
||
|
||
lpOleDoc->m_fUpdateEditMenu = fUpdate;
|
||
}
|
||
|
||
|
||
/* OleDoc_GetUpdateEditMenuFlag
|
||
* ----------------------------
|
||
*
|
||
* Purpose:
|
||
* Get the value of the UpdateEditMenuFlag in OleDoc
|
||
*
|
||
* Parameters:
|
||
*
|
||
* Returns:
|
||
* value of the flag
|
||
*/
|
||
BOOL OleDoc_GetUpdateEditMenuFlag(LPOLEDOC lpOleDoc)
|
||
{
|
||
if (!lpOleDoc)
|
||
return FALSE;
|
||
|
||
return lpOleDoc->m_fUpdateEditMenu;
|
||
}
|
||
|
||
|
||
|
||
/*************************************************************************
|
||
** OleDoc::IUnknown interface implementation
|
||
*************************************************************************/
|
||
|
||
STDMETHODIMP OleDoc_Unk_QueryInterface(
|
||
LPUNKNOWN lpThis,
|
||
REFIID riid,
|
||
LPVOID FAR* lplpvObj
|
||
)
|
||
{
|
||
LPOLEDOC lpOleDoc = ((struct CDocUnknownImpl FAR*)lpThis)->lpOleDoc;
|
||
|
||
return OleDoc_QueryInterface(lpOleDoc, riid, lplpvObj);
|
||
}
|
||
|
||
|
||
STDMETHODIMP_(ULONG) OleDoc_Unk_AddRef(LPUNKNOWN lpThis)
|
||
{
|
||
LPOLEDOC lpOleDoc = ((struct CDocUnknownImpl FAR*)lpThis)->lpOleDoc;
|
||
|
||
OleDbgAddRefMethod(lpThis, "IUnknown");
|
||
|
||
return OleDoc_AddRef(lpOleDoc);
|
||
}
|
||
|
||
|
||
STDMETHODIMP_(ULONG) OleDoc_Unk_Release (LPUNKNOWN lpThis)
|
||
{
|
||
LPOLEDOC lpOleDoc = ((struct CDocUnknownImpl FAR*)lpThis)->lpOleDoc;
|
||
|
||
OleDbgReleaseMethod(lpThis, "IUnknown");
|
||
|
||
return OleDoc_Release(lpOleDoc);
|
||
}
|
||
|