home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / mfc / src / olelink.cpp < prev    next >
C/C++ Source or Header  |  1998-06-16  |  22KB  |  847 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 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.         // Note: CException::Delete does not treat m_bAutoDelete as a
  399.         // traditional  BOOL. Only if it is greater than zero does it
  400.         // take on a TRUE quality.  (that is, all tests are for
  401.         // m_bAutoDelete > 0).  So, if m_bAutoDelete is already "true"
  402.         // (1) this will make it false, and if it is already "false"
  403.         //  it is still considered "false".  Valid values for
  404.         // m_bAutoDelete are thus negative, 0, and 1.  Values greater
  405.         // than 1, although not explicitly asserted in CException,
  406.         // would be invalid.  In short, by using increment  and
  407.         // decrement operations, we enable this to work with both
  408.         // self-deleting and non-self-deleting CException classes.
  409.  
  410.         --e->m_bAutoDelete;
  411.  
  412.         // save the exception for later
  413.         m_pLastException = e;
  414.         return;
  415.     }
  416.  
  417.     // otherwise, just call base class
  418.     COleDocument::ReportSaveLoadException(lpszPathName, e, bSaving,
  419.         nIDPDefault);
  420. }
  421.  
  422. SCODE COleLinkingDoc::EndDeferErrors(SCODE sc)
  423. {
  424.     ASSERT(m_bDeferErrors != 0);
  425.     --m_bDeferErrors;
  426.     if (m_pLastException != NULL)
  427.     {
  428.         ASSERT_VALID(m_pLastException);
  429.         if (sc == S_OK)
  430.             sc = COleException::Process(m_pLastException);
  431.  
  432.         // Note: See note above in ReportSaveLoadException for
  433.         // a comment regarding the special treatment of m_bAutoDelete.
  434.  
  435.         ++m_pLastException->m_bAutoDelete;
  436.  
  437.         // now get rid of the exception that we saved
  438.         m_pLastException->Delete();
  439.         m_pLastException = NULL;
  440.     }
  441.     return sc;
  442. }
  443.  
  444. /////////////////////////////////////////////////////////////////////////////
  445. // COleLinkingDoc OLE interface implementation
  446.  
  447. BEGIN_INTERFACE_MAP(COleLinkingDoc, COleDocument)
  448.     INTERFACE_PART(COleLinkingDoc, IID_IPersist, PersistFile)
  449.     INTERFACE_PART(COleLinkingDoc, IID_IPersistFile, PersistFile)
  450.     INTERFACE_PART(COleLinkingDoc, IID_IParseDisplayName, OleItemContainer)
  451.     INTERFACE_PART(COleLinkingDoc, IID_IOleContainer, OleItemContainer)
  452.     INTERFACE_PART(COleLinkingDoc, IID_IOleItemContainer, OleItemContainer)
  453. END_INTERFACE_MAP()
  454.  
  455. /////////////////////////////////////////////////////////////////////////////
  456. // COleLinkingDoc::XPersistFile implementation
  457.  
  458. STDMETHODIMP_(ULONG) COleLinkingDoc::XPersistFile::AddRef()
  459. {
  460.     METHOD_PROLOGUE_EX_(COleLinkingDoc, PersistFile)
  461.     return pThis->ExternalAddRef();
  462. }
  463.  
  464. STDMETHODIMP_(ULONG) COleLinkingDoc::XPersistFile::Release()
  465. {
  466.     METHOD_PROLOGUE_EX_(COleLinkingDoc, PersistFile)
  467.     return pThis->ExternalRelease();
  468. }
  469.  
  470. STDMETHODIMP COleLinkingDoc::XPersistFile::QueryInterface(
  471.     REFIID iid, LPVOID* ppvObj)
  472. {
  473.     METHOD_PROLOGUE_EX_(COleLinkingDoc, PersistFile)
  474.     return pThis->ExternalQueryInterface(&iid, ppvObj);
  475. }
  476.  
  477. STDMETHODIMP COleLinkingDoc::XPersistFile::GetClassID(LPCLSID lpClassID)
  478. {
  479.     METHOD_PROLOGUE_EX_(COleLinkingDoc, PersistFile)
  480.  
  481.     // this is sometimes called for documents not attached to servers!
  482.     if (pThis->m_pFactory == NULL)
  483.     {
  484.         *lpClassID = CLSID_NULL;
  485.         return E_FAIL;
  486.     }
  487.  
  488.     // get the class ID from the connected server object
  489.     ASSERT_VALID(pThis->m_pFactory);
  490.     *lpClassID = pThis->m_pFactory->GetClassID();
  491.     return S_OK;
  492. }
  493.  
  494. STDMETHODIMP COleLinkingDoc::XPersistFile::IsDirty()
  495. {
  496.     METHOD_PROLOGUE_EX(COleLinkingDoc, PersistFile)
  497.     return pThis->IsModified() ? S_OK : S_FALSE;
  498. }
  499.  
  500. STDMETHODIMP COleLinkingDoc::XPersistFile::Load(
  501.     LPCOLESTR lpszFileName, DWORD /*dwMode*/)
  502. {
  503.     METHOD_PROLOGUE_EX(COleLinkingDoc, PersistFile)
  504.     ASSERT_VALID(pThis);
  505.  
  506.     USES_CONVERSION;
  507.  
  508.     CString strFileName;
  509.     SCODE sc = E_FAIL;
  510.     pThis->BeginDeferErrors();
  511.     LPCTSTR lpszFileNameT = OLE2CT(lpszFileName);
  512.     TRY
  513.     {
  514.         BOOL bUserCtrl = AfxOleGetUserCtrl();
  515.  
  516.         // delegate to file-based Open implementation
  517.         if (!pThis->OnOpenDocument(lpszFileNameT))
  518.         {
  519.             AfxOleSetUserCtrl(bUserCtrl);
  520.             return sc;
  521.         }
  522.         pThis->SendInitialUpdate();
  523.  
  524.         // set the path name, but don't add to MRU list
  525.         pThis->SetPathName(lpszFileNameT, FALSE);
  526.         AfxOleSetUserCtrl(bUserCtrl);
  527.  
  528.         sc = S_OK;
  529.     }
  530.     END_TRY
  531.     sc = pThis->EndDeferErrors(sc);
  532.  
  533.     ASSERT_VALID(pThis);
  534.     return sc;
  535. }
  536.  
  537. STDMETHODIMP COleLinkingDoc::XPersistFile::Save(
  538.     LPCOLESTR lpszFileName, BOOL fRemember)
  539. {
  540.     METHOD_PROLOGUE_EX(COleLinkingDoc, PersistFile)
  541.     ASSERT_VALID(pThis);
  542.  
  543.     USES_CONVERSION;
  544.  
  545.     CString strFileName;
  546.     SCODE sc = E_FAIL;
  547.     pThis->BeginDeferErrors();
  548.     TRY
  549.     {
  550.         // delegate to file-based Save/Save As implementation
  551.         ASSERT(pThis->m_bRemember);
  552.         pThis->m_bRemember = fRemember;
  553.         pThis->OnSaveDocument(OLE2CT(lpszFileName));
  554.         sc = S_OK;
  555.     }
  556.     END_TRY
  557.     sc = pThis->EndDeferErrors(sc);
  558.  
  559.     ASSERT_VALID(pThis);
  560.     return sc;
  561. }
  562.  
  563. STDMETHODIMP COleLinkingDoc::XPersistFile::SaveCompleted(LPCOLESTR lpszFileName)
  564. {
  565.     METHOD_PROLOGUE_EX(COleLinkingDoc, PersistFile)
  566.     ASSERT_VALID(pThis);
  567.  
  568.     USES_CONVERSION;
  569.  
  570.     TRY
  571.     {
  572.         // set the path name, but don't add to MRU list
  573.         pThis->SetPathName(OLE2CT(lpszFileName), FALSE);
  574.     }
  575.     END_TRY
  576.  
  577.     ASSERT_VALID(pThis);
  578.     return S_OK;
  579. }
  580.  
  581. STDMETHODIMP COleLinkingDoc::XPersistFile::GetCurFile(LPOLESTR* lplpszFileName)
  582. {
  583.     METHOD_PROLOGUE_EX_(COleLinkingDoc, PersistFile)
  584.  
  585.     *lplpszFileName = NULL;
  586.  
  587.     // use title if no document
  588.     LPCTSTR lpszResult;
  589.     if (pThis->m_strPathName.IsEmpty())
  590.         lpszResult = pThis->m_strTitle;
  591.     else
  592.         lpszResult = pThis->m_strPathName;
  593.     ASSERT(lpszResult != NULL);
  594.  
  595.     // allocate memory for the file name
  596.     *lplpszFileName = AfxAllocTaskOleString(lpszResult);
  597.     if (*lplpszFileName == NULL)
  598.         return E_OUTOFMEMORY;
  599.  
  600.     ASSERT_VALID(pThis);
  601.     return S_OK;
  602. }
  603.  
  604. /////////////////////////////////////////////////////////////////////////////
  605. // Implementation of IOleItemContainer
  606. //  (supports linking to embeddings and linking to pseudo-objects)
  607.  
  608. STDMETHODIMP_(ULONG) COleLinkingDoc::XOleItemContainer::AddRef()
  609. {
  610.     METHOD_PROLOGUE_EX_(COleLinkingDoc, OleItemContainer)
  611.     return pThis->ExternalAddRef();
  612. }
  613.  
  614. STDMETHODIMP_(ULONG) COleLinkingDoc::XOleItemContainer::Release()
  615. {
  616.     METHOD_PROLOGUE_EX_(COleLinkingDoc, OleItemContainer)
  617.     return pThis->ExternalRelease();
  618. }
  619.  
  620. STDMETHODIMP COleLinkingDoc::XOleItemContainer::QueryInterface(
  621.     REFIID iid, LPVOID* ppvObj)
  622. {
  623.     METHOD_PROLOGUE_EX_(COleLinkingDoc, OleItemContainer)
  624.     return pThis->ExternalQueryInterface(&iid, ppvObj);
  625. }
  626.  
  627. STDMETHODIMP COleLinkingDoc::XOleItemContainer::EnumObjects(
  628.     DWORD /*grfFlags*/, LPENUMUNKNOWN* ppEnumUnknown)
  629. {
  630.     *ppEnumUnknown = NULL;
  631.     return E_NOTIMPL;
  632. }
  633.  
  634. STDMETHODIMP COleLinkingDoc::XOleItemContainer::ParseDisplayName(LPBC lpbc,
  635.     LPOLESTR lpszDisplayName, ULONG* cchEaten, LPMONIKER* ppMoniker)
  636. {
  637.     METHOD_PROLOGUE_EX_(COleLinkingDoc, OleItemContainer)
  638.  
  639.     USES_CONVERSION;
  640.  
  641.     // reset all OUT parameters
  642.     *ppMoniker = NULL;
  643.  
  644.     TCHAR szItemName[OLE_MAXNAMESIZE];
  645.     LPTSTR lpszDest = szItemName;
  646.     LPCTSTR lpszSrc = OLE2CT(lpszDisplayName);
  647.  
  648.     // skip leading delimiters
  649.     int cEaten = 0;
  650.     while (*lpszSrc != '\0' && (*lpszSrc == '\\' || *lpszSrc == '/' ||
  651.         *lpszSrc == ':' || *lpszSrc == '!' || *lpszSrc == '['))
  652.     {
  653.         if (_istlead(*lpszSrc))
  654.             ++lpszSrc, ++cEaten;
  655.         ++lpszSrc;
  656.         ++cEaten;
  657.     }
  658.  
  659.     // parse next token in szItemName
  660.     while (*lpszSrc != '\0' && *lpszSrc != '\\' && *lpszSrc != '/' &&
  661.         *lpszSrc != ':' && *lpszSrc != '!' && *lpszSrc != '[' &&
  662.         cEaten < OLE_MAXNAMESIZE-1)
  663.     {
  664.         if (_istlead(*lpszSrc))
  665.             *lpszDest++ = *lpszSrc++, ++cEaten;
  666.         *lpszDest++ = *lpszSrc++;
  667.         ++cEaten;
  668.     }
  669.     *cchEaten = cEaten;
  670.     *lpszDest = 0;
  671.  
  672.     // attempt to get the object
  673.     LPUNKNOWN lpUnknown;
  674.     SCODE sc = GetObject(T2OLE(szItemName), BINDSPEED_INDEFINITE, lpbc,
  675.         IID_IUnknown, (LPLP)&lpUnknown);
  676.     if (sc != S_OK)
  677.         return sc;
  678.  
  679.     // item name found -- create item moniker for it
  680.     lpUnknown->Release();
  681.     return CreateItemMoniker(OLESTDDELIMOLE, T2COLE(szItemName), ppMoniker);
  682. }
  683.  
  684. STDMETHODIMP COleLinkingDoc::XOleItemContainer::LockContainer(BOOL fLock)
  685. {
  686.     METHOD_PROLOGUE_EX_(COleLinkingDoc, OleItemContainer)
  687.  
  688.     pThis->LockExternal(fLock, TRUE);
  689.     return S_OK;
  690. }
  691.  
  692. STDMETHODIMP COleLinkingDoc::XOleItemContainer::GetObject(
  693.     LPOLESTR lpszItem, DWORD dwSpeedNeeded, LPBINDCTX /*pbc*/, REFIID riid,
  694.     LPVOID* ppvObject)
  695. {
  696.     METHOD_PROLOGUE_EX(COleLinkingDoc, OleItemContainer)
  697.     ASSERT_VALID(pThis);
  698.  
  699.     USES_CONVERSION;
  700.  
  701.     *ppvObject = NULL;
  702.  
  703.     SCODE sc = MK_E_NOOBJECT;
  704.     TRY
  705.     {
  706.         LPCTSTR lpszItemT = OLE2CT(lpszItem);
  707.         // check for link to embedding
  708.         COleClientItem* pClientItem = pThis->OnFindEmbeddedItem(lpszItemT);
  709.         if (pClientItem != NULL)
  710.         {
  711.             ASSERT_VALID(pClientItem);
  712.             sc = S_OK;
  713.  
  714.             // item found -- make sure it is running
  715.             if (!::OleIsRunning(pClientItem->m_lpObject))
  716.             {
  717.                 // should not run the object if bind-speed is immediate
  718.                 if (dwSpeedNeeded != BINDSPEED_INDEFINITE)
  719.                     sc = MK_E_EXCEEDEDDEADLINE;
  720.                 else
  721.                 {
  722.                     // bind speed is not immediate -- so run the object
  723.                     sc = OleRun(pClientItem->m_lpObject);
  724.                 }
  725.             }
  726.  
  727.             if (sc == S_OK)
  728.             {
  729.                 // return the object with appropriate interface
  730.                 sc = pClientItem->m_lpObject->QueryInterface(riid, ppvObject);
  731.             }
  732.         }
  733.         else
  734.         {
  735.             // check for link to pseudo object
  736.             COleServerItem* pServerItem = pThis->OnGetLinkedItem(lpszItemT);
  737.             if (pServerItem != NULL)
  738.             {
  739.                 if (!pServerItem->m_bNeedUnlock)
  740.                 {
  741.                     // when a link is bound, the document must be kept alive
  742.                     pThis->LockExternal(TRUE, FALSE);
  743.                     pServerItem->m_bNeedUnlock = TRUE;
  744.                 }
  745.  
  746.                 // matching item found -- query for the requested interface
  747.                 sc = pServerItem->ExternalQueryInterface(&riid, ppvObject);
  748.             }
  749.         }
  750.     }
  751.     END_TRY
  752.  
  753.     return sc;
  754. }
  755.  
  756. STDMETHODIMP COleLinkingDoc::XOleItemContainer::GetObjectStorage(
  757.     LPOLESTR lpszItem, LPBINDCTX /*pbc*/, REFIID riid, LPVOID* ppvStorage)
  758. {
  759.     METHOD_PROLOGUE_EX(COleLinkingDoc, OleItemContainer)
  760.     ASSERT_VALID(pThis);
  761.  
  762.     USES_CONVERSION;
  763.  
  764.     *ppvStorage = NULL;
  765.  
  766.     // only IStorage is supported
  767.     if (riid != IID_IStorage)
  768.         return E_UNEXPECTED;
  769.  
  770.     // check for link to embedding
  771.     COleClientItem* pClientItem = pThis->OnFindEmbeddedItem(OLE2CT(lpszItem));
  772.     if (pClientItem != NULL)
  773.     {
  774.         ASSERT_VALID(pClientItem);
  775.  
  776.         // if object has no storage, can't return it!
  777.         if (pClientItem->m_lpStorage != NULL)
  778.         {
  779.             // found matching item -- return the storage
  780.             *ppvStorage = pClientItem->m_lpStorage;
  781.             pClientItem->m_lpStorage->AddRef();
  782.             return S_OK;
  783.         }
  784.     }
  785.     return MK_E_NOSTORAGE;
  786. }
  787.  
  788. STDMETHODIMP COleLinkingDoc::XOleItemContainer::IsRunning(LPOLESTR lpszItem)
  789. {
  790.     METHOD_PROLOGUE_EX(COleLinkingDoc, OleItemContainer)
  791.     ASSERT_VALID(pThis);
  792.  
  793.     USES_CONVERSION;
  794.  
  795.     // check for link to embedding
  796.     LPCTSTR lpszItemT = OLE2CT(lpszItem);
  797.     COleClientItem* pClientItem = pThis->OnFindEmbeddedItem(lpszItemT);
  798.     if (pClientItem != NULL)
  799.     {
  800.         ASSERT_VALID(pClientItem);
  801.         if (!::OleIsRunning(pClientItem->m_lpObject))
  802.             return S_FALSE;
  803.  
  804.         return S_OK; // item is in document and is running
  805.     }
  806.  
  807.     // check for link to pseudo object
  808.     SCODE sc = MK_E_NOOBJECT;
  809.     TRY
  810.     {
  811.         COleServerItem* pServerItem = pThis->OnGetLinkedItem(lpszItemT);
  812.         if (pServerItem != NULL)
  813.             sc = S_OK;
  814.     }
  815.     END_TRY
  816.  
  817.     return sc;
  818. }
  819.  
  820. /////////////////////////////////////////////////////////////////////////////
  821. // COleLinkingDoc diagnostics
  822.  
  823. #ifdef _DEBUG
  824. void COleLinkingDoc::AssertValid() const
  825. {
  826.     COleDocument::AssertValid();
  827.     if (m_pFactory != NULL)
  828.         m_pFactory->AssertValid();
  829. }
  830.  
  831. void COleLinkingDoc::Dump(CDumpContext& dc) const
  832. {
  833.     COleDocument::Dump(dc);
  834.  
  835.     dc << "\nm_dwRegister = " << m_dwRegister;
  836.     dc << "\nm_bVisibleLock = " << m_bVisibleLock;
  837.     if (m_pFactory != NULL)
  838.         dc << "\nwith factory: " << m_pFactory;
  839.     else
  840.         dc << "\nwith no factory";
  841.  
  842.     dc << "\n";
  843. }
  844. #endif //_DEBUG
  845.  
  846. /////////////////////////////////////////////////////////////////////////////
  847.