summaryrefslogtreecommitdiffstats
path: root/private/oleutest/letest/outline/linking.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/oleutest/letest/outline/linking.c')
-rw-r--r--private/oleutest/letest/outline/linking.c2157
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