LINKING.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:61k
源码类别:

Windows编程

开发平台:

Visual C++

  1. /*************************************************************************
  2. **
  3. **    OLE 2 Sample Code
  4. **
  5. **    linking.c
  6. **
  7. **    This file contains the major interfaces, methods and related support
  8. **    functions for implementing linking to items. The code
  9. **    contained in this file is used by BOTH the Container and Server
  10. **    (Object) versions of the Outline sample code.
  11. **
  12. **    As a server SVROUTL supports linking to the whole document object
  13. **    (either a file-based document or as an embedded object). It also
  14. **    supports linking to ranges (or PseudoObjects).
  15. **
  16. **    As a container CNTROUTL supports linking to embedded objects.
  17. **    (see file svrpsobj.c for Pseudo Object implementation)
  18. **
  19. **    OleDoc Object
  20. **      exposed interfaces:
  21. **          IPersistFile
  22. **          IOleItemContainer
  23. **          IExternalConnection
  24. **
  25. **    (c) Copyright Microsoft Corp. 1992 - 1997 All Rights Reserved
  26. **
  27. *************************************************************************/
  28. #include "outline.h"
  29. OLEDBGDATA
  30. extern LPOUTLINEAPP             g_lpApp;
  31. /*************************************************************************
  32. ** OleDoc::IPersistFile interface implementation
  33. *************************************************************************/
  34. // IPersistFile::QueryInterface
  35. STDMETHODIMP OleDoc_PFile_QueryInterface(
  36.       LPPERSISTFILE       lpThis,
  37.       REFIID              riid,
  38.       LPVOID FAR*         lplpvObj
  39. )
  40. {
  41.    LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc;
  42.    return OleDoc_QueryInterface(lpOleDoc, riid, lplpvObj);
  43. }
  44. // IPersistFile::AddRef
  45. STDMETHODIMP_(ULONG) OleDoc_PFile_AddRef(LPPERSISTFILE lpThis)
  46. {
  47.    LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc;
  48.    OleDbgAddRefMethod(lpThis, "IPersistFile");
  49.    return OleDoc_AddRef(lpOleDoc);
  50. }
  51. // IPersistFile::Release
  52. STDMETHODIMP_(ULONG) OleDoc_PFile_Release (LPPERSISTFILE lpThis)
  53. {
  54.    LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc;
  55.    OleDbgReleaseMethod(lpThis, "IPersistFile");
  56.    return OleDoc_Release(lpOleDoc);
  57. }
  58. // IPersistFile::GetClassID
  59. STDMETHODIMP OleDoc_PFile_GetClassID (
  60.       LPPERSISTFILE       lpThis,
  61.       CLSID FAR*          lpclsid
  62. )
  63. {
  64.    LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc;
  65.    LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;
  66.    OleDbgOut2("OleDoc_PFile_GetClassIDrn");
  67. #if defined( OLE_SERVER ) && defined( SVR_TREATAS )
  68.    /* NOTE: we must be carefull to return the correct CLSID here.
  69.    **    if we are currently preforming a "TreatAs (aka. ActivateAs)"
  70.    **    operation then we need to return the class of the object
  71.    **    written in the storage of the object. otherwise we would
  72.    **    return our own class id.
  73.    */
  74.    return ServerDoc_GetClassID((LPSERVERDOC)lpOleDoc, lpclsid);
  75. #else
  76.    *lpclsid = CLSID_APP;
  77. #endif
  78.    return NOERROR;
  79. }
  80. // IPersistFile::IsDirty
  81. STDMETHODIMP  OleDoc_PFile_IsDirty(LPPERSISTFILE lpThis)
  82. {
  83.    LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc;
  84.    OleDbgOut2("OleDoc_PFile_IsDirtyrn");
  85.    if (OutlineDoc_IsModified((LPOUTLINEDOC)lpOleDoc))
  86.       return NOERROR;
  87.    else
  88.       return S_FALSE;
  89. }
  90. // IPersistFile::Load
  91. STDMETHODIMP OleDoc_PFile_Load (
  92.       LPPERSISTFILE       lpThis,
  93.       LPCOLESTR           lpszFileName,
  94.       DWORD               grfMode
  95. )
  96. {
  97.    LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc;
  98.    SCODE sc;
  99.    OLEDBG_BEGIN2("OleDoc_PFile_Loadrn")
  100.    /* NOTE: grfMode passed from the caller indicates if the caller
  101.    **    needs Read or ReadWrite permissions. if appropriate the
  102.    **    callee should open the file with the requested permissions.
  103.    **    the caller will normally not impose sharing permissions.
  104.    **
  105.    **    the sample code currently always opens its file ReadWrite.
  106.    */
  107.    if (OutlineDoc_LoadFromFile((LPOUTLINEDOC)lpOleDoc, (LPOLESTR)lpszFileName))
  108.       sc = S_OK;
  109.    else
  110.       sc = E_FAIL;
  111.    OLEDBG_END2
  112.    return sc;
  113. }
  114. // IPersistFile::Save
  115. STDMETHODIMP OleDoc_PFile_Save (
  116.       LPPERSISTFILE       lpThis,
  117.       LPCOLESTR           lpszFileName,
  118.       BOOL                fRemember
  119. )
  120. {
  121.    LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc;
  122.    LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;
  123.    SCODE sc;
  124.    OLEDBG_BEGIN2("OleDoc_PFile_Savern")
  125.    /* NOTE: it is only legal to perform a Save or SaveAs operation
  126.    **    on a file-based document. if the document is an embedded
  127.    **    object then we can not be changed to a file-base object.
  128.    **
  129.    **      fRemember   lpszFileName     Type of Save
  130.    **    ----------------------------------------------
  131.    **        TRUE        NULL           SAVE
  132.    **        TRUE        ! NULL         SAVE AS
  133.    **        FALSE       ! NULL         SAVE COPY AS
  134.    **        FALSE       NULL           ***error***
  135.    */
  136.    if ( (lpszFileName==NULL || (lpszFileName != NULL && fRemember))
  137.          && ((lpOutlineDoc->m_docInitType != DOCTYPE_FROMFILE
  138.             && lpOutlineDoc->m_docInitType != DOCTYPE_NEW)) ) {
  139.       OLEDBG_END2
  140.       return E_INVALIDARG;
  141.    }
  142.    if (OutlineDoc_SaveToFile(
  143.          (LPOUTLINEDOC)lpOleDoc,
  144.          lpszFileName,
  145.          lpOutlineDoc->m_cfSaveFormat,
  146.          fRemember)) {
  147.       sc = S_OK;
  148.    } else
  149.       sc = E_FAIL;
  150.    OLEDBG_END2
  151.    return sc;
  152. }
  153. // IPersistFile::SaveCompleted
  154. STDMETHODIMP OleDoc_PFile_SaveCompleted (
  155.       LPPERSISTFILE       lpThis,
  156.       LPCOLESTR           lpszFileName
  157. )
  158. {
  159.    LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc;
  160.    LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;
  161.    OleDbgOut2("OleDoc_PFile_SaveCompletedrn");
  162.    /* This method is called after IPersistFile::Save is called. during
  163.    **    the period between Save and SaveCompleted the object must
  164.    **    consider itself in NOSCRIBBLE mode (ie. it is NOT allowed to
  165.    **    write to its file. here the object can clear its NOSCRIBBLE
  166.    **    mode flag. the outline app never scribbles to its storage, so
  167.    **    we have nothing to do.
  168.    */
  169.    return NOERROR;
  170. }
  171. // IPersistFile::GetCurFile
  172. STDMETHODIMP OleDoc_PFile_GetCurFile (
  173.       LPPERSISTFILE   lpThis,
  174.       LPOLESTR FAR*   lplpszFileName
  175. )
  176. {
  177.    LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc;
  178.    LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;
  179.    LPMALLOC lpMalloc;
  180.    LPOLESTR lpsz;
  181.    SCODE sc;
  182.    char  szAnsiStr[256];
  183.    OleDbgOut2("OleDoc_PFile_GetCurFilern");
  184.    /* NOTE: we must make sure to set all out ptr parameters to NULL. */
  185.    *lplpszFileName = NULL;
  186.    /*********************************************************************
  187.    ** NOTE: memory returned for the lplpszFileName must be
  188.    **    allocated appropriately using the current registered IMalloc
  189.    **    interface. the allows the ownership of the memory to be
  190.    **    passed to the caller (even if in another process).
  191.    *********************************************************************/
  192.    CoGetMalloc(MEMCTX_TASK, &lpMalloc);
  193.    if (! lpMalloc) {
  194.       return E_FAIL;
  195.    }
  196.    if (lpOutlineDoc->m_docInitType == DOCTYPE_FROMFILE) {
  197.       /* valid filename associated; return file name */
  198.       lpsz = /*(LPOLESTR)*/lpMalloc->lpVtbl->Alloc(
  199.             lpMalloc,
  200.             (OLESTRLEN(lpOutlineDoc->m_szFileName)+1)*sizeof(OLECHAR)
  201.       );
  202.       if (! lpsz) {
  203.          sc = E_OUTOFMEMORY;
  204.          goto error;
  205.       }
  206.       OLESTRCPY(lpsz, /*(LPOLESTR)*/lpOutlineDoc->m_szFileName);
  207.       sc = S_OK;
  208.    } else {
  209.       /* no file associated; return default file name prompt */
  210.       lpsz=/*(LPOLESTR)*/lpMalloc->lpVtbl->Alloc(lpMalloc, (lstrlen(DEFEXTENSION)+3)*sizeof(OLECHAR));
  211.       wsprintf(szAnsiStr, "*.%s", DEFEXTENSION);
  212.       A2W (szAnsiStr, lpsz, OLEUI_CCHPATHMAX);
  213.       sc = S_FALSE;
  214.    }
  215. error:
  216.    OleStdRelease((LPUNKNOWN)lpMalloc);
  217.    *lplpszFileName = lpsz;
  218.    return sc;
  219. }
  220. /*************************************************************************
  221. ** OleDoc::IOleItemContainer interface implementation
  222. *************************************************************************/
  223. // IOleItemContainer::QueryInterface
  224. STDMETHODIMP OleDoc_ItemCont_QueryInterface(
  225.       LPOLEITEMCONTAINER  lpThis,
  226.       REFIID              riid,
  227.       LPVOID FAR*         lplpvObj
  228. )
  229. {
  230.    LPOLEDOC lpOleDoc =
  231.          ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc;
  232.    return OleDoc_QueryInterface(lpOleDoc, riid, lplpvObj);
  233. }
  234. // IOleItemContainer::AddRef
  235. STDMETHODIMP_(ULONG) OleDoc_ItemCont_AddRef(LPOLEITEMCONTAINER lpThis)
  236. {
  237.    LPOLEDOC lpOleDoc =
  238.          ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc;
  239.    OleDbgAddRefMethod(lpThis, "IOleItemContainer");
  240.    return OleDoc_AddRef((LPOLEDOC)lpOleDoc);
  241. }
  242. // IOleItemContainer::Release
  243. STDMETHODIMP_(ULONG) OleDoc_ItemCont_Release(LPOLEITEMCONTAINER lpThis)
  244. {
  245.    LPOLEDOC lpOleDoc =
  246.          ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc;
  247.    OleDbgReleaseMethod(lpThis, "IOleItemContainer");
  248.    return OleDoc_Release((LPOLEDOC)lpOleDoc);
  249. }
  250. // IOleItemContainer::ParseDisplayName
  251. STDMETHODIMP OleDoc_ItemCont_ParseDisplayName(
  252.       LPOLEITEMCONTAINER  lpThis,
  253.       LPBC                lpbc,
  254.       LPOLESTR            lpszDisplayName,
  255.       ULONG FAR*          lpchEaten,
  256.       LPMONIKER FAR*      lplpmkOut
  257. )
  258. {
  259.    LPOLEDOC lpOleDoc =
  260.          ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc;
  261.    OLECHAR szItemName[MAXNAMESIZE];
  262.    LPUNKNOWN lpUnk;
  263.    HRESULT hrErr;
  264.    OleDbgOut2("OleDoc_ItemCont_ParseDisplayNamern");
  265.    /* NOTE: we must make sure to set all out ptr parameters to NULL. */
  266.    *lplpmkOut = NULL;
  267.    *lpchEaten = OleStdGetItemToken(
  268.          lpszDisplayName,
  269.          szItemName,
  270.          MAXNAMESIZE*sizeof(OLECHAR)
  271.    );
  272.    /* NOTE: get a pointer to a running instance of the object. we
  273.    **    should force the object to go running if necessary (even if
  274.    **    this means launching its server EXE). this is the meaining of
  275.    **    BINDSPEED_INDEFINITE. Parsing a Moniker is known to be an
  276.    **    "EXPENSIVE" operation.
  277.    */
  278.    hrErr = OleDoc_ItemCont_GetObject(
  279.          lpThis,
  280.          szItemName,
  281.          BINDSPEED_INDEFINITE,
  282.          lpbc,
  283.          &IID_IUnknown,
  284.          (LPVOID FAR*)&lpUnk
  285.    );
  286.    if (hrErr == NOERROR) {
  287.       OleStdRelease(lpUnk);   // item name FOUND; don't need obj ptr.
  288.       CreateItemMoniker(OLESTR("\"), szItemName, lplpmkOut);
  289.    } else
  290.       *lpchEaten = 0;     // item name is NOT valid
  291.    return hrErr;
  292. }
  293. // IOleItemContainer::EnumObjects
  294. STDMETHODIMP OleDoc_ItemCont_EnumObjects(
  295.       LPOLEITEMCONTAINER  lpThis,
  296.       DWORD               grfFlags,
  297.       LPENUMUNKNOWN FAR*  lplpenumUnknown
  298. )
  299. {
  300.    LPOLEDOC lpOleDoc =
  301.          ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc;
  302.    OLEDBG_BEGIN2("OleDoc_ItemCont_EnumObjectsrn")
  303.    /* NOTE: we must make sure to set all out ptr parameters to NULL. */
  304.    *lplpenumUnknown = NULL;
  305.    /* NOTE: this method should be implemented to allow programatic
  306.    **    clients the ability to what elements the container holds.
  307.    **    this method is NOT called in the standard linking scenarios.
  308.    **
  309.    **    grfFlags can be one of the following:
  310.    **        OLECONTF_EMBEDDINGS   -- enumerate embedded objects
  311.    **        OLECONTF_LINKS        -- enumerate linked objects
  312.    **        OLECONTF_OTHERS       -- enumerate non-OLE compound doc objs
  313.    **        OLECONTF_ONLYUSER     -- enumerate only objs named by user
  314.    **        OLECONTF_ONLYIFRUNNING-- enumerate only objs in running state
  315.    */
  316.    OleDbgAssertSz(0, "NOT YET IMPLEMENTED!");
  317.    OLEDBG_END2
  318.    return E_NOTIMPL;
  319. }
  320. // IOleItemContainer::LockContainer
  321. STDMETHODIMP OleDoc_ItemCont_LockContainer(
  322.       LPOLEITEMCONTAINER  lpThis,
  323.       BOOL                fLock
  324. )
  325. {
  326.    LPOLEDOC lpOleDoc =
  327.          ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc;
  328.    HRESULT hrErr;
  329.    OLEDBG_BEGIN2("OleDoc_ItemCont_LockContainerrn")
  330. #if defined( _DEBUG )
  331.    if (fLock) {
  332.       ++lpOleDoc->m_cCntrLock;
  333.       OleDbgOutRefCnt3(
  334.             "OleDoc_ItemCont_LockContainer: cLock++rn",
  335.             lpOleDoc,
  336.             lpOleDoc->m_cCntrLock
  337.       );
  338.    } else {
  339.       /* NOTE: when there are no open documents and the app is not
  340.       **    under the control of the user and there are no outstanding
  341.       **    locks on the app, then revoke our ClassFactory to enable the
  342.       **    app to shut down.
  343.       */
  344.       --lpOleDoc->m_cCntrLock;
  345.       OleDbgAssertSz (
  346.             lpOleDoc->m_cCntrLock >= 0,
  347.             "OleDoc_ItemCont_LockContainer(FALSE) called with cLock == 0"
  348.       );
  349.       if (lpOleDoc->m_cCntrLock == 0) {
  350.          OleDbgOutRefCnt2(
  351.                "OleDoc_ItemCont_LockContainer: UNLOCKEDrn",
  352.                lpOleDoc, lpOleDoc->m_cCntrLock);
  353.       } else {
  354.          OleDbgOutRefCnt3(
  355.                "OleDoc_ItemCont_LockContainer: cLock--rn",
  356.                lpOleDoc, lpOleDoc->m_cCntrLock);
  357.       }
  358.    }
  359. #endif  // _DEBUG
  360.    /* NOTE: in order to hold the document alive we call
  361.    **    CoLockObjectExternal to add a strong reference to our Doc
  362.    **    object. this will keep the Doc alive when all other external
  363.    **    references release us. whenever an embedded object goes
  364.    **    running a LockContainer(TRUE) is called. when the embedded
  365.    **    object shuts down (ie. transitions from running to loaded)
  366.    **    LockContainer(FALSE) is called. if the user issues File.Close
  367.    **    the document will shut down in any case ignoring any
  368.    **    outstanding LockContainer locks because CoDisconnectObject is
  369.    **    called in OleDoc_Close. this will forceably break any
  370.    **    existing strong reference counts including counts that we add
  371.    **    ourselves by calling CoLockObjectExternal and guarantee that
  372.    **    the Doc object gets its final release (ie. cRefs goes to 0).
  373.    */
  374.    hrErr = OleDoc_Lock(lpOleDoc, fLock, TRUE /* fLastUnlockReleases */);
  375.    OLEDBG_END2
  376.    return hrErr;
  377. }
  378. // IOleItemContainer::GetObject
  379. STDMETHODIMP OleDoc_ItemCont_GetObject(
  380.       LPOLEITEMCONTAINER  lpThis,
  381.       LPOLESTR            lpszItem,
  382.       DWORD               dwSpeedNeeded,
  383.       LPBINDCTX           lpbc,
  384.       REFIID              riid,
  385.       LPVOID FAR*         lplpvObject
  386. )
  387. {
  388.    LPOLEDOC lpOleDoc =
  389.          ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc;
  390.    HRESULT hrErr;
  391.    OLEDBG_BEGIN2("OleDoc_ItemCont_GetObjectrn")
  392.    /* NOTE: we must make sure to set all out ptr parameters to NULL. */
  393.    *lplpvObject = NULL;
  394. #if defined( OLE_SERVER )
  395.    /* NOTE: SERVER ONLY version should return PseudoObjects with
  396.    **    BINDSPEED_IMMEDIATE, thus the dwSpeedNeeded is not important
  397.    **    in the case of a pure server.
  398.    */
  399.    hrErr = ServerDoc_GetObject(
  400.          (LPSERVERDOC)lpOleDoc, lpszItem,riid,lplpvObject);
  401. #endif
  402. #if defined( OLE_CNTR )
  403.    /* NOTE: dwSpeedNeeded indicates how long the caller is willing
  404.    **    to wait for us to get the object:
  405.    **      BINDSPEED_IMMEDIATE -- only if obj already loaded && IsRunning
  406.    **      BINDSPEED_MODERATE  -- load obj if necessary && if IsRunning
  407.    **      BINDSPEED_INDEFINITE-- force obj to load and run if necessary
  408.    */
  409.    hrErr = ContainerDoc_GetObject(
  410.          (LPCONTAINERDOC)lpOleDoc,lpszItem,dwSpeedNeeded,riid,lplpvObject);
  411. #endif
  412.    OLEDBG_END2
  413.    return hrErr;
  414. }
  415. // IOleItemContainer::GetObjectStorage
  416. STDMETHODIMP OleDoc_ItemCont_GetObjectStorage(
  417.       LPOLEITEMCONTAINER  lpThis,
  418.       LPOLESTR            lpszItem,
  419.       LPBINDCTX           lpbc,
  420.       REFIID              riid,
  421.       LPVOID FAR*         lplpvStorage
  422. )
  423. {
  424.    LPOLEDOC lpOleDoc =
  425.          ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc;
  426.    OleDbgOut2("OleDoc_ItemCont_GetObjectStoragern");
  427.    /* NOTE: we must make sure to set all out ptr parameters to NULL. */
  428.    *lplpvStorage = NULL;
  429. #if defined( OLE_SERVER )
  430.    /* NOTE: in the SERVER ONLY version, item names identify pseudo
  431.    **    objects. pseudo objects, do NOT have identifiable storage.
  432.    */
  433.    return E_FAIL;
  434. #endif
  435. #if defined( OLE_CNTR )
  436.    // We can only return an IStorage* type pointer
  437.    if (! IsEqualIID(riid, &IID_IStorage))
  438.    {
  439.       return E_FAIL;
  440.    }
  441.    return ContainerDoc_GetObjectStorage(
  442.          (LPCONTAINERDOC)lpOleDoc,
  443.          lpszItem,
  444.          (LPSTORAGE FAR*)lplpvStorage
  445.    );
  446. #endif
  447. }
  448. // IOleItemContainer::IsRunning
  449. STDMETHODIMP OleDoc_ItemCont_IsRunning(
  450.       LPOLEITEMCONTAINER  lpThis,
  451.       LPOLESTR            lpszItem
  452. )
  453. {
  454.    LPOLEDOC lpOleDoc =
  455.          ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc;
  456.    HRESULT hrErr;
  457.    OLEDBG_BEGIN2("OleDoc_ItemCont_IsRunningrn")
  458.    /* NOTE: Check if item name is valid. if so then return if
  459.    **    Object is running. PseudoObjects in the Server version are
  460.    **    always considered running. Ole objects in the container must
  461.    **    be checked if they are running.
  462.    */
  463. #if defined( OLE_SERVER )
  464.    hrErr = ServerDoc_IsRunning((LPSERVERDOC)lpOleDoc, lpszItem);
  465. #endif
  466. #if defined( OLE_CNTR )
  467.    hrErr = ContainerDoc_IsRunning((LPCONTAINERDOC)lpOleDoc, lpszItem);
  468. #endif
  469.    OLEDBG_END2
  470.    return hrErr;
  471. }
  472. /*************************************************************************
  473. ** OleDoc::IExternalConnection interface implementation
  474. *************************************************************************/
  475. // IExternalConnection::QueryInterface
  476. STDMETHODIMP OleDoc_ExtConn_QueryInterface(
  477.       LPEXTERNALCONNECTION    lpThis,
  478.       REFIID                  riid,
  479.       LPVOID FAR*             lplpvObj
  480. )
  481. {
  482.    LPOLEDOC lpOleDoc =
  483.          ((struct CDocExternalConnectionImpl FAR*)lpThis)->lpOleDoc;
  484.    return OleDoc_QueryInterface(lpOleDoc, riid, lplpvObj);
  485. }
  486. // IExternalConnection::AddRef
  487. STDMETHODIMP_(ULONG) OleDoc_ExtConn_AddRef(LPEXTERNALCONNECTION lpThis)
  488. {
  489.    LPOLEDOC lpOleDoc =
  490.          ((struct CDocExternalConnectionImpl FAR*)lpThis)->lpOleDoc;
  491.    OleDbgAddRefMethod(lpThis, "IExternalConnection");
  492.    return OleDoc_AddRef(lpOleDoc);
  493. }
  494. // IExternalConnection::Release
  495. STDMETHODIMP_(ULONG) OleDoc_ExtConn_Release (LPEXTERNALCONNECTION lpThis)
  496. {
  497.    LPOLEDOC lpOleDoc =
  498.          ((struct CDocExternalConnectionImpl FAR*)lpThis)->lpOleDoc;
  499.    OleDbgReleaseMethod(lpThis, "IExternalConnection");
  500.    return OleDoc_Release(lpOleDoc);
  501. }
  502. // IExternalConnection::AddConnection
  503. STDMETHODIMP_(DWORD) OleDoc_ExtConn_AddConnection(
  504.       LPEXTERNALCONNECTION    lpThis,
  505.       DWORD                   extconn,
  506.       DWORD                   reserved
  507. )
  508. {
  509.    LPOLEDOC lpOleDoc =
  510.          ((struct CDocExternalConnectionImpl FAR*)lpThis)->lpOleDoc;
  511.    if( extconn & EXTCONN_STRONG ) {
  512. #if defined( _DEBUG )
  513.       OleDbgOutRefCnt3(
  514.             "OleDoc_ExtConn_AddConnection: dwStrongExtConn++rn",
  515.             lpOleDoc,
  516.             lpOleDoc->m_dwStrongExtConn + 1
  517.       );
  518. #endif
  519.       return ++(lpOleDoc->m_dwStrongExtConn);
  520.    } else
  521.    {
  522.       return 0;
  523.    }
  524. }
  525. // IExternalConnection::ReleaseConnection
  526. STDMETHODIMP_(DWORD) OleDoc_ExtConn_ReleaseConnection(
  527.       LPEXTERNALCONNECTION    lpThis,
  528.       DWORD                   extconn,
  529.       DWORD                   reserved,
  530.       BOOL                    fLastReleaseCloses
  531. )
  532. {
  533.    LPOLEDOC lpOleDoc =
  534.          ((struct CDocExternalConnectionImpl FAR*)lpThis)->lpOleDoc;
  535.    if( extconn & EXTCONN_STRONG ){
  536.       DWORD dwSave = --(lpOleDoc->m_dwStrongExtConn);
  537. #if defined( _DEBUG )
  538.       OLEDBG_BEGIN2( (fLastReleaseCloses ?
  539.                   "OleDoc_ExtConn_ReleaseConnection(TRUE)rn" :
  540.                   "OleDoc_ExtConn_ReleaseConnection(FALSE)rn") )
  541.       OleDbgOutRefCnt3(
  542.             "OleDoc_ExtConn_ReleaseConnection: dwStrongExtConn--rn",
  543.             lpOleDoc,
  544.             lpOleDoc->m_dwStrongExtConn
  545.       );
  546.       OleDbgAssertSz (
  547.             lpOleDoc->m_dwStrongExtConn >= 0,
  548.             "OleDoc_ExtConn_ReleaseConnection called with dwStrong == 0"
  549.       );
  550. #endif  // _DEBUG
  551.       if( lpOleDoc->m_dwStrongExtConn == 0 && fLastReleaseCloses )
  552.          OleDoc_Close(lpOleDoc, OLECLOSE_SAVEIFDIRTY);
  553.       OLEDBG_END2
  554.       return dwSave;
  555.    } else
  556.    {
  557.       return 0;
  558.    }
  559. }
  560. /*************************************************************************
  561. ** OleDoc Common Support Functions
  562. *************************************************************************/
  563. /* OleDoc_GetFullMoniker
  564. ** ---------------------
  565. **    Return the full, absolute moniker of the document.
  566. **
  567. **    NOTE: the caller must release the pointer returned when done.
  568. */
  569. LPMONIKER OleDoc_GetFullMoniker(LPOLEDOC lpOleDoc, DWORD dwAssign)
  570. {
  571.    LPMONIKER lpMoniker = NULL;
  572.    OLEDBG_BEGIN3("OleDoc_GetFullMonikerrn")
  573.    if (lpOleDoc->m_lpSrcDocOfCopy) {
  574.       /* CASE I: this document was created for a copy or drag/drop
  575.       **    operation. generate the moniker which identifies the
  576.       **    source document of the original copy.
  577.       */
  578.       if (! lpOleDoc->m_fLinkSourceAvail)
  579.          goto done;        // we already know a moniker is not available
  580.       lpMoniker=OleDoc_GetFullMoniker(lpOleDoc->m_lpSrcDocOfCopy, dwAssign);
  581.    }
  582.    else if (lpOleDoc->m_lpFileMoniker) {
  583.       /* CASE II: this document is a top-level user document (either
  584.       **    file-based or untitled). return the FileMoniker stored
  585.       **    with the document; it uniquely identifies the document.
  586.       */
  587.       // we must AddRef the moniker to pass out a ptr
  588.       lpOleDoc->m_lpFileMoniker->lpVtbl->AddRef(lpOleDoc->m_lpFileMoniker);
  589.       lpMoniker = lpOleDoc->m_lpFileMoniker;
  590.    }
  591. #if defined( OLE_SERVER )
  592.    else if (((LPSERVERDOC)lpOleDoc)->m_lpOleClientSite) {
  593.       /* CASE III: this document is an embedded object, ask our
  594.       **    container for our moniker.
  595.       */
  596.       OLEDBG_BEGIN2("IOleClientSite::GetMoniker calledrn");
  597.       ((LPSERVERDOC)lpOleDoc)->m_lpOleClientSite->lpVtbl->GetMoniker(
  598.             ((LPSERVERDOC)lpOleDoc)->m_lpOleClientSite,
  599.             dwAssign,
  600.             OLEWHICHMK_OBJFULL,
  601.             &lpMoniker
  602.       );
  603.       OLEDBG_END2
  604.    }
  605. #endif
  606.    else {
  607.       lpMoniker = NULL;
  608.    }
  609. done:
  610.    OLEDBG_END3
  611.    return lpMoniker;
  612. }
  613. /* OleDoc_DocRenamedUpdate
  614. ** -----------------------
  615. **    Update the documents registration in the running object table (ROT).
  616. **    Also inform all embedded OLE objects (container only) and/or psedudo
  617. **    objects (server only) that the name of the document has changed.
  618. */
  619. void OleDoc_DocRenamedUpdate(LPOLEDOC lpOleDoc, LPMONIKER lpmkDoc)
  620. {
  621.    OLEDBG_BEGIN3("OleDoc_DocRenamedUpdatern")
  622.    OleDoc_AddRef(lpOleDoc);
  623.    /* NOTE: we must re-register ourselves as running when we
  624.    **    get a new moniker assigned (ie. when we are renamed).
  625.    */
  626.    OLEDBG_BEGIN3("OleStdRegisterAsRunning calledrn")
  627.    OleStdRegisterAsRunning(
  628.          (LPUNKNOWN)&lpOleDoc->m_Unknown,
  629.          lpmkDoc,
  630.          &lpOleDoc->m_dwRegROT
  631.    );
  632.    OLEDBG_END3
  633. #if defined( OLE_SERVER )
  634.    {
  635.       LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOleDoc;
  636.       LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;
  637.       /* NOTE: inform any linking clients that the document has been
  638.       **    renamed.
  639.       */
  640.       ServerDoc_SendAdvise (
  641.             lpServerDoc,
  642.             OLE_ONRENAME,
  643.             lpmkDoc,
  644.             0        /* advf -- not relevant here */
  645.       );
  646.       /* NOTE: inform any clients of pseudo objects
  647.       **    within our document, that our document's
  648.       **    Moniker has changed.
  649.       */
  650.       ServerNameTable_InformAllPseudoObjectsDocRenamed(
  651.             (LPSERVERNAMETABLE)lpOutlineDoc->m_lpNameTable, lpmkDoc);
  652.    }
  653. #endif
  654. #if defined( OLE_CNTR )
  655.    {
  656.       LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOleDoc;
  657.       /* NOTE: must tell all OLE objects that our container
  658.       **    moniker changed.
  659.       */
  660.       ContainerDoc_InformAllOleObjectsDocRenamed(
  661.             lpContainerDoc,
  662.             lpmkDoc
  663.       );
  664.    }
  665. #endif
  666.    OleDoc_Release(lpOleDoc);       // release artificial AddRef above
  667.    OLEDBG_END3
  668. }
  669. #if defined( OLE_SERVER )
  670. /*************************************************************************
  671. ** ServerDoc Supprt Functions Used by Server versions
  672. *************************************************************************/
  673. /* ServerDoc_PseudoObjLockDoc
  674. ** --------------------------
  675. **    Add a lock on the Doc on behalf of the PseudoObject. the Doc may not
  676. **    close while the Doc exists.
  677. **
  678. **    when a pseudo object is first created, it calls this method to
  679. **    guarantee that the document stays alive (PseudoObj_Init).
  680. **    when a pseudo object is destroyed, it call
  681. **    ServerDoc_PseudoObjUnlockDoc to release this hold on the document.
  682. */
  683. void ServerDoc_PseudoObjLockDoc(LPSERVERDOC lpServerDoc)
  684. {
  685.    LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc;
  686.    ULONG cPseudoObj;
  687.    cPseudoObj = ++lpServerDoc->m_cPseudoObj;
  688. #if defined( _DEBUG )
  689.    OleDbgOutRefCnt3(
  690.          "ServerDoc_PseudoObjLockDoc: cPseudoObj++rn",
  691.          lpServerDoc,
  692.          cPseudoObj
  693.    );
  694. #endif
  695.    OleDoc_Lock(lpOleDoc, TRUE /* fLock */, 0 /* not applicable */);
  696.    return;
  697. }
  698. /* ServerDoc_PseudoObjUnlockDoc
  699. ** ----------------------------
  700. **    Release the lock on the Doc on behalf of the PseudoObject. if this was
  701. **    the last lock on the Doc, then it will shutdown.
  702. */
  703. void ServerDoc_PseudoObjUnlockDoc(
  704.       LPSERVERDOC         lpServerDoc,
  705.       LPPSEUDOOBJ         lpPseudoObj
  706. )
  707. {
  708.    ULONG cPseudoObj;
  709.    LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc;
  710.    OLEDBG_BEGIN3("ServerDoc_PseudoObjUnlockDocrn")
  711.    /* NOTE: when there are no active pseudo objects in the Doc and
  712.    **    the Doc is not visible, and if there are no outstanding locks
  713.    **    on the Doc, then this is a "silent update"
  714.    **    situation. our Doc is being used programatically by some
  715.    **    client; it is NOT accessible to the user because it is
  716.    **    NOT visible. thus since all Locks have been released, we
  717.    **    will close the document. if the app is only running due
  718.    **    to the presence of this document, then the app will now
  719.    **    also shut down.
  720.    */
  721.    cPseudoObj = --lpServerDoc->m_cPseudoObj;
  722. #if defined( _DEBUG )
  723.    OleDbgAssertSz (
  724.          lpServerDoc->m_cPseudoObj >= 0,
  725.          "PseudoObjUnlockDoc called with cPseudoObj == 0"
  726.    );
  727.    OleDbgOutRefCnt3(
  728.          "ServerDoc_PseudoObjUnlockDoc: cPseudoObj--rn",
  729.          lpServerDoc,
  730.          cPseudoObj
  731.    );
  732. #endif
  733.    OleDoc_Lock(lpOleDoc, FALSE /* fLock */, TRUE /* fLastUnlockReleases */);
  734.    OLEDBG_END3
  735.    return;
  736. }
  737. /* ServerDoc_GetObject
  738. ** -------------------
  739. **
  740. **    Return a pointer to an object identified by an item string
  741. **    (lpszItem). For a server-only app, the object returned will be a
  742. **    pseudo object.
  743. */
  744. HRESULT ServerDoc_GetObject(
  745.       LPSERVERDOC             lpServerDoc,
  746.       LPOLESTR                lpszItem,
  747.       REFIID                  riid,
  748.       LPVOID FAR*             lplpvObject
  749. )
  750. {
  751.    LPPSEUDOOBJ lpPseudoObj;
  752.    LPSERVERNAMETABLE lpServerNameTable =
  753.          (LPSERVERNAMETABLE)((LPOUTLINEDOC)lpServerDoc)->m_lpNameTable;
  754.    *lplpvObject = NULL;
  755.    /* Get the PseudoObj which corresponds to an item name. if the item
  756.    **    name does NOT exist in the name table then NO object is
  757.    **    returned. the ServerNameTable_GetPseudoObj routine finds a
  758.    **    name entry corresponding to the item name, it then checks if
  759.    **    a PseudoObj has already been allocated. if so, it returns the
  760.    **    existing object, otherwise it allocates a new PseudoObj.
  761.    */
  762.    lpPseudoObj = ServerNameTable_GetPseudoObj(
  763.          lpServerNameTable,
  764.          lpszItem,
  765.          lpServerDoc
  766.    );
  767.    if (! lpPseudoObj) {
  768.       *lplpvObject = NULL;
  769.       return MK_E_NOOBJECT;
  770.    }
  771.    // return the desired interface pointer of the pseudo object.
  772.    return PseudoObj_QueryInterface(lpPseudoObj, riid, lplpvObject);
  773. }
  774. /* ServerDoc_IsRunning
  775. ** -------------------
  776. **
  777. **    Check if the object identified by an item string (lpszItem) is in
  778. **    the running state. For a server-only app, if the item name exists in
  779. **    in the NameTable then the item name is considered running.
  780. **    IOleItemContainer::GetObject would succeed.
  781. */
  782. HRESULT ServerDoc_IsRunning(LPSERVERDOC lpServerDoc, LPOLESTR lpszItem)
  783. {
  784.    LPOUTLINENAMETABLE lpOutlineNameTable =
  785.          ((LPOUTLINEDOC)lpServerDoc)->m_lpNameTable;
  786.    LPSERVERNAME lpServerName;
  787.    lpServerName = (LPSERVERNAME)OutlineNameTable_FindName(
  788.          lpOutlineNameTable,
  789.          lpszItem
  790.    );
  791.    if (lpServerName)
  792.       return NOERROR;
  793.    else
  794.       return MK_E_NOOBJECT;
  795. }
  796. /* ServerDoc_GetSelRelMoniker
  797. ** --------------------------
  798. **    Retrieve the relative item moniker which identifies the given
  799. **    selection (lplrSel).
  800. **
  801. **    Returns NULL if a moniker can NOT be created.
  802. */
  803. LPMONIKER ServerDoc_GetSelRelMoniker(
  804.       LPSERVERDOC             lpServerDoc,
  805.       LPLINERANGE             lplrSel,
  806.       DWORD                   dwAssign
  807. )
  808. {
  809.    LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
  810.    LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;
  811.    LPSERVERNAMETABLE lpServerNameTable =
  812.          (LPSERVERNAMETABLE)lpOutlineDoc->m_lpNameTable;
  813.    LPOUTLINENAMETABLE lpOutlineNameTable =
  814.          (LPOUTLINENAMETABLE)lpServerNameTable;
  815.    LPOUTLINENAME lpOutlineName;
  816.    LPMONIKER lpmk;
  817.    lpOutlineName=OutlineNameTable_FindNamedRange(lpOutlineNameTable,lplrSel);
  818.    if (lpOutlineName) {
  819.       /* the selection range already has a name assigned */
  820.       CreateItemMoniker(OLESTR("\"), lpOutlineName->m_szName, &lpmk);
  821.    } else {
  822.       char szbuf[MAXNAMESIZE];
  823.       OLECHAR szUniBuf[MAXNAMESIZE];
  824.       switch (dwAssign) {
  825.          case GETMONIKER_FORCEASSIGN:
  826.             /* Force the assignment of the name. This is called when a
  827.             **    Paste Link actually occurs. At this point we want to
  828.             **    create a Name and add it to the NameTable in order to
  829.             **    track the source of the link. This name (as all
  830.             **    names) will be updated upon editing of the document.
  831.             */
  832.             wsprintf(
  833.                   szbuf,
  834.                   "%s %ld",
  835.                   (LPSTR)DEFRANGENAMEPREFIX,
  836.                   ++(lpServerDoc->m_nNextRangeNo)
  837.             );
  838.             lpOutlineName = OutlineApp_CreateName(lpOutlineApp);
  839.             if (lpOutlineName) {
  840.                A2W (szbuf, lpOutlineName->m_szName, OLEUI_CCHPATHMAX);
  841.                lpOutlineName->m_nStartLine = lplrSel->m_nStartLine;
  842.                lpOutlineName->m_nEndLine = lplrSel->m_nEndLine;
  843.                OutlineDoc_AddName(lpOutlineDoc, lpOutlineName);
  844.             } else {
  845.                // REVIEW: do we need "Out-of-Memory" error message here?
  846.             }
  847.             break;
  848.          case GETMONIKER_TEMPFORUSER:
  849.             /* Create a name to show to the user in the Paste
  850.             **    Special dialog but do NOT yet incur the overhead
  851.             **    of adding a Name to the NameTable. The Moniker
  852.             **    generated should be useful to display to the user
  853.             **    to indicate the source of the copy, but will NOT
  854.             **    be used to create a link directly (the caller
  855.             **    should ask again for a moniker specifying FORCEASSIGN).
  856.             **    we will generate the name that would be the next
  857.             **    auto-generated range name, BUT will NOT actually
  858.             **    increment the range counter.
  859.             */
  860.             wsprintf(
  861.                   szbuf,
  862.                   "%s %ld",
  863.                   (LPSTR)DEFRANGENAMEPREFIX,
  864.                   (lpServerDoc->m_nNextRangeNo)+1
  865.             );
  866.             break;
  867.          case GETMONIKER_ONLYIFTHERE:
  868.             /* the caller only wants a name if one has already been
  869.             **    assigned. we have already above checked if the
  870.             **    current selection has a name, so we will simply
  871.             **    return NULL here.
  872.             */
  873.             return NULL;    // no moniker is assigned
  874.          default:
  875.             return NULL;    // unknown flag given
  876.       }
  877.       A2W (szbuf, szUniBuf, MAXNAMESIZE);
  878.       CreateItemMoniker(OLESTR("\"), szUniBuf, &lpmk);
  879.    }
  880.    return lpmk;
  881. }
  882. /* ServerDoc_GetSelFullMoniker
  883. ** ---------------------------
  884. **    Retrieve the full absolute moniker which identifies the given
  885. **    selection (lplrSel).
  886. **    this moniker is created as a composite of the absolute moniker for
  887. **    the entire document appended with an item moniker which identifies
  888. **    the selection relative to the document.
  889. **    Returns NULL if a moniker can NOT be created.
  890. */
  891. LPMONIKER ServerDoc_GetSelFullMoniker(
  892.       LPSERVERDOC             lpServerDoc,
  893.       LPLINERANGE             lplrSel,
  894.       DWORD                   dwAssign
  895. )
  896. {
  897.    LPMONIKER lpmkDoc = NULL;
  898.    LPMONIKER lpmkItem = NULL;
  899.    LPMONIKER lpmkFull = NULL;
  900.    lpmkDoc = OleDoc_GetFullMoniker(
  901.          (LPOLEDOC)lpServerDoc,
  902.          dwAssign
  903.    );
  904.    if (! lpmkDoc) return NULL;
  905.    lpmkItem = ServerDoc_GetSelRelMoniker(
  906.          lpServerDoc,
  907.          lplrSel,
  908.          dwAssign
  909.    );
  910.    if (lpmkItem) {
  911.       CreateGenericComposite(lpmkDoc, lpmkItem, (LPMONIKER FAR*)&lpmkFull);
  912.       OleStdRelease((LPUNKNOWN)lpmkItem);
  913.    }
  914.    if (lpmkDoc)
  915.       OleStdRelease((LPUNKNOWN)lpmkDoc);
  916.    return lpmkFull;
  917. }
  918. /* ServerNameTable_EditLineUpdate
  919.  * -------------------------------
  920.  *
  921.  *      Update the table when a line at nEditIndex is edited.
  922.  */
  923. void ServerNameTable_EditLineUpdate(
  924.       LPSERVERNAMETABLE       lpServerNameTable,
  925.       int                     nEditIndex
  926. )
  927. {
  928.    LPOUTLINENAMETABLE lpOutlineNameTable =
  929.                               (LPOUTLINENAMETABLE)lpServerNameTable;
  930.    LPOUTLINENAME lpOutlineName;
  931.    LINERANGE lrSel;
  932.    LPPSEUDOOBJ lpPseudoObj;
  933.    int i;
  934.    for(i = 0; i < lpOutlineNameTable->m_nCount; i++) {
  935.       lpOutlineName=OutlineNameTable_GetName(lpOutlineNameTable, i);
  936.       lpPseudoObj = ((LPSERVERNAME)lpOutlineName)->m_lpPseudoObj;
  937.       /* if there is a pseudo object associated with this name, then
  938.       **    check if the line that was modified is included within
  939.       **    the named range.
  940.       */
  941.       if (lpPseudoObj) {
  942.          OutlineName_GetSel(lpOutlineName, &lrSel);
  943.          if(((int)lrSel.m_nStartLine <= nEditIndex) &&
  944.             ((int)lrSel.m_nEndLine >= nEditIndex)) {
  945.             // inform linking clients data has changed
  946.             PseudoObj_SendAdvise(
  947.                   lpPseudoObj,
  948.                   OLE_ONDATACHANGE,
  949.                   NULL,   /* lpmkDoc -- not relevant here */
  950.                   0       /* advf -- no flags necessary */
  951.             );
  952.          }
  953.       }
  954.    }
  955. }
  956. /* ServerNameTable_InformAllPseudoObjectsDocRenamed
  957.  * ------------------------------------------------
  958.  *
  959.  *      Inform all pseudo object clients that the name of the pseudo
  960.  *      object has changed.
  961.  */
  962. void ServerNameTable_InformAllPseudoObjectsDocRenamed(
  963.       LPSERVERNAMETABLE       lpServerNameTable,
  964.       LPMONIKER               lpmkDoc
  965. )
  966. {
  967.    LPOUTLINENAMETABLE lpOutlineNameTable =
  968.                               (LPOUTLINENAMETABLE)lpServerNameTable;
  969.    LPOUTLINENAME lpOutlineName;
  970.    LPPSEUDOOBJ lpPseudoObj;
  971.    LPMONIKER lpmkObj;
  972.    int i;
  973.    OLEDBG_BEGIN2("ServerNameTable_InformAllPseudoObjectsDocRenamedrn");
  974.    for(i = 0; i < lpOutlineNameTable->m_nCount; i++) {
  975.       lpOutlineName=OutlineNameTable_GetName(lpOutlineNameTable, i);
  976.       lpPseudoObj = ((LPSERVERNAME)lpOutlineName)->m_lpPseudoObj;
  977.       /* if there is a pseudo object associated with this name, then
  978.       **    send OnRename advise to its linking clients.
  979.       */
  980.       if (lpPseudoObj &&
  981.          ((lpmkObj=PseudoObj_GetFullMoniker(lpPseudoObj,lpmkDoc))!=NULL)) {
  982.          // inform the clients that the name has changed
  983.          PseudoObj_SendAdvise (
  984.                lpPseudoObj,
  985.                OLE_ONRENAME,
  986.                lpmkObj,
  987.                0           /* advf -- not relevant here */
  988.          );
  989.       }
  990.    }
  991.    OLEDBG_END2
  992. }
  993. /* ServerNameTable_InformAllPseudoObjectsDocSaved
  994.  * ------------------------------------------------
  995.  *
  996.  *      Inform all pseudo object clients that the name of the pseudo
  997.  *      object has changed.
  998.  */
  999. void ServerNameTable_InformAllPseudoObjectsDocSaved(
  1000.       LPSERVERNAMETABLE       lpServerNameTable,
  1001.       LPMONIKER               lpmkDoc
  1002. )
  1003. {
  1004.    LPOUTLINENAMETABLE lpOutlineNameTable =
  1005.                               (LPOUTLINENAMETABLE)lpServerNameTable;
  1006.    LPOUTLINENAME lpOutlineName;
  1007.    LPPSEUDOOBJ lpPseudoObj;
  1008.    LPMONIKER lpmkObj;
  1009.    int i;
  1010.    OLEDBG_BEGIN2("ServerNameTable_InformAllPseudoObjectsDocSavedrn");
  1011.    for(i = 0; i < lpOutlineNameTable->m_nCount; i++) {
  1012.       lpOutlineName=OutlineNameTable_GetName(lpOutlineNameTable, i);
  1013.       lpPseudoObj = ((LPSERVERNAME)lpOutlineName)->m_lpPseudoObj;
  1014.       /* if there is a pseudo object associated with this name, then
  1015.       **    send OnSave advise to its linking clients.
  1016.       */
  1017.       if (lpPseudoObj &&
  1018.          ((lpmkObj=PseudoObj_GetFullMoniker(lpPseudoObj,lpmkDoc))!=NULL)) {
  1019.          // inform the clients that the name has been saved
  1020.          PseudoObj_SendAdvise (
  1021.                lpPseudoObj,
  1022.                OLE_ONSAVE,
  1023.                NULL,   /* lpmkDoc -- not relevant here */
  1024.                0       /* advf -- not relevant here */
  1025.          );
  1026.       }
  1027.    }
  1028.    OLEDBG_END2
  1029. }
  1030. /* ServerNameTable_SendPendingAdvises
  1031.  * ----------------------------------
  1032.  *
  1033.  *      Send any pending change notifications for pseudo objects.
  1034.  *  while ReDraw is diabled on the ServerDoc, then change advise
  1035.  *  notifications are not sent to pseudo object clients.
  1036.  */
  1037. void ServerNameTable_SendPendingAdvises(LPSERVERNAMETABLE lpServerNameTable)
  1038. {
  1039.    LPOUTLINENAMETABLE lpOutlineNameTable =
  1040.                               (LPOUTLINENAMETABLE)lpServerNameTable;
  1041.    LPSERVERNAME lpServerName;
  1042.    int i;
  1043.    for(i = 0; i < lpOutlineNameTable->m_nCount; i++) {
  1044.       lpServerName = (LPSERVERNAME)OutlineNameTable_GetName(
  1045.             lpOutlineNameTable,
  1046.             i
  1047.       );
  1048.       ServerName_SendPendingAdvises(lpServerName);
  1049.    }
  1050. }
  1051. /* ServerNameTable_GetPseudoObj
  1052. ** ----------------------------
  1053. **
  1054. **    Return a pointer to a pseudo object identified by an item string
  1055. **    (lpszItem). if the pseudo object already exists, then return the
  1056. **    existing object, otherwise allocate a new pseudo object.
  1057. */
  1058. LPPSEUDOOBJ ServerNameTable_GetPseudoObj(
  1059.       LPSERVERNAMETABLE       lpServerNameTable,
  1060.       LPOLESTR                lpszItem,
  1061.       LPSERVERDOC             lpServerDoc
  1062. )
  1063. {
  1064.    LPSERVERNAME lpServerName;
  1065.    lpServerName = (LPSERVERNAME)OutlineNameTable_FindName(
  1066.          (LPOUTLINENAMETABLE)lpServerNameTable,
  1067.          lpszItem
  1068.    );
  1069.    if (lpServerName)
  1070.       return ServerName_GetPseudoObj(lpServerName, lpServerDoc);
  1071.    else
  1072.       return NULL;
  1073. }
  1074. /* ServerNameTable_CloseAllPseudoObjs
  1075.  * ----------------------------------
  1076.  *
  1077.  *  Force all pseudo objects to close. this results in sending OnClose
  1078.  *  notification to each pseudo object's linking clients.
  1079.  */
  1080. void ServerNameTable_CloseAllPseudoObjs(LPSERVERNAMETABLE lpServerNameTable)
  1081. {
  1082.    LPOUTLINENAMETABLE lpOutlineNameTable =
  1083.                               (LPOUTLINENAMETABLE)lpServerNameTable;
  1084.    LPSERVERNAME lpServerName;
  1085.    int i;
  1086.    OLEDBG_BEGIN3("ServerNameTable_CloseAllPseudoObjsrn")
  1087.    for(i = 0; i < lpOutlineNameTable->m_nCount; i++) {
  1088.       lpServerName = (LPSERVERNAME)OutlineNameTable_GetName(
  1089.             lpOutlineNameTable,
  1090.             i
  1091.       );
  1092.         ServerName_ClosePseudoObj(lpServerName);
  1093.    }
  1094.    OLEDBG_END3
  1095. }
  1096. /* ServerName_SetSel
  1097.  * -----------------
  1098.  *
  1099.  *      Change the line range of a  name.
  1100.  */
  1101. void ServerName_SetSel(
  1102.       LPSERVERNAME            lpServerName,
  1103.       LPLINERANGE             lplrSel,
  1104.       BOOL                    fRangeModified
  1105. )
  1106. {
  1107.    LPOUTLINENAME lpOutlineName = (LPOUTLINENAME)lpServerName;
  1108.    BOOL fPseudoObjChanged = fRangeModified;
  1109.    if (lpOutlineName->m_nStartLine != lplrSel->m_nStartLine) {
  1110.       lpOutlineName->m_nStartLine = lplrSel->m_nStartLine;
  1111.       fPseudoObjChanged = TRUE;
  1112.    }
  1113.    if (lpOutlineName->m_nEndLine != lplrSel->m_nEndLine) {
  1114.       lpOutlineName->m_nEndLine = lplrSel->m_nEndLine;
  1115.       fPseudoObjChanged = TRUE;
  1116.    }
  1117.    /* NOTE: if the range of an active pseudo object has
  1118.    **    changed, then inform any linking clients that the object
  1119.    **    has changed.
  1120.    */
  1121.    if (lpServerName->m_lpPseudoObj && fPseudoObjChanged) {
  1122.       PseudoObj_SendAdvise(
  1123.             lpServerName->m_lpPseudoObj,
  1124.             OLE_ONDATACHANGE,
  1125.             NULL,   /* lpmkDoc -- not relevant here */
  1126.             0       /* advf -- no flags necessary */
  1127.       );
  1128.    }
  1129. }
  1130. /* ServerName_SendPendingAdvises
  1131.  * -----------------------------
  1132.  *
  1133.  *      Send any pending change notifications for the associated
  1134.  *  pseudo objects for this name (if one exists).
  1135.  *  while ReDraw is diabled on the ServerDoc, then change advise
  1136.  *  notifications are not sent to pseudo object clients.
  1137.  */
  1138. void ServerName_SendPendingAdvises(LPSERVERNAME lpServerName)
  1139. {
  1140.    if (! lpServerName->m_lpPseudoObj)
  1141.       return;     // no associated pseudo object
  1142.    if (lpServerName->m_lpPseudoObj->m_fDataChanged)
  1143.       PseudoObj_SendAdvise(
  1144.             lpServerName->m_lpPseudoObj,
  1145.             OLE_ONDATACHANGE,
  1146.             NULL,   /* lpmkDoc -- not relevant here */
  1147.             0       /* advf -- no flags necessary */
  1148.       );
  1149. }
  1150. /* ServerName_GetPseudoObj
  1151. ** -----------------------
  1152. **
  1153. **    Return a pointer to a pseudo object associated to a ServerName.
  1154. **    if the pseudo object already exists, then return the
  1155. **    existing object, otherwise allocate a new pseudo object.
  1156. **
  1157. **    NOTE: the PseudoObj is returned with a 0 refcnt if first created,
  1158. **    else the existing refcnt is unchanged.
  1159. */
  1160. LPPSEUDOOBJ ServerName_GetPseudoObj(
  1161.       LPSERVERNAME            lpServerName,
  1162.       LPSERVERDOC             lpServerDoc
  1163. )
  1164. {
  1165.    // Check if a PseudoObj already exists
  1166.    if (lpServerName->m_lpPseudoObj)
  1167.       return lpServerName->m_lpPseudoObj;
  1168.    // A PseudoObj does NOT already exist, allocate a new one.
  1169.    lpServerName->m_lpPseudoObj=(LPPSEUDOOBJ) New((DWORD)sizeof(PSEUDOOBJ));
  1170.    if (lpServerName->m_lpPseudoObj == NULL) {
  1171.       OleDbgAssertSz(lpServerName->m_lpPseudoObj != NULL,   "Error allocating PseudoObj");
  1172.       return NULL;
  1173.    }
  1174.    PseudoObj_Init(lpServerName->m_lpPseudoObj, lpServerName, lpServerDoc);
  1175.    return lpServerName->m_lpPseudoObj;
  1176. }
  1177. /* ServerName_ClosePseudoObj
  1178.  * -------------------------
  1179.  *
  1180.  *      if there is an associated pseudo objects for this name (if one
  1181.  *  exists), then close it. this results in sending OnClose
  1182.  *  notification to the pseudo object's linking clients.
  1183.  */
  1184. void ServerName_ClosePseudoObj(LPSERVERNAME lpServerName)
  1185. {
  1186.    if (!lpServerName || !lpServerName->m_lpPseudoObj)
  1187.       return;     // no associated pseudo object
  1188.    PseudoObj_Close(lpServerName->m_lpPseudoObj);
  1189. }
  1190. #endif  // OLE_SERVER
  1191. #if defined( OLE_CNTR )
  1192. /*************************************************************************
  1193. ** ContainerDoc Supprt Functions Used by Container versions
  1194. *************************************************************************/
  1195. /* ContainerLine_GetRelMoniker
  1196. ** ---------------------------
  1197. **    Retrieve the relative item moniker which identifies the OLE object
  1198. **    relative to the container document.
  1199. **
  1200. **    Returns NULL if a moniker can NOT be created.
  1201. */
  1202. LPMONIKER ContainerLine_GetRelMoniker(
  1203.       LPCONTAINERLINE         lpContainerLine,
  1204.       DWORD                   dwAssign
  1205. )
  1206. {
  1207.    LPMONIKER lpmk = NULL;
  1208.    /* NOTE: we should only give out a moniker for the OLE object
  1209.    **    if the object is allowed to be linked to from the inside. if
  1210.    **    so we are allowed to give out a moniker which binds to the
  1211.    **    running OLE object). if the object is an OLE 2.0 embedded
  1212.    **    object then it is allowed to be linked to from the inside. if
  1213.    **    the object is either an OleLink or an OLE 1.0 embedding
  1214.    **    then it can not be linked to from the inside.
  1215.    **    if we were a container/server app then we could offer linking
  1216.    **    to the outside of the object (ie. a pseudo object within our
  1217.    **    document). we are a container only app that does not support
  1218.    **    linking to ranges of its data.
  1219.    */
  1220.    switch (dwAssign) {
  1221.       case GETMONIKER_FORCEASSIGN:
  1222.             /* Force the assignment of the name. This is called when a
  1223.             **    Paste Link actually occurs. From now on we want
  1224.             **    to inform the OLE object that its moniker is
  1225.             **    assigned and is thus necessary to register itself
  1226.             **    in the RunningObjectTable.
  1227.             */
  1228.             CreateItemMoniker(
  1229.                   OLESTR("\"), lpContainerLine->m_szStgName, &lpmk);
  1230.             /* NOTE: if the OLE object is already loaded and it
  1231.             **    is being assigned a moniker for the first time,
  1232.             **    then we need to inform it that it now has a moniker
  1233.             **    assigned by calling IOleObject::SetMoniker. this
  1234.             **    will force the OLE object to register in the
  1235.             **    RunningObjectTable when it enters the running
  1236.             **    state. if the object is not currently loaded,
  1237.             **    SetMoniker will be called automatically later when
  1238.             **    the object is loaded by the function
  1239.             **    ContainerLine_LoadOleObject.
  1240.             */
  1241.             if (! lpContainerLine->m_fMonikerAssigned) {
  1242.                /* we must remember forever more that this object has a
  1243.                **    moniker assigned.
  1244.                */
  1245.                lpContainerLine->m_fMonikerAssigned = TRUE;
  1246.                // we are now dirty and must be saved
  1247.                OutlineDoc_SetModified(
  1248.                      (LPOUTLINEDOC)lpContainerLine->m_lpDoc,
  1249.                      TRUE,   /* fModified */
  1250.                      FALSE,  /* fDataChanged--N/A for container ver. */
  1251.                      FALSE   /* fSizeChanged--N/A for container ver. */
  1252.                );
  1253.                if (lpContainerLine->m_lpOleObj) {
  1254.                   OLEDBG_BEGIN2("IOleObject::SetMoniker calledrn")
  1255.                   lpContainerLine->m_lpOleObj->lpVtbl->SetMoniker(
  1256.                         lpContainerLine->m_lpOleObj,
  1257.                         OLEWHICHMK_OBJREL,
  1258.                         lpmk
  1259.                   );
  1260.                   OLEDBG_END2
  1261.                }
  1262.             }
  1263.             break;
  1264.       case GETMONIKER_ONLYIFTHERE:
  1265.             /* If the OLE object currently has a moniker assigned,
  1266.             **    then return it.
  1267.             */
  1268.             if (lpContainerLine->m_fMonikerAssigned) {
  1269.                CreateItemMoniker(
  1270.                      OLESTR("\"),
  1271.                      lpContainerLine->m_szStgName,
  1272.                      &lpmk
  1273.                );
  1274.             }
  1275.             break;
  1276.       case GETMONIKER_TEMPFORUSER:
  1277.             /* Return the moniker that would be used for the OLE
  1278.             **    object but do NOT force moniker assignment at
  1279.             **    this point. Since our strategy is to use the
  1280.             **    storage name of the object as its item name, we
  1281.             **    can simply create the corresponding ItemMoniker
  1282.             **    (indepenedent of whether the moniker is currently
  1283.             **    assigned or not).
  1284.             */
  1285.             CreateItemMoniker(
  1286.                   OLESTR("\"),
  1287.                   lpContainerLine->m_szStgName,
  1288.                   &lpmk
  1289.             );
  1290.             break;
  1291.       case GETMONIKER_UNASSIGN:
  1292.             lpContainerLine->m_fMonikerAssigned = FALSE;
  1293.             break;
  1294.    }
  1295.    return lpmk;
  1296. }
  1297. /* ContainerLine_GetFullMoniker
  1298. ** ----------------------------
  1299. **    Retrieve the full absolute moniker which identifies the OLE object
  1300. **    in the container document.
  1301. **    this moniker is created as a composite of the absolute moniker for
  1302. **    the entire document appended with an item moniker which identifies
  1303. **    the OLE object relative to the document.
  1304. **    Returns NULL if a moniker can NOT be created.
  1305. */
  1306. LPMONIKER ContainerLine_GetFullMoniker(
  1307.       LPCONTAINERLINE         lpContainerLine,
  1308.       DWORD                   dwAssign
  1309. )
  1310. {
  1311.    LPMONIKER lpmkDoc = NULL;
  1312.    LPMONIKER lpmkItem = NULL;
  1313.    LPMONIKER lpmkFull = NULL;
  1314.    lpmkDoc = OleDoc_GetFullMoniker(
  1315.          (LPOLEDOC)lpContainerLine->m_lpDoc,
  1316.          dwAssign
  1317.    );
  1318.    if (! lpmkDoc)
  1319.    {
  1320.        return NULL;
  1321.    }
  1322.    lpmkItem = ContainerLine_GetRelMoniker(lpContainerLine, dwAssign);
  1323.    if (lpmkItem) {
  1324.       CreateGenericComposite(lpmkDoc, lpmkItem, (LPMONIKER FAR*)&lpmkFull);
  1325.       OleStdRelease((LPUNKNOWN)lpmkItem);
  1326.    }
  1327.    if (lpmkDoc)
  1328.       OleStdRelease((LPUNKNOWN)lpmkDoc);
  1329.    return lpmkFull;
  1330. }
  1331. /* ContainerDoc_InformAllOleObjectsDocRenamed
  1332. ** ------------------------------------------
  1333. **    Inform all OLE objects that the name of the ContainerDoc has changed.
  1334. */
  1335. void ContainerDoc_InformAllOleObjectsDocRenamed(
  1336.       LPCONTAINERDOC          lpContainerDoc,
  1337.       LPMONIKER               lpmkDoc
  1338. )
  1339. {
  1340.    LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;
  1341.    int i;
  1342.    LPLINE lpLine;
  1343.    // artificial AddRef in case someone releases object during call
  1344.    OleDoc_AddRef((LPOLEDOC)lpContainerDoc);
  1345.    for (i = 0; i < lpLL->m_nNumLines; i++) {
  1346.       lpLine=LineList_GetLine(lpLL, i);
  1347.       if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) {
  1348.          LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine;
  1349.          /* NOTE: if the OLE object is already loaded AND the
  1350.          **    object already has a moniker assigned, then we need
  1351.          **    to inform it that the moniker of the ContainerDoc has
  1352.          **    changed. of course, this means the full moniker of
  1353.          **    the object has changed. to do this we call
  1354.          **    IOleObject::SetMoniker. this will force the OLE
  1355.          **    object to re-register in the RunningObjectTable if it
  1356.          **    is currently in the running state. it is not in the
  1357.          **    running state, the object handler can make not that
  1358.          **    the object has a new moniker. if the object is not
  1359.          **    currently loaded, SetMoniker will be called
  1360.          **    automatically later when the object is loaded by the
  1361.          **    function ContainerLine_LoadOleObject.
  1362.          **    also if the object is a linked object, we always want
  1363.          **    to call SetMoniker on the link so that in case the
  1364.          **    link source is contained within our same container,
  1365.          **    the link source will be tracked. the link rebuilds
  1366.          **    its absolute moniker if it has a relative moniker.
  1367.          */
  1368.          if (lpContainerLine->m_lpOleObj) {
  1369.             if (lpContainerLine->m_fMonikerAssigned ||
  1370.                lpContainerLine->m_dwLinkType != 0) {
  1371.                OLEDBG_BEGIN2("IOleObject::SetMoniker calledrn")
  1372.                lpContainerLine->m_lpOleObj->lpVtbl->SetMoniker(
  1373.                      lpContainerLine->m_lpOleObj,
  1374.                      OLEWHICHMK_CONTAINER,
  1375.                      lpmkDoc
  1376.                );
  1377.                OLEDBG_END2
  1378.             }
  1379.             /* NOTE: we must call IOleObject::SetHostNames so
  1380.             **    any open objects can update their window titles.
  1381.             */
  1382.             OLEDBG_BEGIN2("IOleObject::SetHostNames calledrn")
  1383.             lpContainerLine->m_lpOleObj->lpVtbl->SetHostNames(
  1384.                   lpContainerLine->m_lpOleObj,
  1385.                   /*(LPOLESTR)*/APPNAME,
  1386.                   ((LPOUTLINEDOC)lpContainerDoc)->m_lpszDocTitle
  1387.             );
  1388.             OLEDBG_END2
  1389.          }
  1390.       }
  1391.    }
  1392.    // release artificial AddRef
  1393.    OleDoc_Release((LPOLEDOC)lpContainerDoc);
  1394. }
  1395. /* ContainerDoc_GetObject
  1396. ** ----------------------
  1397. **    Return a pointer to the desired interface of an object identified
  1398. **    by an item string (lpszItem). the object returned will be an OLE
  1399. **    object (either link or embedding).
  1400. **
  1401. **      NOTE: we must force the object to run because we are
  1402. **          REQUIRED to return a pointer the OLE object in the
  1403. **          RUNNING state.
  1404. **
  1405. **    dwSpeedNeeded indicates how long the caller is willing
  1406. **    to wait for us to get the object:
  1407. **      BINDSPEED_IMMEDIATE -- only if obj already loaded && IsRunning
  1408. **      BINDSPEED_MODERATE  -- load obj if necessary && if IsRunning
  1409. **      BINDSPEED_INDEFINITE-- force obj to load and run if necessary
  1410. */
  1411. HRESULT ContainerDoc_GetObject(
  1412.       LPCONTAINERDOC          lpContainerDoc,
  1413.       LPOLESTR                lpszItem,
  1414.       DWORD                   dwSpeedNeeded,
  1415.       REFIID                  riid,
  1416.       LPVOID FAR*             lplpvObject
  1417. )
  1418. {
  1419.    LPLINELIST  lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;
  1420.    int         i;
  1421.    LPLINE      lpLine;
  1422.    BOOL        fMatchFound = FALSE;
  1423.    DWORD       dwStatus;
  1424.    HRESULT     hrErr;
  1425.    *lplpvObject = NULL;
  1426.    for (i = 0; i < lpLL->m_nNumLines; i++) {
  1427.       lpLine=LineList_GetLine(lpLL, i);
  1428.       if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) {
  1429.          LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine;
  1430.          if (OLESTRCMP(lpContainerLine->m_szStgName, lpszItem) == 0) {
  1431.             fMatchFound = TRUE;     // valid item name
  1432.             // check if object is loaded.
  1433.             if (lpContainerLine->m_lpOleObj == NULL) {
  1434.                // if BINDSPEED_IMMEDIATE is requested, object must
  1435.                // ALREADY be loadded.
  1436.                if (dwSpeedNeeded == BINDSPEED_IMMEDIATE)
  1437.                   return MK_E_EXCEEDEDDEADLINE;
  1438.                ContainerLine_LoadOleObject(lpContainerLine);
  1439.                if (! lpContainerLine->m_lpOleObj)
  1440.                   return E_OUTOFMEMORY;
  1441.             }
  1442.             /* NOTE: check if the object is allowed to be linked
  1443.             **    to from the inside (ie. we are allowed to
  1444.             **    give out a moniker which binds to the running
  1445.             **    OLE object). if the object is an OLE
  1446.             **    2.0 embedded object then it is allowed to be
  1447.             **    linked to from the inside. if the object is
  1448.             **    either an OleLink or an OLE 1.0 embedding
  1449.             **    then it can not be linked to from the inside.
  1450.             **    if we were a container/server app then we
  1451.             **    could offer linking to the outside of the
  1452.             **    object (ie. a pseudo object within our
  1453.             **    document). we are a container only app that
  1454.             **    does not support linking to ranges of its data.
  1455.             */
  1456.             OLEDBG_BEGIN2("IOleObject::GetMiscStatus calledrn");
  1457.             lpContainerLine->m_lpOleObj->lpVtbl->GetMiscStatus(
  1458.                   lpContainerLine->m_lpOleObj,
  1459.                   DVASPECT_CONTENT, /* aspect is not important */
  1460.                   (LPDWORD)&dwStatus
  1461.             );
  1462.             OLEDBG_END2
  1463.             if (dwStatus & OLEMISC_CANTLINKINSIDE)
  1464.             {
  1465.                return MK_E_NOOBJECT;
  1466.             }
  1467.             // check if object is running.
  1468.             if (! OleIsRunning(lpContainerLine->m_lpOleObj)) {
  1469.                // if BINDSPEED_MODERATE is requested, object must
  1470.                // ALREADY be running.
  1471.                if (dwSpeedNeeded == BINDSPEED_MODERATE)
  1472.                {
  1473.                   return MK_E_EXCEEDEDDEADLINE;
  1474.                }
  1475.                /* NOTE: we have found a match for the item name.
  1476.                **    now we must return a pointer to the desired
  1477.                **    interface on the RUNNING object. we must
  1478.                **    carefully load the object and initially ask for
  1479.                **    an interface that we are sure the loaded form of
  1480.                **    the object supports. if we immediately ask the
  1481.                **    loaded object for the desired interface, the
  1482.                **    QueryInterface call might fail if it is an
  1483.                **    interface that is supported only when the object
  1484.                **    is running. thus we force the object to load and
  1485.                **    return its IUnknown*. then we force the object to
  1486.                **    run, and then finally, we can ask for the
  1487.                **    actually requested interface.
  1488.                */
  1489.                hrErr = ContainerLine_RunOleObject(lpContainerLine);
  1490.                if (hrErr != NOERROR) {
  1491.                   return hrErr;
  1492.                }
  1493.             }
  1494.             // Retrieve the requested interface
  1495.             *lplpvObject = OleStdQueryInterface(
  1496.                   (LPUNKNOWN)lpContainerLine->m_lpOleObj, riid);
  1497.             break;  // Match FOUND!
  1498.          }
  1499.       }
  1500.    }
  1501.    if (*lplpvObject != NULL) {
  1502.       return NOERROR;
  1503.    } else
  1504.    {
  1505.       return (fMatchFound ? E_NOINTERFACE
  1506.                      : MK_E_NOOBJECT);
  1507.    }
  1508. }
  1509. /* ContainerDoc_GetObjectStorage
  1510. ** -----------------------------
  1511. **    Return a pointer to the IStorage* used by the object identified
  1512. **    by an item string (lpszItem). the object identified could be either
  1513. **    an OLE object (either link or embedding).
  1514. */
  1515. HRESULT ContainerDoc_GetObjectStorage(
  1516.       LPCONTAINERDOC          lpContainerDoc,
  1517.       LPOLESTR                lpszItem,
  1518.       LPSTORAGE FAR*          lplpStg
  1519. )
  1520. {
  1521.    LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;
  1522.    int i;
  1523.    LPLINE lpLine;
  1524.    *lplpStg = NULL;
  1525.    for (i = 0; i < lpLL->m_nNumLines; i++) {
  1526.       lpLine=LineList_GetLine(lpLL, i);
  1527.       if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) {
  1528.          LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine;
  1529.          if (OLESTRCMP(lpContainerLine->m_szStgName, lpszItem) == 0) {
  1530.             *lplpStg = lpContainerLine->m_lpStg;
  1531.             break;  // Match FOUND!
  1532.          }
  1533.       }
  1534.    }
  1535.    if (*lplpStg != NULL) {
  1536.       return NOERROR;
  1537.    } else
  1538.    {
  1539.       return MK_E_NOOBJECT;
  1540.    }
  1541. }
  1542. /* ContainerDoc_IsRunning
  1543. ** ----------------------
  1544. **    Check if the object identified by an item string (lpszItem) is in
  1545. **    the running state.
  1546. **    For a container-only app, a check is made if the OLE object
  1547. **    associated with the item name is running.
  1548. */
  1549. HRESULT ContainerDoc_IsRunning(LPCONTAINERDOC   lpContainerDoc, LPOLESTR lpszItem)
  1550. {
  1551.    LPLINELIST  lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;
  1552.    int         i;
  1553.    LPLINE      lpLine;
  1554.    DWORD       dwStatus;
  1555.    for (i = 0; i < lpLL->m_nNumLines; i++) {
  1556.       lpLine=LineList_GetLine(lpLL, i);
  1557.       if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) {
  1558.          LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine;
  1559.          if (OLESTRCPY(lpContainerLine->m_szStgName, lpszItem) == 0) {
  1560.             /* NOTE: we have found a match for the item name.
  1561.             **    now we must check if the OLE object is running.
  1562.             **    we will load the object if not already loaded.
  1563.             */
  1564.             if (! lpContainerLine->m_lpOleObj) {
  1565.                ContainerLine_LoadOleObject(lpContainerLine);
  1566.                if (! lpContainerLine->m_lpOleObj)
  1567.                   return E_OUTOFMEMORY;
  1568.             }
  1569.             /* NOTE: check if the object is allowed to be linked
  1570.             **    to from the inside (ie. we are allowed to
  1571.             **    give out a moniker which binds to the running
  1572.             **    OLE object). if the object is an OLE
  1573.             **    2.0 embedded object then it is allowed to be
  1574.             **    linked to from the inside. if the object is
  1575.             **    either an OleLink or an OLE 1.0 embedding
  1576.             **    then it can not be linked to from the inside.
  1577.             **    if we were a container/server app then we
  1578.             **    could offer linking to the outside of the
  1579.             **    object (ie. a pseudo object within our
  1580.             **    document). we are a container only app that
  1581.             **    does not support linking to ranges of its data.
  1582.             */
  1583.             OLEDBG_BEGIN2("IOleObject::GetMiscStatus calledrn")
  1584.             lpContainerLine->m_lpOleObj->lpVtbl->GetMiscStatus(
  1585.                   lpContainerLine->m_lpOleObj,
  1586.                   DVASPECT_CONTENT, /* aspect is not important */
  1587.                   (LPDWORD)&dwStatus
  1588.             );
  1589.             OLEDBG_END2
  1590.             if (dwStatus & OLEMISC_CANTLINKINSIDE)
  1591.             {
  1592.                return MK_E_NOOBJECT;
  1593.             }
  1594.             if (OleIsRunning(lpContainerLine->m_lpOleObj))
  1595.             {
  1596.                return NOERROR;
  1597.             }
  1598.             else
  1599.             {
  1600.                return S_FALSE;
  1601.             }
  1602.          }
  1603.       }
  1604.    }
  1605.    // no object was found corresponding to the item name
  1606.    return MK_E_NOOBJECT;
  1607. }
  1608. #endif  // OLE_CNTR