OLEDOC.C
资源名称:MSDN_VC98.zip [点击查看]
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:40k
源码类别:
Windows编程
开发平台:
Visual 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 - 1996 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
- /*
- ** NOTE: 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.
- */
- // NOTE: data transfer documents should not hold the app alive
- if (! fDataTransferDoc)
- OleApp_DocLockApp(lpOleApp);
- #if defined( OLE_SERVER )
- /* NOTE: perform initialization specific for an OLE server */
- if (! ServerDoc_Init((LPSERVERDOC)lpOleDoc, fDataTransferDoc))
- return FALSE;
- #endif
- #if defined( OLE_CNTR )
- /* NOTE: 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.
- *
- * NOTE: 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) {
- /* NOTE: 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 calledrn")
- 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 {
- OLESTRCPY(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_ShowWindowrn")
- /* NOTE: 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 )
- /* NOTE: 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 calledrn")
- RegisterDragDrop(
- LineList_GetWindow(lpLL),
- (LPDROPTARGET)&lpOleDoc->m_DropTarget
- );
- OLEDBG_END2
- lpOleDoc->m_fRegDragDrop = TRUE;
- }
- #endif // USE_DRAGDROP
- #if defined( USE_FRAMETOOLS )
- {
- /* NOTE: 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) {
- /* NOTE: 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 calledrn");
- lpServerDoc->m_lpOleClientSite->lpVtbl->ShowObject(
- lpServerDoc->m_lpOleClientSite
- );
- OLEDBG_END2
- /* NOTE: 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) calledrn");
- lpServerDoc->m_lpOleClientSite->lpVtbl->OnShowWindow(
- lpServerDoc->m_lpOleClientSite,
- TRUE
- );
- OLEDBG_END2
- }
- /* NOTE: 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);
- SetForegroundWindow(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_HideWindowrn")
- #if defined( USE_DRAGDROP )
- // The document's window is being hidden, revoke it as a DropTarget
- if (lpOleDoc->m_fRegDragDrop) {
- OLEDBG_BEGIN2("RevokeDragDrop calledrn");
- RevokeDragDrop(LineList_GetWindow(lpLL));
- OLEDBG_END2
- lpOleDoc->m_fRegDragDrop = FALSE ;
- }
- #endif // USE_DRAGDROP
- /* NOTE: 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;
- /* NOTE: 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) calledrn");
- lpServerDoc->m_lpOleClientSite->lpVtbl->OnShowWindow(
- lpServerDoc->m_lpOleClientSite,
- FALSE
- );
- OLEDBG_END2
- }
- }
- #endif
- /* NOTE: 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) calledrn")
- } else {
- if (fLastUnlockReleases)
- OLEDBG_BEGIN2("CoLockObjectExternal(lpDoc,FALSE,TRUE) calledrn")
- else
- OLEDBG_BEGIN2("CoLockObjectExternal(lpDoc,FALSE,FALSE) calledrn")
- }
- #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++rn",
- 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;
- /*********************************************************************
- ** NOTE: 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--rn", lpOleDoc, cRef);
- #endif
- if (cRef == 0)
- OutlineDoc_Destroy((LPOUTLINEDOC)lpOleDoc);
- return cRef;
- }
- /* OleDoc_QueryInterface
- ** ---------------------
- **
- ** Retrieve a pointer to an interface on the document object.
- **
- ** NOTE: 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;
- /* NOTE: we must make sure to set all out ptr parameters to NULL. */
- *lplpvObj = NULL;
- if (IsEqualIID(riid, &IID_IUnknown)) {
- OleDbgOut4("OleDoc_QueryInterface: IUnknown* RETURNEDrn");
- *lplpvObj = (LPVOID) &lpOleDoc->m_Unknown;
- OleDoc_AddRef(lpOleDoc);
- sc = S_OK;
- }
- else if(lpOutlineDoc->m_fDataTransferDoc
- && IsEqualIID(riid, &IID_IDataObject)) {
- OleDbgOut4("OleDoc_QueryInterface: IDataObject* RETURNEDrn");
- *lplpvObj = (LPVOID) &lpOleDoc->m_DataObject;
- OleDoc_AddRef(lpOleDoc);
- sc = S_OK;
- }
- /* NOTE: 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* RETURNEDrn");
- *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* RETURNEDrn");
- *lplpvObj = (LPVOID) &lpOleDoc->m_OleItemContainer;
- OleDoc_AddRef(lpOleDoc);
- sc = S_OK;
- }
- else if(IsEqualIID(riid, &IID_IExternalConnection)) {
- OleDbgOut4("OleDoc_QueryInterface: IExternalConnection* RETURNEDrn");
- *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* RETURNEDrn");
- *lplpvObj = (LPVOID) &lpOleDoc->m_DropTarget;
- OleDoc_AddRef(lpOleDoc);
- sc = S_OK;
- }
- else if(IsEqualIID(riid, &IID_IDropSource)) {
- OleDbgOut4("OleDoc_QueryInterface: IDropSource* RETURNEDrn");
- *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* RETURNEDrn");
- *lplpvObj=(LPVOID)&((LPCONTAINERDOC)lpOleDoc)->m_OleUILinkContainer;
- OleDoc_AddRef(lpOleDoc);
- sc = S_OK;
- }
- #endif
- #if defined( OLE_SERVER )
- /* NOTE: if OLE server version, than also offer the server
- ** specific interfaces: IOleObject and IPersistStorage.
- */
- else if (IsEqualIID(riid, &IID_IOleObject)) {
- OleDbgOut4("OleDoc_QueryInterface: IOleObject* RETURNEDrn");
- *lplpvObj = (LPVOID) &((LPSERVERDOC)lpOleDoc)->m_OleObject;
- OleDoc_AddRef(lpOleDoc);
- sc = S_OK;
- }
- else if(IsEqualIID(riid, &IID_IPersistStorage)) {
- OleDbgOut4("OleDoc_QueryInterface: IPersistStorage* RETURNEDrn");
- *lplpvObj = (LPVOID) &((LPSERVERDOC)lpOleDoc)->m_PersistStorage;
- OleDoc_AddRef(lpOleDoc);
- sc = S_OK;
- }
- else if(IsEqualIID(riid, &IID_IDataObject)) {
- OleDbgOut4("OleDoc_QueryInterface: IDataObject* RETURNEDrn");
- *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* RETURNEDrn");
- *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* RETURNEDrn");
- *lplpvObj = (LPVOID) &((LPSERVERDOC)lpOleDoc)->m_OleInPlaceObject;
- OleDoc_AddRef(lpOleDoc);
- sc = S_OK;
- }
- #endif // INPLACE_SVR
- #endif // OLE_SERVER
- done:
- OleDbgQueryInterfaceMethod(*lplpvObj);
- return 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_Closern")
- if (! OutlineDoc_CheckSaveChanges((LPOUTLINEDOC)lpOleDoc,&dwSaveOption)
- && fAbortIfSaveCanceled) {
- OLEDBG_END3
- return FALSE; // cancel closing the doc
- }
- lpOleDoc->m_fObjIsClosing = TRUE; // guard against recursive call
- /* NOTE: 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;
- /* NOTE: 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 )
- /* NOTE: if the server is currently in-place active we must
- ** deactivate it now before closing
- */
- ServerDoc_DoInPlaceDeactivate((LPSERVERDOC)lpOleDoc);
- #endif
- /* NOTE: 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);
- }
- /* NOTE: 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 calledrn")
- OleStdRevokeAsRunning(&lpOleDoc->m_dwRegROT);
- OLEDBG_END3
- /* NOTE: 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;
- /* NOTE: force all pseudo objects to close. this informs all
- ** linking clients of pseudo objects to release their PseudoObj.
- */
- ServerNameTable_CloseAllPseudoObjs(lpServerNameTable);
- /* NOTE: 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
- );
- }
- /* NOTE: 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,
- OLESTR("DataAdviseHldr not released properly")
- );
- lpServerDoc->m_lpDataAdviseHldr = NULL;
- }
- // NOTE: 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 */
- );
- /* NOTE: 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,
- OLESTR("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;
- }
- /* NOTE: 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) calledrn")
- 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 )
- /* NOTE: 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 )
- OleDbgAssertSz(
- (lpOutlineDoc->m_fDataTransferDoc || lpOleDoc->m_fObjIsClosing),
- "Destroy called without Close being calledrn"
- );
- #endif // _DEBUG
- #if defined( OBSOLETE )
- /* NOTE: 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;
- /* NOTE: 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;
- }
- /*****************************************************************
- ** NOTE: 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);
- }