diff options
Diffstat (limited to 'private/oleutest/letest/outline/linking.c')
-rw-r--r-- | private/oleutest/letest/outline/linking.c | 2157 |
1 files changed, 2157 insertions, 0 deletions
diff --git a/private/oleutest/letest/outline/linking.c b/private/oleutest/letest/outline/linking.c new file mode 100644 index 000000000..cc0e91d72 --- /dev/null +++ b/private/oleutest/letest/outline/linking.c @@ -0,0 +1,2157 @@ +/************************************************************************* +** +** OLE 2 Sample Code +** +** linking.c +** +** This file contains the major interfaces, methods and related support +** functions for implementing linking to items. The code +** contained in this file is used by BOTH the Container and Server +** (Object) versions of the Outline sample code. +** +** As a server SVROUTL supports linking to the whole document object +** (either a file-based document or as an embedded object). It also +** supports linking to ranges (or PseudoObjects). +** +** As a container CNTROUTL supports linking to embedded objects. +** (see file svrpsobj.c for Pseudo Object implementation) +** +** OleDoc Object +** exposed interfaces: +** IPersistFile +** IOleItemContainer +** IExternalConnection +** +** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved +** +*************************************************************************/ + +#include "outline.h" + +OLEDBGDATA + +extern LPOUTLINEAPP g_lpApp; + + + +STDMETHODIMP OleDoc_ItemCont_GetObjectA( + LPOLEITEMCONTAINER lpThis, + LPSTR lpszItem, + DWORD dwSpeedNeeded, + LPBINDCTX lpbc, + REFIID riid, + LPVOID FAR*lplpvObject +); + +STDMETHODIMP OleDoc_ItemCont_GetObjectStorageA( + LPOLEITEMCONTAINER lpThis, + LPSTR lpszItem, + LPBINDCTX lpbc, + REFIID riid, + LPVOID FAR*lplpvStorage +); + +#if defined(OLE_CNTR) + +STDMETHODIMP OleDoc_ItemCont_IsRunningA( + LPOLEITEMCONTAINER lpThis, + LPSTR lpszItem +); + +HRESULT ContainerDoc_IsRunningA( + LPCONTAINERDOC lpContainerDoc, + LPSTR lpszItem); + +HRESULT ContainerDoc_GetObjectA( + LPCONTAINERDOC lpContainerDoc, + LPSTR lpszItem, + DWORD dwSpeedNeeded, + REFIID riid, + LPVOID FAR*lplpvObject +); + +HRESULT ContainerDoc_GetObjectStorageA( + LPCONTAINERDOC lpContainerDoc, + LPSTR lpszItem, + LPSTORAGE FAR*lplpStg); + +#endif // OLE_CNTR + +#if defined(OLE_SERVER) + +HRESULT ServerDoc_IsRunningA(LPSERVERDOC lpServerDoc, LPSTR lpszItem); + +HRESULT ServerDoc_GetObjectA( + LPSERVERDOC lpServerDoc, + LPSTR lpszItem, + REFIID riid, + LPVOID FAR*lplpvObject); + +#endif // OLE_SERVER + + + + + + +/************************************************************************* +** OleDoc::IPersistFile interface implementation +*************************************************************************/ + +// IPersistFile::QueryInterface +STDMETHODIMP OleDoc_PFile_QueryInterface( + LPPERSISTFILE lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +) +{ + LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc; + + return OleDoc_QueryInterface(lpOleDoc, riid, lplpvObj); +} + + +// IPersistFile::AddRef +STDMETHODIMP_(ULONG) OleDoc_PFile_AddRef(LPPERSISTFILE lpThis) +{ + LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc; + + OleDbgAddRefMethod(lpThis, "IPersistFile"); + + return OleDoc_AddRef(lpOleDoc); +} + + +// IPersistFile::Release +STDMETHODIMP_(ULONG) OleDoc_PFile_Release (LPPERSISTFILE lpThis) +{ + LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc; + + OleDbgReleaseMethod(lpThis, "IPersistFile"); + + return OleDoc_Release(lpOleDoc); +} + + +// IPersistFile::GetClassID +STDMETHODIMP OleDoc_PFile_GetClassID ( + LPPERSISTFILE lpThis, + CLSID FAR* lpclsid +) +{ + LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc; + LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp; + OleDbgOut2("OleDoc_PFile_GetClassID\r\n"); + +#if defined( OLE_SERVER ) && defined( SVR_TREATAS ) + + /* OLE2NOTE: we must be carefull to return the correct CLSID here. + ** if we are currently preforming a "TreatAs (aka. ActivateAs)" + ** operation then we need to return the class of the object + ** written in the storage of the object. otherwise we would + ** return our own class id. + */ + return ServerDoc_GetClassID((LPSERVERDOC)lpOleDoc, lpclsid); +#else + *lpclsid = CLSID_APP; +#endif + return NOERROR; +} + + +// IPersistFile::IsDirty +STDMETHODIMP OleDoc_PFile_IsDirty(LPPERSISTFILE lpThis) +{ + LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc; + OleDbgOut2("OleDoc_PFile_IsDirty\r\n"); + + if (OutlineDoc_IsModified((LPOUTLINEDOC)lpOleDoc)) + return NOERROR; + else + return ResultFromScode(S_FALSE); +} + + +// IPersistFile::Load +STDMETHODIMP OleDoc_PFile_LoadA( + LPPERSISTFILE lpThis, + LPCSTR lpszFileName, + DWORD grfMode +) +{ + LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc; + SCODE sc; + + OLEDBG_BEGIN2("OleDoc_PFile_Load\r\n") + + /* OLE2NOTE: grfMode passed from the caller indicates if the caller + ** needs Read or ReadWrite permissions. if appropriate the + ** callee should open the file with the requested permissions. + ** the caller will normally not impose sharing permissions. + ** + ** the sample code currently always opens its file ReadWrite. + */ + + if (OutlineDoc_LoadFromFile((LPOUTLINEDOC)lpOleDoc, (LPSTR)lpszFileName)) + sc = S_OK; + else + sc = E_FAIL; + + OLEDBG_END2 + return ResultFromScode(sc); +} + + + +// IPersistFile::Load +STDMETHODIMP OleDoc_PFile_Load ( + LPPERSISTFILE lpThis, + LPCOLESTR lpszFileName, + DWORD grfMode +) +{ + CREATESTR(lpsz, lpszFileName) + + HRESULT hr = OleDoc_PFile_LoadA(lpThis, lpsz, grfMode); + + FREESTR(lpsz) + + return hr; +} + + + +// IPersistFile::Save +STDMETHODIMP OleDoc_PFile_SaveA ( + LPPERSISTFILE lpThis, + LPCSTR lpszFileName, + BOOL fRemember +) +{ + LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc; + SCODE sc; + + OLEDBG_BEGIN2("OleDoc_PFile_Save\r\n") + + /* OLE2NOTE: it is only legal to perform a Save or SaveAs operation + ** on a file-based document. if the document is an embedded + ** object then we can not be changed to a file-base object. + ** + ** fRemember lpszFileName Type of Save + ** ---------------------------------------------- + ** TRUE NULL SAVE + ** TRUE ! NULL SAVE AS + ** FALSE ! NULL SAVE COPY AS + ** FALSE NULL ***error*** + */ + if ( (lpszFileName==NULL || (lpszFileName != NULL && fRemember)) + && ((lpOutlineDoc->m_docInitType != DOCTYPE_FROMFILE + && lpOutlineDoc->m_docInitType != DOCTYPE_NEW)) ) { + OLEDBG_END2 + return ResultFromScode(E_INVALIDARG); + } + + if (OutlineDoc_SaveToFile( + (LPOUTLINEDOC)lpOleDoc, + lpszFileName, + lpOutlineDoc->m_cfSaveFormat, + fRemember)) { + sc = S_OK; + } else + sc = E_FAIL; + + OLEDBG_END2 + return ResultFromScode(sc); +} + + + +// IPersistFile::Save +STDMETHODIMP OleDoc_PFile_Save( + LPPERSISTFILE lpThis, + LPCOLESTR lpszFileName, + BOOL fRemember +) +{ + CREATESTR(lpsz, lpszFileName) + + HRESULT hr = OleDoc_PFile_SaveA(lpThis, lpsz, fRemember); + + FREESTR(lpsz) + + return hr; +} + + + + +// IPersistFile::SaveCompleted +STDMETHODIMP OleDoc_PFile_SaveCompletedA ( + LPPERSISTFILE lpThis, + LPCSTR lpszFileName +) +{ + LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc; + + OleDbgOut2("OleDoc_PFile_SaveCompleted\r\n"); + + /* This method is called after IPersistFile::Save is called. during + ** the period between Save and SaveCompleted the object must + ** consider itself in NOSCRIBBLE mode (ie. it is NOT allowed to + ** write to its file. here the object can clear its NOSCRIBBLE + ** mode flag. the outline app never scribbles to its storage, so + ** we have nothing to do. + */ + return NOERROR; +} + + + +STDMETHODIMP OleDoc_PFile_SaveCompleted ( + LPPERSISTFILE lpThis, + LPCOLESTR lpszFileName +) +{ + CREATESTR(lpsz, lpszFileName) + + HRESULT hr = OleDoc_PFile_SaveCompletedA(lpThis, lpsz); + + FREESTR(lpsz) + + return hr; +} + + + +// IPersistFile::GetCurFile +STDMETHODIMP OleDoc_PFile_GetCurFileA ( + LPPERSISTFILE lpThis, + LPSTR FAR* lplpszFileName +) +{ + LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc; + LPMALLOC lpMalloc; + LPSTR lpsz; + SCODE sc; + OleDbgOut2("OleDoc_PFile_GetCurFile\r\n"); + + /* OLE2NOTE: we must make sure to set all out ptr parameters to NULL. */ + *lplpszFileName = NULL; + + /********************************************************************* + ** OLE2NOTE: memory returned for the lplpszFileName must be + ** allocated appropriately using the current registered IMalloc + ** interface. the allows the ownership of the memory to be + ** passed to the caller (even if in another process). + *********************************************************************/ + + CoGetMalloc(MEMCTX_TASK, &lpMalloc); + if (! lpMalloc) { + return ResultFromScode(E_FAIL); + } + + if (lpOutlineDoc->m_docInitType == DOCTYPE_FROMFILE) { + /* valid filename associated; return file name */ + lpsz = (LPSTR)lpMalloc->lpVtbl->Alloc( + lpMalloc, + lstrlen((LPSTR)lpOutlineDoc->m_szFileName)+1 + ); + if (! lpsz) { + sc = E_OUTOFMEMORY; + goto error; + } + + lstrcpy(lpsz, (LPSTR)lpOutlineDoc->m_szFileName); + sc = S_OK; + } else { + /* no file associated; return default file name prompt */ + lpsz=(LPSTR)lpMalloc->lpVtbl->Alloc(lpMalloc, sizeof(DEFEXTENSION)+3); + wsprintf(lpsz, "*.%s", DEFEXTENSION); + sc = S_FALSE; + } + +error: + OleStdRelease((LPUNKNOWN)lpMalloc); + *lplpszFileName = lpsz; + return ResultFromScode(sc); +} + +STDMETHODIMP OleDoc_PFile_GetCurFile ( + LPPERSISTFILE lpThis, + LPOLESTR FAR* lplpszFileName +) +{ + LPSTR lpsz; + + HRESULT hr = OleDoc_PFile_GetCurFileA(lpThis, &lpsz); + + CopyAndFreeSTR(lpsz, lplpszFileName); + + return hr; +} + +/************************************************************************* +** OleDoc::IOleItemContainer interface implementation +*************************************************************************/ + +// IOleItemContainer::QueryInterface +STDMETHODIMP OleDoc_ItemCont_QueryInterface( + LPOLEITEMCONTAINER lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +) +{ + LPOLEDOC lpOleDoc = + ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc; + + return OleDoc_QueryInterface(lpOleDoc, riid, lplpvObj); +} + + +// IOleItemContainer::AddRef +STDMETHODIMP_(ULONG) OleDoc_ItemCont_AddRef(LPOLEITEMCONTAINER lpThis) +{ + LPOLEDOC lpOleDoc = + ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc; + + OleDbgAddRefMethod(lpThis, "IOleItemContainer"); + + return OleDoc_AddRef((LPOLEDOC)lpOleDoc); +} + + +// IOleItemContainer::Release +STDMETHODIMP_(ULONG) OleDoc_ItemCont_Release(LPOLEITEMCONTAINER lpThis) +{ + LPOLEDOC lpOleDoc = + ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc; + + OleDbgReleaseMethod(lpThis, "IOleItemContainer"); + + return OleDoc_Release((LPOLEDOC)lpOleDoc); +} + + +// IOleItemContainer::ParseDisplayName +STDMETHODIMP OleDoc_ItemCont_ParseDisplayNameA( + LPOLEITEMCONTAINER lpThis, + LPBC lpbc, + LPSTR lpszDisplayName, + ULONG FAR* lpchEaten, + LPMONIKER FAR* lplpmkOut +) +{ + LPOLEDOC lpOleDoc = + ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc; + char szItemName[MAXNAMESIZE]; + LPUNKNOWN lpUnk; + HRESULT hrErr; + OleDbgOut2("OleDoc_ItemCont_ParseDisplayName\r\n"); + + /* OLE2NOTE: we must make sure to set all out ptr parameters to NULL. */ + *lplpmkOut = NULL; + + *lpchEaten = OleStdGetItemToken( + lpszDisplayName, + szItemName, + sizeof(szItemName) + ); + + /* OLE2NOTE: get a pointer to a running instance of the object. we + ** should force the object to go running if necessary (even if + ** this means launching its server EXE). this is the meaining of + ** BINDSPEED_INDEFINITE. Parsing a Moniker is known to be an + ** "EXPENSIVE" operation. + */ + hrErr = OleDoc_ItemCont_GetObjectA( + lpThis, + szItemName, + BINDSPEED_INDEFINITE, + lpbc, + &IID_IUnknown, + (LPVOID FAR*)&lpUnk + ); + + if (hrErr == NOERROR) { + OleStdRelease(lpUnk); // item name FOUND; don't need obj ptr. + + CreateItemMonikerA(OLESTDDELIM, szItemName, lplpmkOut); + + } else + *lpchEaten = 0; // item name is NOT valid + + return hrErr; +} + +STDMETHODIMP OleDoc_ItemCont_ParseDisplayName( + LPOLEITEMCONTAINER lpThis, + LPBC lpbc, + LPOLESTR lpszDisplayName, + ULONG FAR* lpchEaten, + LPMONIKER FAR* lplpmkOut +) +{ + CREATESTR(lpsz, lpszDisplayName) + + HRESULT hr = OleDoc_ItemCont_ParseDisplayNameA(lpThis, lpbc, + lpsz, lpchEaten, lplpmkOut); + + FREESTR(lpsz); + + return hr; +} + + +// IOleItemContainer::EnumObjects +STDMETHODIMP OleDoc_ItemCont_EnumObjects( + LPOLEITEMCONTAINER lpThis, + DWORD grfFlags, + LPENUMUNKNOWN FAR* lplpenumUnknown +) +{ + LPOLEDOC lpOleDoc = + ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc; + + OLEDBG_BEGIN2("OleDoc_ItemCont_EnumObjects\r\n") + + /* OLE2NOTE: we must make sure to set all out ptr parameters to NULL. */ + *lplpenumUnknown = NULL; + + /* OLE2NOTE: this method should be implemented to allow programatic + ** clients the ability to what elements the container holds. + ** this method is NOT called in the standard linking scenarios. + ** + ** grfFlags can be one of the following: + ** OLECONTF_EMBEDDINGS -- enumerate embedded objects + ** OLECONTF_LINKS -- enumerate linked objects + ** OLECONTF_OTHERS -- enumerate non-OLE compound doc objs + ** OLECONTF_ONLYUSER -- enumerate only objs named by user + ** OLECONTF_ONLYIFRUNNING-- enumerate only objs in running state + */ + + OleDbgAssertSz(0, "NOT YET IMPLEMENTED!"); + + OLEDBG_END2 + return ResultFromScode(E_NOTIMPL); +} + + +// IOleItemContainer::LockContainer +STDMETHODIMP OleDoc_ItemCont_LockContainer( + LPOLEITEMCONTAINER lpThis, + BOOL fLock +) +{ + LPOLEDOC lpOleDoc = + ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc; + HRESULT hrErr; + OLEDBG_BEGIN2("OleDoc_ItemCont_LockContainer\r\n") + +#if defined( _DEBUG ) + if (fLock) { + ++lpOleDoc->m_cCntrLock; + OleDbgOutRefCnt3( + "OleDoc_ItemCont_LockContainer: cLock++\r\n", + lpOleDoc, + lpOleDoc->m_cCntrLock + ); + } else { + /* OLE2NOTE: when there are no open documents and the app is not + ** under the control of the user and there are no outstanding + ** locks on the app, then revoke our ClassFactory to enable the + ** app to shut down. + */ + --lpOleDoc->m_cCntrLock; + OleDbgAssertSz ( + lpOleDoc->m_cCntrLock >= 0, + "OleDoc_ItemCont_LockContainer(FALSE) called with cLock == 0" + ); + + if (lpOleDoc->m_cCntrLock == 0) { + OleDbgOutRefCnt2( + "OleDoc_ItemCont_LockContainer: UNLOCKED\r\n", + lpOleDoc, lpOleDoc->m_cCntrLock); + } else { + OleDbgOutRefCnt3( + "OleDoc_ItemCont_LockContainer: cLock--\r\n", + lpOleDoc, lpOleDoc->m_cCntrLock); + } + } +#endif // _DEBUG + + /* OLE2NOTE: in order to hold the document alive we call + ** CoLockObjectExternal to add a strong reference to our Doc + ** object. this will keep the Doc alive when all other external + ** references release us. whenever an embedded object goes + ** running a LockContainer(TRUE) is called. when the embedded + ** object shuts down (ie. transitions from running to loaded) + ** LockContainer(FALSE) is called. if the user issues File.Close + ** the document will shut down in any case ignoring any + ** outstanding LockContainer locks because CoDisconnectObject is + ** called in OleDoc_Close. this will forceably break any + ** existing strong reference counts including counts that we add + ** ourselves by calling CoLockObjectExternal and guarantee that + ** the Doc object gets its final release (ie. cRefs goes to 0). + */ + hrErr = OleDoc_Lock(lpOleDoc, fLock, TRUE /* fLastUnlockReleases */); + + OLEDBG_END2 + return hrErr; +} + + +// IOleItemContainer::GetObject +STDMETHODIMP OleDoc_ItemCont_GetObjectA( + LPOLEITEMCONTAINER lpThis, + LPSTR lpszItem, + DWORD dwSpeedNeeded, + LPBINDCTX lpbc, + REFIID riid, + LPVOID FAR* lplpvObject +) +{ + LPOLEDOC lpOleDoc = + ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc; + HRESULT hrErr; + + OLEDBG_BEGIN2("OleDoc_ItemCont_GetObject\r\n") + + /* OLE2NOTE: we must make sure to set all out ptr parameters to NULL. */ + *lplpvObject = NULL; + +#if defined( OLE_SERVER ) + + /* OLE2NOTE: SERVER ONLY version should return PseudoObjects with + ** BINDSPEED_IMMEDIATE, thus the dwSpeedNeeded is not important + ** in the case of a pure server. + */ + hrErr = ServerDoc_GetObjectA( + (LPSERVERDOC)lpOleDoc, lpszItem,riid,lplpvObject); +#endif +#if defined( OLE_CNTR ) + + /* OLE2NOTE: dwSpeedNeeded indicates how long the caller is willing + ** to wait for us to get the object: + ** BINDSPEED_IMMEDIATE -- only if obj already loaded && IsRunning + ** BINDSPEED_MODERATE -- load obj if necessary && if IsRunning + ** BINDSPEED_INDEFINITE-- force obj to load and run if necessary + */ + hrErr = ContainerDoc_GetObjectA( + (LPCONTAINERDOC)lpOleDoc,lpszItem,dwSpeedNeeded,riid,lplpvObject); +#endif + + OLEDBG_END2 + return hrErr; +} + + + + +STDMETHODIMP OleDoc_ItemCont_GetObject( + LPOLEITEMCONTAINER lpThis, + LPOLESTR lpszItem, + DWORD dwSpeedNeeded, + LPBINDCTX lpbc, + REFIID riid, + LPVOID FAR* lplpvObject +) +{ + CREATESTR(lpsz, lpszItem) + + HRESULT hr = OleDoc_ItemCont_GetObjectA(lpThis, lpsz, dwSpeedNeeded, lpbc, + riid, lplpvObject); + + FREESTR(lpsz) + + return hr; +} + + +// IOleItemContainer::GetObjectStorage +STDMETHODIMP OleDoc_ItemCont_GetObjectStorageA( + LPOLEITEMCONTAINER lpThis, + LPSTR lpszItem, + LPBINDCTX lpbc, + REFIID riid, + LPVOID FAR* lplpvStorage +) +{ + LPOLEDOC lpOleDoc = + ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc; + OleDbgOut2("OleDoc_ItemCont_GetObjectStorage\r\n"); + + /* OLE2NOTE: we must make sure to set all out ptr parameters to NULL. */ + *lplpvStorage = NULL; + +#if defined( OLE_SERVER ) + /* OLE2NOTE: in the SERVER ONLY version, item names identify pseudo + ** objects. pseudo objects, do NOT have identifiable storage. + */ + return ResultFromScode(E_FAIL); +#endif +#if defined( OLE_CNTR ) + // We can only return an IStorage* type pointer + if (! IsEqualIID(riid, &IID_IStorage)) + return ResultFromScode(E_FAIL); + + return ContainerDoc_GetObjectStorageA( + (LPCONTAINERDOC)lpOleDoc, + lpszItem, + (LPSTORAGE FAR*)lplpvStorage + ); +#endif +} + +STDMETHODIMP OleDoc_ItemCont_GetObjectStorage( + LPOLEITEMCONTAINER lpThis, + LPOLESTR lpszItem, + LPBINDCTX lpbc, + REFIID riid, + LPVOID FAR* lplpvStorage +) +{ + CREATESTR(lpsz, lpszItem) + + HRESULT hr = OleDoc_ItemCont_GetObjectStorageA(lpThis, lpsz, lpbc, + riid, lplpvStorage); + + FREESTR(lpsz) + + return hr; +} + +// IOleItemContainer::IsRunning +STDMETHODIMP OleDoc_ItemCont_IsRunningA( + LPOLEITEMCONTAINER lpThis, + LPSTR lpszItem +) +{ + LPOLEDOC lpOleDoc = + ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc; + HRESULT hrErr; + + OLEDBG_BEGIN2("OleDoc_ItemCont_IsRunning\r\n") + + /* OLE2NOTE: Check if item name is valid. if so then return if + ** Object is running. PseudoObjects in the Server version are + ** always considered running. Ole objects in the container must + ** be checked if they are running. + */ + +#if defined( OLE_SERVER ) + hrErr = ServerDoc_IsRunningA((LPSERVERDOC)lpOleDoc, lpszItem); +#endif +#if defined( OLE_CNTR ) + hrErr = ContainerDoc_IsRunningA((LPCONTAINERDOC)lpOleDoc, lpszItem); +#endif + + OLEDBG_END2 + return hrErr; +} + +STDMETHODIMP OleDoc_ItemCont_IsRunning( + LPOLEITEMCONTAINER lpThis, + LPOLESTR lpszItem +) +{ + CREATESTR(lpsz, lpszItem) + + HRESULT hr = OleDoc_ItemCont_IsRunningA(lpThis,lpsz); + + FREESTR(lpsz) + + return hr; +} + +/************************************************************************* +** OleDoc::IExternalConnection interface implementation +*************************************************************************/ + +// IExternalConnection::QueryInterface +STDMETHODIMP OleDoc_ExtConn_QueryInterface( + LPEXTERNALCONNECTION lpThis, + REFIID riid, + LPVOID FAR* lplpvObj +) +{ + LPOLEDOC lpOleDoc = + ((struct CDocExternalConnectionImpl FAR*)lpThis)->lpOleDoc; + + return OleDoc_QueryInterface(lpOleDoc, riid, lplpvObj); +} + + +// IExternalConnection::AddRef +STDMETHODIMP_(ULONG) OleDoc_ExtConn_AddRef(LPEXTERNALCONNECTION lpThis) +{ + LPOLEDOC lpOleDoc = + ((struct CDocExternalConnectionImpl FAR*)lpThis)->lpOleDoc; + + OleDbgAddRefMethod(lpThis, "IExternalConnection"); + + return OleDoc_AddRef(lpOleDoc); +} + + +// IExternalConnection::Release +STDMETHODIMP_(ULONG) OleDoc_ExtConn_Release (LPEXTERNALCONNECTION lpThis) +{ + LPOLEDOC lpOleDoc = + ((struct CDocExternalConnectionImpl FAR*)lpThis)->lpOleDoc; + + OleDbgReleaseMethod(lpThis, "IExternalConnection"); + + return OleDoc_Release(lpOleDoc); +} + + +// IExternalConnection::AddConnection +STDMETHODIMP_(DWORD) OleDoc_ExtConn_AddConnection( + LPEXTERNALCONNECTION lpThis, + DWORD extconn, + DWORD reserved +) +{ + LPOLEDOC lpOleDoc = + ((struct CDocExternalConnectionImpl FAR*)lpThis)->lpOleDoc; + + if( extconn & EXTCONN_STRONG ) { + +#if defined( _DEBUG ) + OleDbgOutRefCnt3( + "OleDoc_ExtConn_AddConnection: dwStrongExtConn++\r\n", + lpOleDoc, + lpOleDoc->m_dwStrongExtConn + 1 + ); +#endif + return ++(lpOleDoc->m_dwStrongExtConn); + } else + return 0; +} + + +// IExternalConnection::ReleaseConnection +STDMETHODIMP_(DWORD) OleDoc_ExtConn_ReleaseConnection( + LPEXTERNALCONNECTION lpThis, + DWORD extconn, + DWORD reserved, + BOOL fLastReleaseCloses +) +{ + LPOLEDOC lpOleDoc = + ((struct CDocExternalConnectionImpl FAR*)lpThis)->lpOleDoc; + + if( extconn & EXTCONN_STRONG ){ + DWORD dwSave = --(lpOleDoc->m_dwStrongExtConn); +#if defined( _DEBUG ) + OLEDBG_BEGIN2( (fLastReleaseCloses ? + "OleDoc_ExtConn_ReleaseConnection(TRUE)\r\n" : + "OleDoc_ExtConn_ReleaseConnection(FALSE)\r\n") ) + OleDbgOutRefCnt3( + "OleDoc_ExtConn_ReleaseConnection: dwStrongExtConn--\r\n", + lpOleDoc, + lpOleDoc->m_dwStrongExtConn + ); + OleDbgAssertSz ( + lpOleDoc->m_dwStrongExtConn >= 0, + "OleDoc_ExtConn_ReleaseConnection called with dwStrong == 0" + ); +#endif // _DEBUG + + if( lpOleDoc->m_dwStrongExtConn == 0 && fLastReleaseCloses ) + OleDoc_Close(lpOleDoc, OLECLOSE_SAVEIFDIRTY); + + OLEDBG_END2 + return dwSave; + } else + return 0; +} + + +/************************************************************************* +** OleDoc Common Support Functions +*************************************************************************/ + + +/* OleDoc_GetFullMoniker +** --------------------- +** Return the full, absolute moniker of the document. +** +** NOTE: the caller must release the pointer returned when done. +*/ +LPMONIKER OleDoc_GetFullMoniker(LPOLEDOC lpOleDoc, DWORD dwAssign) +{ + LPMONIKER lpMoniker = NULL; + + OLEDBG_BEGIN3("OleDoc_GetFullMoniker\r\n") + + if (lpOleDoc->m_lpSrcDocOfCopy) { + /* CASE I: this document was created for a copy or drag/drop + ** operation. generate the moniker which identifies the + ** source document of the original copy. + */ + if (! lpOleDoc->m_fLinkSourceAvail) + goto done; // we already know a moniker is not available + + lpMoniker=OleDoc_GetFullMoniker(lpOleDoc->m_lpSrcDocOfCopy, dwAssign); + } + else if (lpOleDoc->m_lpFileMoniker) { + + /* CASE II: this document is a top-level user document (either + ** file-based or untitled). return the FileMoniker stored + ** with the document; it uniquely identifies the document. + */ + // we must AddRef the moniker to pass out a ptr + lpOleDoc->m_lpFileMoniker->lpVtbl->AddRef(lpOleDoc->m_lpFileMoniker); + + lpMoniker = lpOleDoc->m_lpFileMoniker; + } + +#if defined( OLE_SERVER ) + + else if (((LPSERVERDOC)lpOleDoc)->m_lpOleClientSite) { + + /* CASE III: this document is an embedded object, ask our + ** container for our moniker. + */ + OLEDBG_BEGIN2("IOleClientSite::GetMoniker called\r\n"); + ((LPSERVERDOC)lpOleDoc)->m_lpOleClientSite->lpVtbl->GetMoniker( + ((LPSERVERDOC)lpOleDoc)->m_lpOleClientSite, + dwAssign, + OLEWHICHMK_OBJFULL, + &lpMoniker + ); + OLEDBG_END2 + } + +#endif + + else { + lpMoniker = NULL; + } + +done: + OLEDBG_END3 + return lpMoniker; +} + + +/* OleDoc_DocRenamedUpdate +** ----------------------- +** Update the documents registration in the running object table (ROT). +** Also inform all embedded OLE objects (container only) and/or psedudo +** objects (server only) that the name of the document has changed. +*/ +void OleDoc_DocRenamedUpdate(LPOLEDOC lpOleDoc, LPMONIKER lpmkDoc) +{ + OLEDBG_BEGIN3("OleDoc_DocRenamedUpdate\r\n") + + OleDoc_AddRef(lpOleDoc); + + /* OLE2NOTE: we must re-register ourselves as running when we + ** get a new moniker assigned (ie. when we are renamed). + */ + OLEDBG_BEGIN3("OleStdRegisterAsRunning called\r\n") + OleStdRegisterAsRunning( + (LPUNKNOWN)&lpOleDoc->m_Unknown, + lpmkDoc, + &lpOleDoc->m_dwRegROT + ); + OLEDBG_END3 + +#if defined( OLE_SERVER ) + { + LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOleDoc; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc; + + /* OLE2NOTE: inform any linking clients that the document has been + ** renamed. + */ + ServerDoc_SendAdvise ( + lpServerDoc, + OLE_ONRENAME, + lpmkDoc, + 0 /* advf -- not relevant here */ + ); + + /* OLE2NOTE: inform any clients of pseudo objects + ** within our document, that our document's + ** Moniker has changed. + */ + ServerNameTable_InformAllPseudoObjectsDocRenamed( + (LPSERVERNAMETABLE)lpOutlineDoc->m_lpNameTable, lpmkDoc); + } +#endif +#if defined( OLE_CNTR ) + { + LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOleDoc; + + /* OLE2NOTE: must tell all OLE objects that our container + ** moniker changed. + */ + ContainerDoc_InformAllOleObjectsDocRenamed( + lpContainerDoc, + lpmkDoc + ); + } +#endif + + OleDoc_Release(lpOleDoc); // release artificial AddRef above + OLEDBG_END3 +} + + + +#if defined( OLE_SERVER ) + +/************************************************************************* +** ServerDoc Supprt Functions Used by Server versions +*************************************************************************/ + + +/* ServerDoc_PseudoObjLockDoc +** -------------------------- +** Add a lock on the Doc on behalf of the PseudoObject. the Doc may not +** close while the Doc exists. +** +** when a pseudo object is first created, it calls this method to +** guarantee that the document stays alive (PseudoObj_Init). +** when a pseudo object is destroyed, it call +** ServerDoc_PseudoObjUnlockDoc to release this hold on the document. +*/ +void ServerDoc_PseudoObjLockDoc(LPSERVERDOC lpServerDoc) +{ + LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc; + ULONG cPseudoObj; + + cPseudoObj = ++lpServerDoc->m_cPseudoObj; + +#if defined( _DEBUG ) + OleDbgOutRefCnt3( + "ServerDoc_PseudoObjLockDoc: cPseudoObj++\r\n", + lpServerDoc, + cPseudoObj + ); +#endif + OleDoc_Lock(lpOleDoc, TRUE /* fLock */, 0 /* not applicable */); + return; +} + + +/* ServerDoc_PseudoObjUnlockDoc +** ---------------------------- +** Release the lock on the Doc on behalf of the PseudoObject. if this was +** the last lock on the Doc, then it will shutdown. +*/ +void ServerDoc_PseudoObjUnlockDoc( + LPSERVERDOC lpServerDoc, + LPPSEUDOOBJ lpPseudoObj +) +{ + ULONG cPseudoObj; + LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc; + OLEDBG_BEGIN3("ServerDoc_PseudoObjUnlockDoc\r\n") + + /* OLE2NOTE: when there are no active pseudo objects in the Doc and + ** the Doc is not visible, and if there are no outstanding locks + ** on the Doc, then this is a "silent update" + ** situation. our Doc is being used programatically by some + ** client; it is NOT accessible to the user because it is + ** NOT visible. thus since all Locks have been released, we + ** will close the document. if the app is only running due + ** to the presence of this document, then the app will now + ** also shut down. + */ + cPseudoObj = --lpServerDoc->m_cPseudoObj; + +#if defined( _DEBUG ) + OleDbgAssertSz ( + lpServerDoc->m_cPseudoObj >= 0, + "PseudoObjUnlockDoc called with cPseudoObj == 0" + ); + + OleDbgOutRefCnt3( + "ServerDoc_PseudoObjUnlockDoc: cPseudoObj--\r\n", + lpServerDoc, + cPseudoObj + ); +#endif + OleDoc_Lock(lpOleDoc, FALSE /* fLock */, TRUE /* fLastUnlockReleases */); + + OLEDBG_END3 + return; +} + + +/* ServerDoc_GetObject +** ------------------- +** +** Return a pointer to an object identified by an item string +** (lpszItem). For a server-only app, the object returned will be a +** pseudo object. +*/ +HRESULT ServerDoc_GetObjectA( + LPSERVERDOC lpServerDoc, + LPSTR lpszItem, + REFIID riid, + LPVOID FAR* lplpvObject +) +{ + LPPSEUDOOBJ lpPseudoObj; + LPSERVERNAMETABLE lpServerNameTable = + (LPSERVERNAMETABLE)((LPOUTLINEDOC)lpServerDoc)->m_lpNameTable; + + *lplpvObject = NULL; + + /* Get the PseudoObj which corresponds to an item name. if the item + ** name does NOT exist in the name table then NO object is + ** returned. the ServerNameTable_GetPseudoObj routine finds a + ** name entry corresponding to the item name, it then checks if + ** a PseudoObj has already been allocated. if so, it returns the + ** existing object, otherwise it allocates a new PseudoObj. + */ + lpPseudoObj = ServerNameTable_GetPseudoObj( + lpServerNameTable, + lpszItem, + lpServerDoc + ); + + if (! lpPseudoObj) { + *lplpvObject = NULL; + return ResultFromScode(MK_E_NOOBJECT); + } + + // return the desired interface pointer of the pseudo object. + return PseudoObj_QueryInterface(lpPseudoObj, riid, lplpvObject); +} + + + +HRESULT ServerDoc_GetObject( + LPSERVERDOC lpServerDoc, + LPOLESTR lpszItem, + REFIID riid, + LPVOID FAR* lplpvObject +) +{ + CREATESTR(pstr, lpszItem) + + HRESULT hr = ServerDoc_GetObjectA(lpServerDoc, pstr, riid, lplpvObject); + + FREESTR(pstr) + + return hr; +} + + + +/* ServerDoc_IsRunning +** ------------------- +** +** Check if the object identified by an item string (lpszItem) is in +** the running state. For a server-only app, if the item name exists in +** in the NameTable then the item name is considered running. +** IOleItemContainer::GetObject would succeed. +*/ + +HRESULT ServerDoc_IsRunningA(LPSERVERDOC lpServerDoc, LPSTR lpszItem) +{ + LPOUTLINENAMETABLE lpOutlineNameTable = + ((LPOUTLINEDOC)lpServerDoc)->m_lpNameTable; + LPSERVERNAME lpServerName; + + lpServerName = (LPSERVERNAME)OutlineNameTable_FindName( + lpOutlineNameTable, + lpszItem + ); + + if (lpServerName) + return NOERROR; + else + return ResultFromScode(MK_E_NOOBJECT); +} + + +/* ServerDoc_GetSelRelMoniker +** -------------------------- +** Retrieve the relative item moniker which identifies the given +** selection (lplrSel). +** +** Returns NULL if a moniker can NOT be created. +*/ + +LPMONIKER ServerDoc_GetSelRelMoniker( + LPSERVERDOC lpServerDoc, + LPLINERANGE lplrSel, + DWORD dwAssign +) +{ + LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; + LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc; + LPSERVERNAMETABLE lpServerNameTable = + (LPSERVERNAMETABLE)lpOutlineDoc->m_lpNameTable; + LPOUTLINENAMETABLE lpOutlineNameTable = + (LPOUTLINENAMETABLE)lpServerNameTable; + LPOUTLINENAME lpOutlineName; + LPMONIKER lpmk; + + lpOutlineName=OutlineNameTable_FindNamedRange(lpOutlineNameTable,lplrSel); + + if (lpOutlineName) { + /* the selection range already has a name assigned */ + CreateItemMonikerA(OLESTDDELIM, lpOutlineName->m_szName, &lpmk); + } else { + char szbuf[MAXNAMESIZE]; + + switch (dwAssign) { + + case GETMONIKER_FORCEASSIGN: + + /* Force the assignment of the name. This is called when a + ** Paste Link actually occurs. At this point we want to + ** create a Name and add it to the NameTable in order to + ** track the source of the link. This name (as all + ** names) will be updated upon editing of the document. + */ + wsprintf( + szbuf, + "%s %ld", + (LPSTR)DEFRANGENAMEPREFIX, + ++(lpServerDoc->m_nNextRangeNo) + ); + + lpOutlineName = OutlineApp_CreateName(lpOutlineApp); + + if (lpOutlineName) { + lstrcpy(lpOutlineName->m_szName, szbuf); + lpOutlineName->m_nStartLine = lplrSel->m_nStartLine; + lpOutlineName->m_nEndLine = lplrSel->m_nEndLine; + OutlineDoc_AddName(lpOutlineDoc, lpOutlineName); + } else { + // REVIEW: do we need "Out-of-Memory" error message here? + } + break; + + case GETMONIKER_TEMPFORUSER: + + /* Create a name to show to the user in the Paste + ** Special dialog but do NOT yet incur the overhead + ** of adding a Name to the NameTable. The Moniker + ** generated should be useful to display to the user + ** to indicate the source of the copy, but will NOT + ** be used to create a link directly (the caller + ** should ask again for a moniker specifying FORCEASSIGN). + ** we will generate the name that would be the next + ** auto-generated range name, BUT will NOT actually + ** increment the range counter. + */ + wsprintf( + szbuf, + "%s %ld", + (LPSTR)DEFRANGENAMEPREFIX, + (lpServerDoc->m_nNextRangeNo)+1 + ); + break; + + case GETMONIKER_ONLYIFTHERE: + + /* the caller only wants a name if one has already been + ** assigned. we have already above checked if the + ** current selection has a name, so we will simply + ** return NULL here. + */ + return NULL; // no moniker is assigned + + default: + return NULL; // unknown flag given + } + + CreateItemMonikerA(OLESTDDELIM, szbuf, &lpmk); + } + return lpmk; +} + + +/* ServerDoc_GetSelFullMoniker +** --------------------------- +** Retrieve the full absolute moniker which identifies the given +** selection (lplrSel). +** this moniker is created as a composite of the absolute moniker for +** the entire document appended with an item moniker which identifies +** the selection relative to the document. +** Returns NULL if a moniker can NOT be created. +*/ +LPMONIKER ServerDoc_GetSelFullMoniker( + LPSERVERDOC lpServerDoc, + LPLINERANGE lplrSel, + DWORD dwAssign +) +{ + LPMONIKER lpmkDoc = NULL; + LPMONIKER lpmkItem = NULL; + LPMONIKER lpmkFull = NULL; + + lpmkDoc = OleDoc_GetFullMoniker( + (LPOLEDOC)lpServerDoc, + dwAssign + ); + if (! lpmkDoc) return NULL; + + lpmkItem = ServerDoc_GetSelRelMoniker( + lpServerDoc, + lplrSel, + dwAssign + ); + if (lpmkItem) { + CreateGenericComposite(lpmkDoc, lpmkItem, (LPMONIKER FAR*)&lpmkFull); + OleStdRelease((LPUNKNOWN)lpmkItem); + } + + if (lpmkDoc) + OleStdRelease((LPUNKNOWN)lpmkDoc); + + return lpmkFull; +} + + +/* ServerNameTable_EditLineUpdate + * ------------------------------- + * + * Update the table when a line at nEditIndex is edited. + */ +void ServerNameTable_EditLineUpdate( + LPSERVERNAMETABLE lpServerNameTable, + int nEditIndex +) +{ + LPOUTLINENAMETABLE lpOutlineNameTable = + (LPOUTLINENAMETABLE)lpServerNameTable; + LPOUTLINENAME lpOutlineName; + LINERANGE lrSel; + LPPSEUDOOBJ lpPseudoObj; + int i; + + for(i = 0; i < lpOutlineNameTable->m_nCount; i++) { + lpOutlineName=OutlineNameTable_GetName(lpOutlineNameTable, i); + + lpPseudoObj = ((LPSERVERNAME)lpOutlineName)->m_lpPseudoObj; + + /* if there is a pseudo object associated with this name, then + ** check if the line that was modified is included within + ** the named range. + */ + if (lpPseudoObj) { + OutlineName_GetSel(lpOutlineName, &lrSel); + + if(((int)lrSel.m_nStartLine <= nEditIndex) && + ((int)lrSel.m_nEndLine >= nEditIndex)) { + + // inform linking clients data has changed + PseudoObj_SendAdvise( + lpPseudoObj, + OLE_ONDATACHANGE, + NULL, /* lpmkDoc -- not relevant here */ + 0 /* advf -- no flags necessary */ + ); + } + + } + } +} + + +/* ServerNameTable_InformAllPseudoObjectsDocRenamed + * ------------------------------------------------ + * + * Inform all pseudo object clients that the name of the pseudo + * object has changed. + */ +void ServerNameTable_InformAllPseudoObjectsDocRenamed( + LPSERVERNAMETABLE lpServerNameTable, + LPMONIKER lpmkDoc +) +{ + LPOUTLINENAMETABLE lpOutlineNameTable = + (LPOUTLINENAMETABLE)lpServerNameTable; + LPOUTLINENAME lpOutlineName; + LPPSEUDOOBJ lpPseudoObj; + LPMONIKER lpmkObj; + int i; + + OLEDBG_BEGIN2("ServerNameTable_InformAllPseudoObjectsDocRenamed\r\n"); + + for(i = 0; i < lpOutlineNameTable->m_nCount; i++) { + lpOutlineName=OutlineNameTable_GetName(lpOutlineNameTable, i); + + lpPseudoObj = ((LPSERVERNAME)lpOutlineName)->m_lpPseudoObj; + + /* if there is a pseudo object associated with this name, then + ** send OnRename advise to its linking clients. + */ + if (lpPseudoObj && + ((lpmkObj=PseudoObj_GetFullMoniker(lpPseudoObj,lpmkDoc))!=NULL)) { + + // inform the clients that the name has changed + PseudoObj_SendAdvise ( + lpPseudoObj, + OLE_ONRENAME, + lpmkObj, + 0 /* advf -- not relevant here */ + ); + } + } + OLEDBG_END2 +} + + +/* ServerNameTable_InformAllPseudoObjectsDocSaved + * ------------------------------------------------ + * + * Inform all pseudo object clients that the name of the pseudo + * object has changed. + */ +void ServerNameTable_InformAllPseudoObjectsDocSaved( + LPSERVERNAMETABLE lpServerNameTable, + LPMONIKER lpmkDoc +) +{ + LPOUTLINENAMETABLE lpOutlineNameTable = + (LPOUTLINENAMETABLE)lpServerNameTable; + LPOUTLINENAME lpOutlineName; + LPPSEUDOOBJ lpPseudoObj; + LPMONIKER lpmkObj; + int i; + + OLEDBG_BEGIN2("ServerNameTable_InformAllPseudoObjectsDocSaved\r\n"); + + for(i = 0; i < lpOutlineNameTable->m_nCount; i++) { + lpOutlineName=OutlineNameTable_GetName(lpOutlineNameTable, i); + + lpPseudoObj = ((LPSERVERNAME)lpOutlineName)->m_lpPseudoObj; + + /* if there is a pseudo object associated with this name, then + ** send OnSave advise to its linking clients. + */ + if (lpPseudoObj && + ((lpmkObj=PseudoObj_GetFullMoniker(lpPseudoObj,lpmkDoc))!=NULL)) { + + // inform the clients that the name has been saved + PseudoObj_SendAdvise ( + lpPseudoObj, + OLE_ONSAVE, + NULL, /* lpmkDoc -- not relevant here */ + 0 /* advf -- not relevant here */ + ); + } + } + OLEDBG_END2 +} + + +/* ServerNameTable_SendPendingAdvises + * ---------------------------------- + * + * Send any pending change notifications for pseudo objects. + * while ReDraw is diabled on the ServerDoc, then change advise + * notifications are not sent to pseudo object clients. + */ +void ServerNameTable_SendPendingAdvises(LPSERVERNAMETABLE lpServerNameTable) +{ + LPOUTLINENAMETABLE lpOutlineNameTable = + (LPOUTLINENAMETABLE)lpServerNameTable; + LPSERVERNAME lpServerName; + int i; + + for(i = 0; i < lpOutlineNameTable->m_nCount; i++) { + lpServerName = (LPSERVERNAME)OutlineNameTable_GetName( + lpOutlineNameTable, + i + ); + ServerName_SendPendingAdvises(lpServerName); + } +} + + +/* ServerNameTable_GetPseudoObj +** ---------------------------- +** +** Return a pointer to a pseudo object identified by an item string +** (lpszItem). if the pseudo object already exists, then return the +** existing object, otherwise allocate a new pseudo object. +*/ +LPPSEUDOOBJ ServerNameTable_GetPseudoObj( + LPSERVERNAMETABLE lpServerNameTable, + LPSTR lpszItem, + LPSERVERDOC lpServerDoc +) +{ + LPSERVERNAME lpServerName; + + lpServerName = (LPSERVERNAME)OutlineNameTable_FindName( + (LPOUTLINENAMETABLE)lpServerNameTable, + lpszItem + ); + + if (lpServerName) + return ServerName_GetPseudoObj(lpServerName, lpServerDoc); + else + return NULL; +} + + +/* ServerNameTable_CloseAllPseudoObjs + * ---------------------------------- + * + * Force all pseudo objects to close. this results in sending OnClose + * notification to each pseudo object's linking clients. + */ +void ServerNameTable_CloseAllPseudoObjs(LPSERVERNAMETABLE lpServerNameTable) +{ + LPOUTLINENAMETABLE lpOutlineNameTable = + (LPOUTLINENAMETABLE)lpServerNameTable; + LPSERVERNAME lpServerName; + int i; + + OLEDBG_BEGIN3("ServerNameTable_CloseAllPseudoObjs\r\n") + + for(i = 0; i < lpOutlineNameTable->m_nCount; i++) { + lpServerName = (LPSERVERNAME)OutlineNameTable_GetName( + lpOutlineNameTable, + i + ); + ServerName_ClosePseudoObj(lpServerName); + } + + OLEDBG_END3 +} + + + +/* ServerName_SetSel + * ----------------- + * + * Change the line range of a name. + */ +void ServerName_SetSel( + LPSERVERNAME lpServerName, + LPLINERANGE lplrSel, + BOOL fRangeModified +) +{ + LPOUTLINENAME lpOutlineName = (LPOUTLINENAME)lpServerName; + BOOL fPseudoObjChanged = fRangeModified; + + if (lpOutlineName->m_nStartLine != lplrSel->m_nStartLine) { + lpOutlineName->m_nStartLine = lplrSel->m_nStartLine; + fPseudoObjChanged = TRUE; + } + + if (lpOutlineName->m_nEndLine != lplrSel->m_nEndLine) { + lpOutlineName->m_nEndLine = lplrSel->m_nEndLine; + fPseudoObjChanged = TRUE; + } + + /* OLE2NOTE: if the range of an active pseudo object has + ** changed, then inform any linking clients that the object + ** has changed. + */ + if (lpServerName->m_lpPseudoObj && fPseudoObjChanged) { + PseudoObj_SendAdvise( + lpServerName->m_lpPseudoObj, + OLE_ONDATACHANGE, + NULL, /* lpmkDoc -- not relevant here */ + 0 /* advf -- no flags necessary */ + ); + } +} + + +/* ServerName_SendPendingAdvises + * ----------------------------- + * + * Send any pending change notifications for the associated + * pseudo objects for this name (if one exists). + * while ReDraw is diabled on the ServerDoc, then change advise + * notifications are not sent to pseudo object clients. + */ +void ServerName_SendPendingAdvises(LPSERVERNAME lpServerName) +{ + if (! lpServerName->m_lpPseudoObj) + return; // no associated pseudo object + + if (lpServerName->m_lpPseudoObj->m_fDataChanged) + PseudoObj_SendAdvise( + lpServerName->m_lpPseudoObj, + OLE_ONDATACHANGE, + NULL, /* lpmkDoc -- not relevant here */ + 0 /* advf -- no flags necessary */ + ); +} + + +/* ServerName_GetPseudoObj +** ----------------------- +** +** Return a pointer to a pseudo object associated to a ServerName. +** if the pseudo object already exists, then return the +** existing object, otherwise allocate a new pseudo object. +** +** NOTE: the PseudoObj is returned with a 0 refcnt if first created, +** else the existing refcnt is unchanged. +*/ +LPPSEUDOOBJ ServerName_GetPseudoObj( + LPSERVERNAME lpServerName, + LPSERVERDOC lpServerDoc +) +{ + // Check if a PseudoObj already exists + if (lpServerName->m_lpPseudoObj) + return lpServerName->m_lpPseudoObj; + + // A PseudoObj does NOT already exist, allocate a new one. + lpServerName->m_lpPseudoObj=(LPPSEUDOOBJ) New((DWORD)sizeof(PSEUDOOBJ)); + if (lpServerName->m_lpPseudoObj == NULL) { + OleDbgAssertSz(lpServerName->m_lpPseudoObj != NULL, "Error allocating PseudoObj"); + return NULL; + } + + PseudoObj_Init(lpServerName->m_lpPseudoObj, lpServerName, lpServerDoc); + return lpServerName->m_lpPseudoObj; +} + + +/* ServerName_ClosePseudoObj + * ------------------------- + * + * if there is an associated pseudo objects for this name (if one + * exists), then close it. this results in sending OnClose + * notification to the pseudo object's linking clients. + */ +void ServerName_ClosePseudoObj(LPSERVERNAME lpServerName) +{ + if (!lpServerName || !lpServerName->m_lpPseudoObj) + return; // no associated pseudo object + + PseudoObj_Close(lpServerName->m_lpPseudoObj); +} + + +#endif // OLE_SERVER + + +#if defined( OLE_CNTR ) + + +/************************************************************************* +** ContainerDoc Supprt Functions Used by Container versions +*************************************************************************/ + + +/* ContainerLine_GetRelMoniker +** --------------------------- +** Retrieve the relative item moniker which identifies the OLE object +** relative to the container document. +** +** Returns NULL if a moniker can NOT be created. +*/ +LPMONIKER ContainerLine_GetRelMoniker( + LPCONTAINERLINE lpContainerLine, + DWORD dwAssign +) +{ + LPMONIKER lpmk = NULL; + + /* OLE2NOTE: we should only give out a moniker for the OLE object + ** if the object is allowed to be linked to from the inside. if + ** so we are allowed to give out a moniker which binds to the + ** running OLE object). if the object is an OLE 2.0 embedded + ** object then it is allowed to be linked to from the inside. if + ** the object is either an OleLink or an OLE 1.0 embedding + ** then it can not be linked to from the inside. + ** if we were a container/server app then we could offer linking + ** to the outside of the object (ie. a pseudo object within our + ** document). we are a container only app that does not support + ** linking to ranges of its data. + */ + + switch (dwAssign) { + + case GETMONIKER_FORCEASSIGN: + + /* Force the assignment of the name. This is called when a + ** Paste Link actually occurs. From now on we want + ** to inform the OLE object that its moniker is + ** assigned and is thus necessary to register itself + ** in the RunningObjectTable. + */ + CreateItemMonikerA( + OLESTDDELIM, lpContainerLine->m_szStgName, &lpmk); + + /* OLE2NOTE: if the OLE object is already loaded and it + ** is being assigned a moniker for the first time, + ** then we need to inform it that it now has a moniker + ** assigned by calling IOleObject::SetMoniker. this + ** will force the OLE object to register in the + ** RunningObjectTable when it enters the running + ** state. if the object is not currently loaded, + ** SetMoniker will be called automatically later when + ** the object is loaded by the function + ** ContainerLine_LoadOleObject. + */ + if (! lpContainerLine->m_fMonikerAssigned) { + + /* we must remember forever more that this object has a + ** moniker assigned. + */ + lpContainerLine->m_fMonikerAssigned = TRUE; + + // we are now dirty and must be saved + OutlineDoc_SetModified( + (LPOUTLINEDOC)lpContainerLine->m_lpDoc, + TRUE, /* fModified */ + FALSE, /* fDataChanged--N/A for container ver. */ + FALSE /* fSizeChanged--N/A for container ver. */ + ); + + if (lpContainerLine->m_lpOleObj) { + OLEDBG_BEGIN2("IOleObject::SetMoniker called\r\n") + lpContainerLine->m_lpOleObj->lpVtbl->SetMoniker( + lpContainerLine->m_lpOleObj, + OLEWHICHMK_OBJREL, + lpmk + ); + OLEDBG_END2 + } + } + break; + + case GETMONIKER_ONLYIFTHERE: + + /* If the OLE object currently has a moniker assigned, + ** then return it. + */ + if (lpContainerLine->m_fMonikerAssigned) { + + CreateItemMonikerA( + OLESTDDELIM, + lpContainerLine->m_szStgName, + &lpmk + ); + + } + break; + + case GETMONIKER_TEMPFORUSER: + + /* Return the moniker that would be used for the OLE + ** object but do NOT force moniker assignment at + ** this point. Since our strategy is to use the + ** storage name of the object as its item name, we + ** can simply create the corresponding ItemMoniker + ** (indepenedent of whether the moniker is currently + ** assigned or not). + */ + CreateItemMonikerA( + OLESTDDELIM, + lpContainerLine->m_szStgName, + &lpmk + ); + + break; + + case GETMONIKER_UNASSIGN: + + lpContainerLine->m_fMonikerAssigned = FALSE; + break; + + } + + return lpmk; +} + + +/* ContainerLine_GetFullMoniker +** ---------------------------- +** Retrieve the full absolute moniker which identifies the OLE object +** in the container document. +** this moniker is created as a composite of the absolute moniker for +** the entire document appended with an item moniker which identifies +** the OLE object relative to the document. +** Returns NULL if a moniker can NOT be created. +*/ +LPMONIKER ContainerLine_GetFullMoniker( + LPCONTAINERLINE lpContainerLine, + DWORD dwAssign +) +{ + LPMONIKER lpmkDoc = NULL; + LPMONIKER lpmkItem = NULL; + LPMONIKER lpmkFull = NULL; + + lpmkDoc = OleDoc_GetFullMoniker( + (LPOLEDOC)lpContainerLine->m_lpDoc, + dwAssign + ); + if (! lpmkDoc) return NULL; + + lpmkItem = ContainerLine_GetRelMoniker(lpContainerLine, dwAssign); + + if (lpmkItem) { + CreateGenericComposite(lpmkDoc, lpmkItem, (LPMONIKER FAR*)&lpmkFull); + OleStdRelease((LPUNKNOWN)lpmkItem); + } + + if (lpmkDoc) + OleStdRelease((LPUNKNOWN)lpmkDoc); + + return lpmkFull; +} + + +/* ContainerDoc_InformAllOleObjectsDocRenamed +** ------------------------------------------ +** Inform all OLE objects that the name of the ContainerDoc has changed. +*/ +void ContainerDoc_InformAllOleObjectsDocRenamed( + LPCONTAINERDOC lpContainerDoc, + LPMONIKER lpmkDoc +) +{ + LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList; + int i; + LPLINE lpLine; + + for (i = 0; i < lpLL->m_nNumLines; i++) { + lpLine=LineList_GetLine(lpLL, i); + + if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) { + LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine; + + /* OLE2NOTE: if the OLE object is already loaded AND the + ** object already has a moniker assigned, then we need + ** to inform it that the moniker of the ContainerDoc has + ** changed. of course, this means the full moniker of + ** the object has changed. to do this we call + ** IOleObject::SetMoniker. this will force the OLE + ** object to re-register in the RunningObjectTable if it + ** is currently in the running state. it is not in the + ** running state, the object handler can make not that + ** the object has a new moniker. if the object is not + ** currently loaded, SetMoniker will be called + ** automatically later when the object is loaded by the + ** function ContainerLine_LoadOleObject. + ** also if the object is a linked object, we always want + ** to call SetMoniker on the link so that in case the + ** link source is contained within our same container, + ** the link source will be tracked. the link rebuilds + ** its absolute moniker if it has a relative moniker. + */ + if (lpContainerLine->m_lpOleObj) { + if (lpContainerLine->m_fMonikerAssigned || + lpContainerLine->m_dwLinkType != 0) { + OLEDBG_BEGIN2("IOleObject::SetMoniker called\r\n") + lpContainerLine->m_lpOleObj->lpVtbl->SetMoniker( + lpContainerLine->m_lpOleObj, + OLEWHICHMK_CONTAINER, + lpmkDoc + ); + OLEDBG_END2 + } + + /* OLE2NOTE: we must call IOleObject::SetHostNames so + ** any open objects can update their window titles. + */ + OLEDBG_BEGIN2("IOleObject::SetHostNames called\r\n") + + CallIOleObjectSetHostNamesA( + lpContainerLine->m_lpOleObj, + APPNAME, + ((LPOUTLINEDOC)lpContainerDoc)->m_lpszDocTitle + ); + + OLEDBG_END2 + } + } + } +} + + +/* ContainerDoc_GetObject +** ---------------------- +** Return a pointer to the desired interface of an object identified +** by an item string (lpszItem). the object returned will be an OLE +** object (either link or embedding). +** +** OLE2NOTE: we must force the object to run because we are +** REQUIRED to return a pointer the OLE object in the +** RUNNING state. +** +** dwSpeedNeeded indicates how long the caller is willing +** to wait for us to get the object: +** BINDSPEED_IMMEDIATE -- only if obj already loaded && IsRunning +** BINDSPEED_MODERATE -- load obj if necessary && if IsRunning +** BINDSPEED_INDEFINITE-- force obj to load and run if necessary +*/ +HRESULT ContainerDoc_GetObjectA( + LPCONTAINERDOC lpContainerDoc, + LPSTR lpszItem, + DWORD dwSpeedNeeded, + REFIID riid, + LPVOID FAR* lplpvObject +) +{ + LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList; + int i; + LPLINE lpLine; + BOOL fMatchFound = FALSE; + DWORD dwStatus; + HRESULT hrErr; + + *lplpvObject = NULL; + + for (i = 0; i < lpLL->m_nNumLines; i++) { + lpLine=LineList_GetLine(lpLL, i); + + if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) { + LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine; + + if (lstrcmp(lpContainerLine->m_szStgName, lpszItem) == 0) { + + fMatchFound = TRUE; // valid item name + + // check if object is loaded. + if (lpContainerLine->m_lpOleObj == NULL) { + + // if BINDSPEED_IMMEDIATE is requested, object must + // ALREADY be loadded. + if (dwSpeedNeeded == BINDSPEED_IMMEDIATE) + return ResultFromScode(MK_E_EXCEEDEDDEADLINE); + + ContainerLine_LoadOleObject(lpContainerLine); + if (! lpContainerLine->m_lpOleObj) + return ResultFromScode(E_OUTOFMEMORY); + } + + /* OLE2NOTE: check if the object is allowed to be linked + ** to from the inside (ie. we are allowed to + ** give out a moniker which binds to the running + ** OLE object). if the object is an OLE + ** 2.0 embedded object then it is allowed to be + ** linked to from the inside. if the object is + ** either an OleLink or an OLE 1.0 embedding + ** then it can not be linked to from the inside. + ** if we were a container/server app then we + ** could offer linking to the outside of the + ** object (ie. a pseudo object within our + ** document). we are a container only app that + ** does not support linking to ranges of its data. + */ + OLEDBG_BEGIN2("IOleObject::GetMiscStatus called\r\n"); + lpContainerLine->m_lpOleObj->lpVtbl->GetMiscStatus( + lpContainerLine->m_lpOleObj, + DVASPECT_CONTENT, /* aspect is not important */ + (LPDWORD)&dwStatus + ); + OLEDBG_END2 + if (dwStatus & OLEMISC_CANTLINKINSIDE) + return ResultFromScode(MK_E_NOOBJECT); + + // check if object is running. + if (! OleIsRunning(lpContainerLine->m_lpOleObj)) { + + // if BINDSPEED_MODERATE is requested, object must + // ALREADY be running. + if (dwSpeedNeeded == BINDSPEED_MODERATE) + return ResultFromScode(MK_E_EXCEEDEDDEADLINE); + + /* OLE2NOTE: we have found a match for the item name. + ** now we must return a pointer to the desired + ** interface on the RUNNING object. we must + ** carefully load the object and initially ask for + ** an interface that we are sure the loaded form of + ** the object supports. if we immediately ask the + ** loaded object for the desired interface, the + ** QueryInterface call might fail if it is an + ** interface that is supported only when the object + ** is running. thus we force the object to load and + ** return its IUnknown*. then we force the object to + ** run, and then finally, we can ask for the + ** actually requested interface. + */ + hrErr = ContainerLine_RunOleObject(lpContainerLine); + if (hrErr != NOERROR) { + return hrErr; + } + } + + // Retrieve the requested interface + *lplpvObject = OleStdQueryInterface( + (LPUNKNOWN)lpContainerLine->m_lpOleObj, riid); + + break; // Match FOUND! + } + } + } + + if (*lplpvObject != NULL) { + return NOERROR; + } else + return (fMatchFound ? ResultFromScode(E_NOINTERFACE) + : ResultFromScode(MK_E_NOOBJECT)); +} + + +HRESULT ContainerDoc_GetObject( + LPCONTAINERDOC lpContainerDoc, + LPOLESTR lpszItem, + DWORD dwSpeedNeeded, + REFIID riid, + LPVOID FAR* lplpvObject +) +{ + CREATESTR(lpsz, lpszItem) + + HRESULT hr = ContainerDoc_GetObjectA(lpContainerDoc, lpsz, dwSpeedNeeded, + riid, lplpvObject); + + FREESTR(lpsz) + + return hr; +} + +/* ContainerDoc_GetObjectStorage +** ----------------------------- +** Return a pointer to the IStorage* used by the object identified +** by an item string (lpszItem). the object identified could be either +** an OLE object (either link or embedding). +*/ +HRESULT ContainerDoc_GetObjectStorageA( + LPCONTAINERDOC lpContainerDoc, + LPSTR lpszItem, + LPSTORAGE FAR* lplpStg +) +{ + LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList; + int i; + LPLINE lpLine; + + *lplpStg = NULL; + + for (i = 0; i < lpLL->m_nNumLines; i++) { + lpLine=LineList_GetLine(lpLL, i); + + if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) { + LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine; + + if (lstrcmp(lpContainerLine->m_szStgName, lpszItem) == 0) { + + *lplpStg = lpContainerLine->m_lpStg; + break; // Match FOUND! + } + } + } + + if (*lplpStg != NULL) { + return NOERROR; + } else + return ResultFromScode(MK_E_NOOBJECT); +} + +HRESULT ContainerDoc_GetObjectStorage( + LPCONTAINERDOC lpContainerDoc, + LPOLESTR lpszItem, + LPSTORAGE FAR* lplpStg +) +{ + CREATESTR(lpsz, lpszItem) + + HRESULT hr = ContainerDoc_GetObjectStorageA(lpContainerDoc, lpsz, lplpStg); + + FREESTR(lpsz) + + return hr; +} + +/* ContainerDoc_IsRunning +** ---------------------- +** Check if the object identified by an item string (lpszItem) is in +** the running state. +** For a container-only app, a check is made if the OLE object +** associated with the item name is running. +*/ +HRESULT ContainerDoc_IsRunningA(LPCONTAINERDOC lpContainerDoc, LPSTR lpszItem) +{ + LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList; + int i; + LPLINE lpLine; + DWORD dwStatus; + + for (i = 0; i < lpLL->m_nNumLines; i++) { + lpLine=LineList_GetLine(lpLL, i); + + if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) { + LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine; + + if (lstrcmp(lpContainerLine->m_szStgName, lpszItem) == 0) { + + /* OLE2NOTE: we have found a match for the item name. + ** now we must check if the OLE object is running. + ** we will load the object if not already loaded. + */ + if (! lpContainerLine->m_lpOleObj) { + ContainerLine_LoadOleObject(lpContainerLine); + if (! lpContainerLine->m_lpOleObj) + return ResultFromScode(E_OUTOFMEMORY); + } + + /* OLE2NOTE: check if the object is allowed to be linked + ** to from the inside (ie. we are allowed to + ** give out a moniker which binds to the running + ** OLE object). if the object is an OLE + ** 2.0 embedded object then it is allowed to be + ** linked to from the inside. if the object is + ** either an OleLink or an OLE 1.0 embedding + ** then it can not be linked to from the inside. + ** if we were a container/server app then we + ** could offer linking to the outside of the + ** object (ie. a pseudo object within our + ** document). we are a container only app that + ** does not support linking to ranges of its data. + */ + OLEDBG_BEGIN2("IOleObject::GetMiscStatus called\r\n") + lpContainerLine->m_lpOleObj->lpVtbl->GetMiscStatus( + lpContainerLine->m_lpOleObj, + DVASPECT_CONTENT, /* aspect is not important */ + (LPDWORD)&dwStatus + ); + OLEDBG_END2 + if (dwStatus & OLEMISC_CANTLINKINSIDE) + return ResultFromScode(MK_E_NOOBJECT); + + if (OleIsRunning(lpContainerLine->m_lpOleObj)) + return NOERROR; + else + return ResultFromScode(S_FALSE); + } + } + } + + // no object was found corresponding to the item name + return ResultFromScode(MK_E_NOOBJECT); +} + +HRESULT ContainerDoc_IsRunning(LPCONTAINERDOC lpContainerDoc, LPOLESTR lpszItem) +{ + CREATESTR(lpsz, lpszItem) + + HRESULT hr = ContainerDoc_IsRunningA(lpContainerDoc, lpsz); + + FREESTR(lpsz) + + return hr; +} + +#endif // OLE_CNTR |