olelink.cpp 21 KB

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