home *** CD-ROM | disk | FTP | other *** search
/ Supercompiler 1997 / SUPERCOMPILER97.iso / MS_VC.50 / VC / MFC / SRC / OLELINK.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1996-11-15  |  20.4 KB  |  828 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1997 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10.  
  11. #include "stdafx.h"
  12.  
  13. #ifdef AFX_OLE3_SEG
  14. #pragma code_seg(AFX_OLE3_SEG)
  15. #endif
  16.  
  17. #ifdef _DEBUG
  18. #undef THIS_FILE
  19. static char THIS_FILE[] = __FILE__;
  20. #endif
  21.  
  22. #define new DEBUG_NEW
  23.  
  24. #define OLE_MAXNAMESIZE     (256)
  25.  
  26. /////////////////////////////////////////////////////////////////////////////
  27. // COleLinkingDoc - enables linking to embeddings (basis for server)
  28.  
  29. COleLinkingDoc::COleLinkingDoc()
  30. {
  31.     m_dwRegister = 0;
  32.     m_pFactory = NULL;
  33.     m_bVisibleLock = FALSE;
  34.     m_bDeferErrors = FALSE;
  35.     m_pLastException = NULL;
  36.     m_lpMonikerROT = NULL;
  37.  
  38.     ASSERT_VALID(this);
  39. }
  40.  
  41. COleLinkingDoc::~COleLinkingDoc()
  42. {
  43.     ASSERT_VALID(this);
  44.  
  45.     ASSERT(!m_bVisibleLock);
  46.  
  47.     DisconnectViews();
  48.     ASSERT(m_viewList.IsEmpty());
  49.  
  50.     Revoke();   // cleanup naming support
  51.  
  52.     ExternalDisconnect();
  53. }
  54.  
  55. /////////////////////////////////////////////////////////////////////////////
  56. // COleLinkingDoc moniker handling
  57.  
  58. LPMONIKER COleLinkingDoc::GetMoniker(OLEGETMONIKER nAssign)
  59. {
  60.     USES_CONVERSION;
  61.  
  62.     ASSERT_VALID(this);
  63.  
  64.     // use base class implementation if no registered moniker
  65.     if (m_strMoniker.IsEmpty())
  66.         return COleDocument::GetMoniker(nAssign);
  67.  
  68.     // return file moniker based on current path name
  69.     LPMONIKER lpMoniker;
  70.     CreateFileMoniker(T2COLE(m_strMoniker), &lpMoniker);
  71.     return lpMoniker;
  72. }
  73.  
  74. BOOL COleLinkingDoc::Register(COleObjectFactory* pFactory, LPCTSTR lpszPathName)
  75. {
  76.     USES_CONVERSION;
  77.  
  78.     ASSERT_VALID(this);
  79.     ASSERT(pFactory == NULL ||
  80.         AfxIsValidAddress(pFactory, sizeof(COleObjectFactory)));
  81.     ASSERT(lpszPathName == NULL || AfxIsValidString(lpszPathName));
  82.     ASSERT(m_dwRegister == 0);
  83.  
  84.     // attach the document to the server
  85.     ASSERT(m_pFactory == NULL || m_pFactory == pFactory);
  86.     m_pFactory = pFactory;
  87.  
  88.     BOOL bResult = TRUE;
  89.  
  90.     // create file moniker based on path name
  91.     RELEASE(m_lpMonikerROT);
  92.     m_strMoniker.Empty();
  93.     if (lpszPathName != NULL)
  94.     {
  95.         if (CreateFileMoniker(T2COLE(lpszPathName), &m_lpMonikerROT) != S_OK)
  96.             bResult = FALSE;
  97.     }
  98.  
  99.     // register file moniker as running
  100.     if (m_lpMonikerROT != NULL)
  101.     {
  102.         // see if the object is already running in the ROT
  103.         LPRUNNINGOBJECTTABLE lpROT = NULL;
  104.         VERIFY(GetRunningObjectTable(0, &lpROT) == S_OK);
  105.         ASSERT(lpROT != NULL);
  106.         LPUNKNOWN lpUnk;
  107.         if (lpROT->GetObject(m_lpMonikerROT, &lpUnk) == S_OK)
  108.         {
  109.             // fatal error -- can't register same moniker twice!
  110.             lpUnk->Release();
  111.             RELEASE(m_lpMonikerROT);
  112.             return FALSE;
  113.         }
  114.         // not already running -- so ok to attempt registration
  115.         SCODE sc = lpROT->Register(NULL, (LPUNKNOWN)
  116.             GetInterface(&IID_IUnknown), m_lpMonikerROT, &m_dwRegister);
  117.         lpROT->Release();
  118.         m_strMoniker = lpszPathName;
  119.         if (sc != S_OK)
  120.             bResult = FALSE;
  121.     }
  122.  
  123.     // update all objects with new moniker
  124.     POSITION pos = GetStartPosition();
  125.     COleClientItem* pItem;
  126.     while ((pItem = GetNextClientItem(pos)) != NULL)
  127.     {
  128.         if (pItem->m_bMoniker)
  129.         {
  130.             ASSERT(pItem->m_lpObject != NULL);
  131.             pItem->m_lpObject->SetMoniker(OLEWHICHMK_CONTAINER,
  132.                 m_lpMonikerROT);
  133.         }
  134.     }
  135.  
  136.     return bResult;
  137. }
  138.  
  139. void COleLinkingDoc::Revoke()
  140. {
  141.     ASSERT_VALID(this);
  142.  
  143.     // revoke current registration
  144.     if (m_dwRegister != 0)
  145.     {
  146.         LPRUNNINGOBJECTTABLE lpROT = NULL;
  147.         GetRunningObjectTable(0, &lpROT);
  148.         if (lpROT != NULL)
  149.         {
  150.             lpROT->Revoke(m_dwRegister);
  151.             lpROT->Release();
  152.         }
  153.         m_dwRegister = 0;
  154.     }
  155.     RELEASE(m_lpMonikerROT);
  156.     m_strMoniker = _T("");
  157. }
  158.  
  159. BOOL COleLinkingDoc::OnNewDocument()
  160. {
  161.     ASSERT_VALID(this);
  162.  
  163.     Revoke();
  164.     RegisterIfServerAttached(NULL, TRUE);
  165.  
  166.     if (!COleDocument::OnNewDocument())
  167.         return FALSE;
  168.  
  169.     AfxOleSetUserCtrl(TRUE);
  170.  
  171.     return TRUE;
  172. }
  173.  
  174. BOOL COleLinkingDoc::OnOpenDocument(LPCTSTR lpszPathName)
  175. {
  176.     ASSERT_VALID(this);
  177.  
  178.     // always register the document before opening it
  179.     Revoke();
  180.     if (!RegisterIfServerAttached(lpszPathName, FALSE))
  181.     {
  182.         // always output a trace (it is just an FYI -- not generally fatal)
  183.         TRACE1("Warning: Unable to register moniker '%s' as running\n", lpszPathName);
  184.     }
  185.  
  186.     if (!COleDocument::OnOpenDocument(lpszPathName))
  187.     {
  188.         Revoke();
  189.         return FALSE;
  190.     }
  191.  
  192.     // if the app was started only to print, don't set user control
  193.  
  194.     CWinApp* pApp = AfxGetApp();
  195.     ASSERT(pApp != NULL);
  196.     if (pApp->m_pCmdInfo == NULL ||
  197.         (pApp->m_pCmdInfo->m_nShellCommand != CCommandLineInfo::FileDDE &&
  198.          pApp->m_pCmdInfo->m_nShellCommand != CCommandLineInfo::FilePrint))
  199.     {
  200.         AfxOleSetUserCtrl(TRUE);
  201.     }
  202.  
  203.     return TRUE;
  204. }
  205.  
  206. BOOL COleLinkingDoc::OnSaveDocument(LPCTSTR lpszPathName)
  207. {
  208.     ASSERT_VALID(this);
  209.  
  210.     BOOL bRemember = m_bRemember;
  211.     if (!COleDocument::OnSaveDocument(lpszPathName))
  212.         return FALSE;
  213.  
  214.     if (bRemember && (m_strMoniker != lpszPathName))
  215.     {
  216.         // update the moniker/registration since the name has changed
  217.         Revoke();
  218.         RegisterIfServerAttached(lpszPathName, TRUE);
  219.     }
  220.     return TRUE;
  221. }
  222.  
  223. void COleLinkingDoc::OnCloseDocument()
  224. {
  225.     InternalAddRef();   // protect document during shutdown
  226.  
  227.     // update lock count before sending notifications
  228.     UpdateVisibleLock(FALSE, FALSE);
  229.  
  230.     Revoke();   // cleanup naming support
  231.  
  232.     // remove visible lock if present
  233.     if (m_bVisibleLock)
  234.     {
  235.         m_bVisibleLock = FALSE;
  236.         LockExternal(FALSE, FALSE);
  237.     }
  238.  
  239.     // cleanup the document but don't delete yet
  240.     BOOL bAutoDelete = m_bAutoDelete;
  241.     m_bAutoDelete = FALSE;
  242.     COleDocument::OnCloseDocument();
  243.     ASSERT_VALID(this);
  244.  
  245.     // remove extra reference count and destroy
  246.     InterlockedDecrement(&m_dwRef);
  247.     if (bAutoDelete)
  248.         delete this;    // now safe to destroy document
  249. }
  250.  
  251. void COleLinkingDoc::UpdateVisibleLock(BOOL bVisible, BOOL bRemoveRefs)
  252. {
  253.     ASSERT_VALID(this);
  254.  
  255.     if (bVisible != m_bVisibleLock)
  256.     {
  257.         InternalAddRef();   // make sure document is stable
  258.         m_bVisibleLock = bVisible;
  259.         LockExternal(bVisible, bRemoveRefs);
  260.         InternalRelease();  // may Release the document!
  261.     }
  262. }
  263.  
  264. void COleLinkingDoc::OnShowViews(BOOL bVisible)
  265. {
  266.     if (bVisible)
  267.         UpdateVisibleLock(bVisible, TRUE);
  268. }
  269.  
  270. void COleLinkingDoc::SaveToStorage(CObject* pObject)
  271. {
  272.     ASSERT_VALID(this);
  273.     if (pObject != NULL)
  274.         ASSERT_VALID(pObject);
  275.  
  276.     // write the classID of the application to the root storage
  277.     if (m_pFactory != NULL)
  278.     {
  279.         ASSERT(m_lpRootStg != NULL);
  280.         WriteClassStg(m_lpRootStg, m_pFactory->GetClassID());
  281.     }
  282.     COleDocument::SaveToStorage(pObject);
  283. }
  284.  
  285. BOOL COleLinkingDoc::RegisterIfServerAttached(LPCTSTR lpszPathName, BOOL bMessage)
  286. {
  287.     ASSERT_VALID(this);
  288.     ASSERT(lpszPathName == NULL || AfxIsValidString(lpszPathName));
  289.  
  290.     CDocTemplate* pTemplate = GetDocTemplate();
  291.     ASSERT_VALID(pTemplate);
  292.  
  293.     COleObjectFactory* pFactory =
  294.         (COleObjectFactory*)pTemplate->m_pAttachedFactory;
  295.     if (pFactory != NULL)
  296.     {
  297.         // always attach the document to the server at this time
  298.         ASSERT_KINDOF(COleObjectFactory, pFactory);
  299.         m_pFactory = pFactory;
  300.  
  301.         // register with OLE Server
  302.         if (!Register(pFactory, lpszPathName))
  303.         {
  304.             if (bMessage)
  305.             {
  306.                 // only report error when message box allowed
  307.                 ReportSaveLoadException(lpszPathName, NULL, FALSE,
  308.                     AFX_IDP_FAILED_TO_NOTIFY);
  309.             }
  310.             return FALSE;
  311.         }
  312.     }
  313.     return TRUE;
  314. }
  315.  
  316. LPOLEITEMCONTAINER COleLinkingDoc::GetContainer()
  317. {
  318.     ASSERT_VALID(this);
  319.  
  320.     // get the IOleItemContainer interface via QueryInterface
  321.     LPOLEITEMCONTAINER lpContainer;
  322.     InternalQueryInterface(&IID_IOleItemContainer, (LPLP)&lpContainer);
  323.     return lpContainer;
  324. }
  325.  
  326. /////////////////////////////////////////////////////////////////////////////
  327. // COleLinkingDoc default implementation
  328.  
  329. COleServerItem* COleLinkingDoc::OnGetLinkedItem(LPCTSTR /*lpszItemName*/)
  330. {
  331.     ASSERT_VALID(this);
  332.  
  333.     // default implementation is in COleServerDoc
  334.     return NULL;
  335. }
  336.  
  337. COleClientItem* COleLinkingDoc::OnFindEmbeddedItem(LPCTSTR lpszItemName)
  338. {
  339.     ASSERT_VALID(this);
  340.     ASSERT(AfxIsValidString(lpszItemName));
  341.  
  342.     // default implementation walks list of client items looking for
  343.     //  a case sensitive match
  344.  
  345.     POSITION pos = GetStartPosition();
  346.     COleClientItem* pItem;
  347.     while ((pItem = GetNextClientItem(pos)) != NULL)
  348.     {
  349.         // a client item is running if there is a match in name
  350.         //  and the m_lpObject is also running.
  351.         TCHAR szItemName[OLE_MAXITEMNAME];
  352.         pItem->GetItemName(szItemName);
  353.         if (lstrcmp(szItemName, lpszItemName) == 0)
  354.             return pItem;
  355.     }
  356. #ifdef _DEBUG
  357.     if (afxTraceFlags & traceOle)
  358.     {
  359.         TRACE0("Warning: default COleLinkingDoc::OnFindEmbeddedItem\n");
  360.         TRACE1("\timplementation failed to find item '%s'.\n", lpszItemName);
  361.     }
  362. #endif
  363.     return NULL;    // no matching item found
  364. }
  365.  
  366. void COleLinkingDoc::LockExternal(BOOL bLock, BOOL bRemoveRefs)
  367. {
  368.     // when an item binding is successful, the original document
  369.     //  is released.  To keep it alive and the RPC stubs that make
  370.     //  it available to the external world (via the running object
  371.     //  table), we need to place a lock on it.
  372.  
  373.     // a lock created with CoLockObjectExternal adds a reference
  374.     //  to the object itself (with IUnknown::AddRef) as well
  375.     //  as keeping the RPC stub alive.
  376.  
  377.     ::CoLockObjectExternal((LPUNKNOWN)GetInterface(&IID_IUnknown),
  378.         bLock, bRemoveRefs);
  379.  
  380.     if (bLock)
  381.     {
  382.         // avoid "dead" objects in the running object table (ROT), by
  383.         //  re-registering this object in the ROT.
  384.         if (!m_strPathName.IsEmpty())
  385.         {
  386.             Revoke();
  387.             RegisterIfServerAttached(m_strPathName, FALSE);
  388.         }
  389.     }
  390. }
  391.  
  392. void COleLinkingDoc::ReportSaveLoadException(LPCTSTR lpszPathName,
  393.     CException* e, BOOL bSaving, UINT nIDPDefault)
  394. {
  395.     // watch out for special mode
  396.     if (m_bDeferErrors)
  397.     {
  398.         // save the exception for later
  399.         --e->m_bAutoDelete;
  400.         m_pLastException = e;
  401.         return;
  402.     }
  403.  
  404.     // otherwise, just call base class
  405.     COleDocument::ReportSaveLoadException(lpszPathName, e, bSaving,
  406.         nIDPDefault);
  407. }
  408.  
  409. SCODE COleLinkingDoc::EndDeferErrors(SCODE sc)
  410. {
  411.     ASSERT(m_bDeferErrors != 0);
  412.     --m_bDeferErrors;
  413.     if (m_pLastException != NULL)
  414.     {
  415.         ASSERT_VALID(m_pLastException);
  416.         if (sc == S_OK)
  417.             sc = COleException::Process(m_pLastException);
  418.         ++m_pLastException->m_bAutoDelete;
  419.         m_pLastException->Delete();
  420.         m_pLastException = NULL;
  421.     }
  422.     return sc;
  423. }
  424.  
  425. /////////////////////////////////////////////////////////////////////////////
  426. // COleLinkingDoc OLE interface implementation
  427.  
  428. BEGIN_INTERFACE_MAP(COleLinkingDoc, COleDocument)
  429.     INTERFACE_PART(COleLinkingDoc, IID_IPersist, PersistFile)
  430.     INTERFACE_PART(COleLinkingDoc, IID_IPersistFile, PersistFile)
  431.     INTERFACE_PART(COleLinkingDoc, IID_IParseDisplayName, OleItemContainer)
  432.     INTERFACE_PART(COleLinkingDoc, IID_IOleContainer, OleItemContainer)
  433.     INTERFACE_PART(COleLinkingDoc, IID_IOleItemContainer, OleItemContainer)
  434. END_INTERFACE_MAP()
  435.  
  436. /////////////////////////////////////////////////////////////////////////////
  437. // COleLinkingDoc::XPersistFile implementation
  438.  
  439. STDMETHODIMP_(ULONG) COleLinkingDoc::XPersistFile::AddRef()
  440. {
  441.     METHOD_PROLOGUE_EX_(COleLinkingDoc, PersistFile)
  442.     return pThis->ExternalAddRef();
  443. }
  444.  
  445. STDMETHODIMP_(ULONG) COleLinkingDoc::XPersistFile::Release()
  446. {
  447.     METHOD_PROLOGUE_EX_(COleLinkingDoc, PersistFile)
  448.     return pThis->ExternalRelease();
  449. }
  450.  
  451. STDMETHODIMP COleLinkingDoc::XPersistFile::QueryInterface(
  452.     REFIID iid, LPVOID* ppvObj)
  453. {
  454.     METHOD_PROLOGUE_EX_(COleLinkingDoc, PersistFile)
  455.     return pThis->ExternalQueryInterface(&iid, ppvObj);
  456. }
  457.  
  458. STDMETHODIMP COleLinkingDoc::XPersistFile::GetClassID(LPCLSID lpClassID)
  459. {
  460.     METHOD_PROLOGUE_EX_(COleLinkingDoc, PersistFile)
  461.  
  462.     // this is sometimes called for documents not attached to servers!
  463.     if (pThis->m_pFactory == NULL)
  464.     {
  465.         *lpClassID = CLSID_NULL;
  466.         return E_FAIL;
  467.     }
  468.  
  469.     // get the class ID from the connected server object
  470.     ASSERT_VALID(pThis->m_pFactory);
  471.     *lpClassID = pThis->m_pFactory->GetClassID();
  472.     return S_OK;
  473. }
  474.  
  475. STDMETHODIMP COleLinkingDoc::XPersistFile::IsDirty()
  476. {
  477.     METHOD_PROLOGUE_EX(COleLinkingDoc, PersistFile)
  478.     return pThis->IsModified() ? S_OK : S_FALSE;
  479. }
  480.  
  481. STDMETHODIMP COleLinkingDoc::XPersistFile::Load(
  482.     LPCOLESTR lpszFileName, DWORD /*dwMode*/)
  483. {
  484.     METHOD_PROLOGUE_EX(COleLinkingDoc, PersistFile)
  485.     ASSERT_VALID(pThis);
  486.  
  487.     USES_CONVERSION;
  488.  
  489.     CString strFileName;
  490.     SCODE sc = E_FAIL;
  491.     pThis->BeginDeferErrors();
  492.     LPCTSTR lpszFileNameT = OLE2CT(lpszFileName);
  493.     TRY
  494.     {
  495.         BOOL bUserCtrl = AfxOleGetUserCtrl();
  496.  
  497.         // delegate to file-based Open implementation
  498.         if (!pThis->OnOpenDocument(lpszFileNameT))
  499.         {
  500.             AfxOleSetUserCtrl(bUserCtrl);
  501.             return S_FALSE;
  502.         }
  503.         pThis->SendInitialUpdate();
  504.  
  505.         // set the path name, but don't add to MRU list
  506.         pThis->SetPathName(lpszFileNameT, FALSE);
  507.         AfxOleSetUserCtrl(bUserCtrl);
  508.  
  509.         sc = S_OK;
  510.     }
  511.     END_TRY
  512.     sc = pThis->EndDeferErrors(sc);
  513.  
  514.     ASSERT_VALID(pThis);
  515.     return sc;
  516. }
  517.  
  518. STDMETHODIMP COleLinkingDoc::XPersistFile::Save(
  519.     LPCOLESTR lpszFileName, BOOL fRemember)
  520. {
  521.     METHOD_PROLOGUE_EX(COleLinkingDoc, PersistFile)
  522.     ASSERT_VALID(pThis);
  523.  
  524.     USES_CONVERSION;
  525.  
  526.     CString strFileName;
  527.     SCODE sc = E_FAIL;
  528.     pThis->BeginDeferErrors();
  529.     TRY
  530.     {
  531.         // delegate to file-based Save/Save As implementation
  532.         ASSERT(pThis->m_bRemember == TRUE);
  533.         pThis->m_bRemember = fRemember;
  534.         pThis->OnSaveDocument(OLE2CT(lpszFileName));
  535.         sc = S_OK;
  536.     }
  537.     END_TRY
  538.     sc = pThis->EndDeferErrors(sc);
  539.  
  540.     ASSERT_VALID(pThis);
  541.     return sc;
  542. }
  543.  
  544. STDMETHODIMP COleLinkingDoc::XPersistFile::SaveCompleted(LPCOLESTR lpszFileName)
  545. {
  546.     METHOD_PROLOGUE_EX(COleLinkingDoc, PersistFile)
  547.     ASSERT_VALID(pThis);
  548.  
  549.     USES_CONVERSION;
  550.  
  551.     TRY
  552.     {
  553.         // set the path name, but don't add to MRU list
  554.         pThis->SetPathName(OLE2CT(lpszFileName), FALSE);
  555.     }
  556.     END_TRY
  557.  
  558.     ASSERT_VALID(pThis);
  559.     return S_OK;
  560. }
  561.  
  562. STDMETHODIMP COleLinkingDoc::XPersistFile::GetCurFile(LPOLESTR* lplpszFileName)
  563. {
  564.     METHOD_PROLOGUE_EX_(COleLinkingDoc, PersistFile)
  565.  
  566.     *lplpszFileName = NULL;
  567.  
  568.     // use title if no document
  569.     LPCTSTR lpszResult;
  570.     if (pThis->m_strPathName.IsEmpty())
  571.         lpszResult = pThis->m_strTitle;
  572.     else
  573.         lpszResult = pThis->m_strPathName;
  574.     ASSERT(lpszResult != NULL);
  575.  
  576.     // allocate memory for the file name
  577.     *lplpszFileName = AfxAllocTaskOleString(lpszResult);
  578.     if (*lplpszFileName == NULL)
  579.         return E_OUTOFMEMORY;
  580.  
  581.     ASSERT_VALID(pThis);
  582.     return S_OK;
  583. }
  584.  
  585. /////////////////////////////////////////////////////////////////////////////
  586. // Implementation of IOleItemContainer
  587. //  (supports linking to embeddings and linking to pseudo-objects)
  588.  
  589. STDMETHODIMP_(ULONG) COleLinkingDoc::XOleItemContainer::AddRef()
  590. {
  591.     METHOD_PROLOGUE_EX_(COleLinkingDoc, OleItemContainer)
  592.     return pThis->ExternalAddRef();
  593. }
  594.  
  595. STDMETHODIMP_(ULONG) COleLinkingDoc::XOleItemContainer::Release()
  596. {
  597.     METHOD_PROLOGUE_EX_(COleLinkingDoc, OleItemContainer)
  598.     return pThis->ExternalRelease();
  599. }
  600.  
  601. STDMETHODIMP COleLinkingDoc::XOleItemContainer::QueryInterface(
  602.     REFIID iid, LPVOID* ppvObj)
  603. {
  604.     METHOD_PROLOGUE_EX_(COleLinkingDoc, OleItemContainer)
  605.     return pThis->ExternalQueryInterface(&iid, ppvObj);
  606. }
  607.  
  608. STDMETHODIMP COleLinkingDoc::XOleItemContainer::EnumObjects(
  609.     DWORD /*grfFlags*/, LPENUMUNKNOWN* ppEnumUnknown)
  610. {
  611.     *ppEnumUnknown = NULL;
  612.     return E_NOTIMPL;
  613. }
  614.  
  615. STDMETHODIMP COleLinkingDoc::XOleItemContainer::ParseDisplayName(LPBC lpbc,
  616.     LPOLESTR lpszDisplayName, ULONG* cchEaten, LPMONIKER* ppMoniker)
  617. {
  618.     METHOD_PROLOGUE_EX_(COleLinkingDoc, OleItemContainer)
  619.  
  620.     USES_CONVERSION;
  621.  
  622.     // reset all OUT parameters
  623.     *ppMoniker = NULL;
  624.  
  625.     TCHAR szItemName[OLE_MAXNAMESIZE];
  626.     LPTSTR lpszDest = szItemName;
  627.     LPCTSTR lpszSrc = OLE2CT(lpszDisplayName);
  628.  
  629.     // skip leading delimiters
  630.     int cEaten = 0;
  631.     while (*lpszSrc != '\0' && (*lpszSrc == '\\' || *lpszSrc == '/' ||
  632.         *lpszSrc == ':' || *lpszSrc == '!' || *lpszSrc == '['))
  633.     {
  634.         if (_istlead(*lpszSrc))
  635.             ++lpszSrc, ++cEaten;
  636.         ++lpszSrc;
  637.         ++cEaten;
  638.     }
  639.  
  640.     // parse next token in szItemName
  641.     while (*lpszSrc != '\0' && *lpszSrc != '\\' && *lpszSrc != '/' &&
  642.         *lpszSrc != ':' && *lpszSrc != '!' && *lpszSrc != '[' &&
  643.         cEaten < OLE_MAXNAMESIZE-1)
  644.     {
  645.         if (_istlead(*lpszSrc))
  646.             *lpszDest++ = *lpszSrc++, ++cEaten;
  647.         *lpszDest++ = *lpszSrc++;
  648.         ++cEaten;
  649.     }
  650.     *cchEaten = cEaten;
  651.     *lpszDest = 0;
  652.  
  653.     // attempt to get the object
  654.     LPUNKNOWN lpUnknown;
  655.     SCODE sc = GetObject(T2OLE(szItemName), BINDSPEED_INDEFINITE, lpbc,
  656.         IID_IUnknown, (LPLP)&lpUnknown);
  657.     if (sc != S_OK)
  658.         return sc;
  659.  
  660.     // item name found -- create item moniker for it
  661.     lpUnknown->Release();
  662.     return CreateItemMoniker(OLESTDDELIMOLE, T2COLE(szItemName), ppMoniker);
  663. }
  664.  
  665. STDMETHODIMP COleLinkingDoc::XOleItemContainer::LockContainer(BOOL fLock)
  666. {
  667.     METHOD_PROLOGUE_EX_(COleLinkingDoc, OleItemContainer)
  668.  
  669.     pThis->LockExternal(fLock, TRUE);
  670.     return S_OK;
  671. }
  672.  
  673. STDMETHODIMP COleLinkingDoc::XOleItemContainer::GetObject(
  674.     LPOLESTR lpszItem, DWORD dwSpeedNeeded, LPBINDCTX /*pbc*/, REFIID riid,
  675.     LPVOID* ppvObject)
  676. {
  677.     METHOD_PROLOGUE_EX(COleLinkingDoc, OleItemContainer)
  678.     ASSERT_VALID(pThis);
  679.  
  680.     USES_CONVERSION;
  681.  
  682.     *ppvObject = NULL;
  683.  
  684.     SCODE sc = MK_E_NOOBJECT;
  685.     TRY
  686.     {
  687.         LPCTSTR lpszItemT = OLE2CT(lpszItem);
  688.         // check for link to embedding
  689.         COleClientItem* pClientItem = pThis->OnFindEmbeddedItem(lpszItemT);
  690.         if (pClientItem != NULL)
  691.         {
  692.             ASSERT_VALID(pClientItem);
  693.             sc = S_OK;
  694.  
  695.             // item found -- make sure it is running
  696.             if (!::OleIsRunning(pClientItem->m_lpObject))
  697.             {
  698.                 // should not run the object if bind-speed is immediate
  699.                 if (dwSpeedNeeded != BINDSPEED_INDEFINITE)
  700.                     sc = MK_E_EXCEEDEDDEADLINE;
  701.                 else
  702.                 {
  703.                     // bind speed is not immediate -- so run the object
  704.                     sc = OleRun(pClientItem->m_lpObject);
  705.                 }
  706.             }
  707.  
  708.             if (sc == S_OK)
  709.             {
  710.                 // return the object with appropriate interface
  711.                 sc = pClientItem->m_lpObject->QueryInterface(riid, ppvObject);
  712.             }
  713.         }
  714.         else
  715.         {
  716.             // check for link to pseudo object
  717.             COleServerItem* pServerItem = pThis->OnGetLinkedItem(lpszItemT);
  718.             if (pServerItem != NULL)
  719.             {
  720.                 if (!pServerItem->m_bNeedUnlock)
  721.                 {
  722.                     // when a link is bound, the document must be kept alive
  723.                     pThis->LockExternal(TRUE, FALSE);
  724.                     pServerItem->m_bNeedUnlock = TRUE;
  725.                 }
  726.  
  727.                 // matching item found -- query for the requested interface
  728.                 sc = pServerItem->ExternalQueryInterface(&riid, ppvObject);
  729.             }
  730.         }
  731.     }
  732.     END_TRY
  733.  
  734.     return sc;
  735. }
  736.  
  737. STDMETHODIMP COleLinkingDoc::XOleItemContainer::GetObjectStorage(
  738.     LPOLESTR lpszItem, LPBINDCTX /*pbc*/, REFIID riid, LPVOID* ppvStorage)
  739. {
  740.     METHOD_PROLOGUE_EX(COleLinkingDoc, OleItemContainer)
  741.     ASSERT_VALID(pThis);
  742.  
  743.     USES_CONVERSION;
  744.  
  745.     *ppvStorage = NULL;
  746.  
  747.     // only IStorage is supported
  748.     if (riid != IID_IStorage)
  749.         return E_UNEXPECTED;
  750.  
  751.     // check for link to embedding
  752.     COleClientItem* pClientItem = pThis->OnFindEmbeddedItem(OLE2CT(lpszItem));
  753.     if (pClientItem != NULL)
  754.     {
  755.         ASSERT_VALID(pClientItem);
  756.  
  757.         // if object has no storage, can't return it!
  758.         if (pClientItem->m_lpStorage != NULL)
  759.         {
  760.             // found matching item -- return the storage
  761.             *ppvStorage = pClientItem->m_lpStorage;
  762.             pClientItem->m_lpStorage->AddRef();
  763.             return S_OK;
  764.         }
  765.     }
  766.     return MK_E_NOSTORAGE;
  767. }
  768.  
  769. STDMETHODIMP COleLinkingDoc::XOleItemContainer::IsRunning(LPOLESTR lpszItem)
  770. {
  771.     METHOD_PROLOGUE_EX(COleLinkingDoc, OleItemContainer)
  772.     ASSERT_VALID(pThis);
  773.  
  774.     USES_CONVERSION;
  775.  
  776.     // check for link to embedding
  777.     LPCTSTR lpszItemT = OLE2CT(lpszItem);
  778.     COleClientItem* pClientItem = pThis->OnFindEmbeddedItem(lpszItemT);
  779.     if (pClientItem != NULL)
  780.     {
  781.         ASSERT_VALID(pClientItem);
  782.         if (!::OleIsRunning(pClientItem->m_lpObject))
  783.             return S_FALSE;
  784.  
  785.         return S_OK; // item is in document and is running
  786.     }
  787.  
  788.     // check for link to pseudo object
  789.     SCODE sc = MK_E_NOOBJECT;
  790.     TRY
  791.     {
  792.         COleServerItem* pServerItem = pThis->OnGetLinkedItem(lpszItemT);
  793.         if (pServerItem != NULL)
  794.             sc = S_OK;
  795.     }
  796.     END_TRY
  797.  
  798.     return sc;
  799. }
  800.  
  801. /////////////////////////////////////////////////////////////////////////////
  802. // COleLinkingDoc diagnostics
  803.  
  804. #ifdef _DEBUG
  805. void COleLinkingDoc::AssertValid() const
  806. {
  807.     COleDocument::AssertValid();
  808.     if (m_pFactory != NULL)
  809.         m_pFactory->AssertValid();
  810. }
  811.  
  812. void COleLinkingDoc::Dump(CDumpContext& dc) const
  813. {
  814.     COleDocument::Dump(dc);
  815.  
  816.     dc << "\nm_dwRegister = " << m_dwRegister;
  817.     dc << "\nm_bVisibleLock = " << m_bVisibleLock;
  818.     if (m_pFactory != NULL)
  819.         dc << "\nwith factory: " << m_pFactory;
  820.     else
  821.         dc << "\nwith no factory";
  822.  
  823.     dc << "\n";
  824. }
  825. #endif //_DEBUG
  826.  
  827. /////////////////////////////////////////////////////////////////////////////
  828.