oledoc1.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879
  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_OLE_SEG
  12. #pragma code_seg(AFX_OLE_SEG)
  13. #endif
  14. #ifdef _DEBUG
  15. #undef THIS_FILE
  16. static char THIS_FILE[] = __FILE__;
  17. #endif
  18. #define new DEBUG_NEW
  19. /////////////////////////////////////////////////////////////////////////////
  20. // COleDocument - enables both server and client
  21. COleDocument::COleDocument()
  22. {
  23. ASSERT(m_viewList.IsEmpty());
  24. ASSERT(m_docItemList.IsEmpty());
  25. #ifdef _DEBUG
  26. // check for common mistake of not initializing OLE libraries before
  27. // creating an OLE document.
  28. LPMALLOC lpMalloc = NULL;
  29. if (::CoGetMalloc(MEMCTX_TASK, &lpMalloc) != S_OK)
  30. {
  31. TRACE0("Warning: CoGetMalloc(MEMCTX_TASK, ...) failed --\n");
  32. TRACE0("\tperhaps AfxOleInit() has not been called.\n");
  33. }
  34. RELEASE(lpMalloc);
  35. #endif
  36. m_dwNextItemNumber = 1; // item number for first item in document
  37. m_bLastVisible = FALSE;
  38. m_bRemember = TRUE;
  39. m_bSameAsLoad = TRUE;
  40. m_lpRootStg = NULL;
  41. m_ptd = NULL; // default to screen target device
  42. m_bCompoundFile = FALSE;
  43. AfxOleLockApp();
  44. }
  45. COleDocument::~COleDocument()
  46. {
  47. ASSERT_VALID(this);
  48. #ifdef _DEBUG
  49. if (!m_docItemList.IsEmpty())
  50. TRACE1("Warning: destroying COleDocument with %d doc items.\n",
  51. m_docItemList.GetCount());
  52. #endif
  53. // remove all doc-items from the list before shutting down the storage
  54. POSITION pos = GetStartPosition();
  55. while (pos != NULL)
  56. {
  57. CDocItem* pItem = GetNextItem(pos);
  58. ASSERT(pItem != NULL);
  59. delete pItem;
  60. }
  61. // release the hold on the document storage
  62. RELEASE(m_lpRootStg);
  63. CoTaskMemFree(m_ptd);
  64. AfxOleUnlockApp();
  65. }
  66. /////////////////////////////////////////////////////////////////////////////
  67. // DocItem management
  68. void COleDocument::AddItem(CDocItem* pItem)
  69. {
  70. // don't do an ASSERT_VALID until after we've added it !
  71. ASSERT_KINDOF(CDocItem, pItem);
  72. ASSERT(pItem->m_pDocument == NULL); // not yet initialized
  73. m_docItemList.AddTail(pItem);
  74. pItem->m_pDocument = this;
  75. ASSERT_VALID(pItem); // now it must be valid
  76. }
  77. void COleDocument::RemoveItem(CDocItem* pItem)
  78. {
  79. ASSERT_VALID(pItem); // must be valid before detach
  80. ASSERT_KINDOF(CDocItem, pItem);
  81. ASSERT(pItem->m_pDocument == this); // formerly attached
  82. ASSERT(m_docItemList.Find(pItem) != NULL); // must be in list
  83. m_docItemList.RemoveAt(m_docItemList.Find(pItem));
  84. ASSERT(m_docItemList.Find(pItem) == NULL); // must not be in list now
  85. pItem->m_pDocument = NULL;
  86. }
  87. POSITION COleDocument::GetStartPosition() const
  88. {
  89. ASSERT_VALID(this);
  90. return m_docItemList.GetHeadPosition();
  91. }
  92. CDocItem* COleDocument::GetNextItem(POSITION& pos) const
  93. {
  94. // handle special case of !pos -- makes enumeration code smaller
  95. if (pos == NULL)
  96. return NULL;
  97. // otherwise get next item from list
  98. ASSERT_VALID(this);
  99. CDocItem* pItem = (CDocItem*)m_docItemList.GetNext(pos);
  100. ASSERT(pItem != NULL);
  101. ASSERT_KINDOF(CDocItem, pItem);
  102. ASSERT(pItem->m_pDocument == this); // must be ours
  103. return pItem;
  104. }
  105. CDocItem*
  106. COleDocument::GetNextItemOfKind(POSITION& pos, CRuntimeClass* pClass) const
  107. {
  108. while (pos != NULL)
  109. {
  110. CDocItem* pItem = GetNextItem(pos);
  111. ASSERT_VALID(pItem);
  112. if (pItem->IsKindOf(pClass))
  113. return pItem;
  114. }
  115. return NULL; // no suitable item found
  116. }
  117. COleClientItem* COleDocument::GetNextClientItem(POSITION& pos) const
  118. {
  119. COleClientItem *pItem =
  120. (COleClientItem*)GetNextItemOfKind(pos, RUNTIME_CLASS(COleClientItem));
  121. return pItem;
  122. }
  123. COleServerItem* COleDocument::GetNextServerItem(POSITION& pos) const
  124. {
  125. COleServerItem *pItem =
  126. (COleServerItem*)GetNextItemOfKind(pos, RUNTIME_CLASS(COleServerItem));
  127. return pItem;
  128. }
  129. void COleDocument::DeleteContents()
  130. {
  131. // deletes all COleClientItem objects in the doc item list
  132. // (Note: doesn't touch server items or other docitems)
  133. POSITION pos = GetStartPosition();
  134. COleClientItem* pItem;
  135. while ((pItem = GetNextClientItem(pos)) != NULL)
  136. {
  137. if (pItem->m_lpObject != NULL)
  138. {
  139. pItem->Release(OLECLOSE_NOSAVE); // release OLE object
  140. RemoveItem(pItem); // disconnect from document
  141. pItem->InternalRelease(); // may 'delete pItem'
  142. }
  143. }
  144. }
  145. void COleDocument::SetPathName(LPCTSTR lpszPathName, BOOL bAddToMRU)
  146. {
  147. USES_CONVERSION;
  148. CDocument::SetPathName(lpszPathName, bAddToMRU);
  149. // update all of the objects' host names
  150. POSITION pos = GetStartPosition();
  151. COleClientItem* pItem;
  152. while ((pItem = GetNextClientItem(pos)) != NULL)
  153. {
  154. // update that item's host names
  155. pItem->m_lpObject->SetHostNames(T2COLE(AfxGetAppName()),
  156. T2COLE(m_strTitle));
  157. }
  158. }
  159. void COleDocument::Serialize(CArchive& ar)
  160. {
  161. ASSERT_VALID(this);
  162. // serialize all items in the doc item list
  163. if (ar.IsStoring())
  164. {
  165. DWORD dwCount = 0;
  166. POSITION pos = GetStartPosition();
  167. while (pos != NULL)
  168. {
  169. CDocItem* pDocItem = GetNextItem(pos);
  170. ASSERT_VALID(pDocItem);
  171. // only count non-blank ones
  172. if (!pDocItem->IsBlank())
  173. ++dwCount;
  174. }
  175. ar << dwCount; // write count of objects
  176. // serialize all the items in the list
  177. pos = GetStartPosition();
  178. while (pos != NULL)
  179. {
  180. CDocItem* pDocItem = GetNextItem(pos);
  181. ASSERT_VALID(pDocItem);
  182. // only write non-blank ones
  183. if (!pDocItem->IsBlank())
  184. ar << pDocItem;
  185. }
  186. }
  187. else
  188. {
  189. // read number of items in the file
  190. DWORD dwCount;
  191. ar >> dwCount;
  192. // read all of them into the list
  193. while (dwCount--)
  194. {
  195. CDocItem* pDocItem;
  196. ar >> pDocItem; // as they are serialized, they are added!
  197. }
  198. }
  199. }
  200. void COleDocument::CommitItems(BOOL bSuccess)
  201. {
  202. // special 'Commit' phase for COleClientItem items
  203. POSITION pos = GetStartPosition();
  204. COleClientItem* pItem;
  205. while ((pItem = GetNextClientItem(pos)) != NULL)
  206. {
  207. // calling CommitItem with FALSE causes the object to revert
  208. // to the original storage. Calling CommitItem TRUE causes
  209. // the item to adopt the new storage created in the Serialize
  210. // function.
  211. pItem->CommitItem(bSuccess);
  212. }
  213. }
  214. BOOL COleDocument::HasBlankItems() const
  215. {
  216. ASSERT_VALID(this);
  217. POSITION pos = GetStartPosition();
  218. while (pos != NULL)
  219. {
  220. CDocItem* pDocItem = GetNextItem(pos);
  221. ASSERT_VALID(pDocItem);
  222. if (pDocItem->IsBlank())
  223. return TRUE; // blank item found
  224. }
  225. return FALSE; // no items found that were blank
  226. }
  227. void COleDocument::UpdateModifiedFlag()
  228. {
  229. ASSERT_VALID(this);
  230. POSITION pos = GetStartPosition();
  231. COleClientItem* pItem;
  232. while ((pItem = GetNextClientItem(pos)) != NULL)
  233. {
  234. if (pItem->IsModified())
  235. {
  236. SetModifiedFlag();
  237. break;
  238. }
  239. }
  240. }
  241. void COleDocument::PreCloseFrame(CFrameWnd* pFrameArg)
  242. {
  243. ASSERT_VALID(this);
  244. ASSERT_VALID(pFrameArg);
  245. // turn off redraw so the user doesn't see the deactivation happening
  246. BOOL bSetRedraw = FALSE;
  247. if (pFrameArg->GetStyle() & WS_VISIBLE)
  248. {
  249. pFrameArg->SendMessage(WM_SETREDRAW, (WPARAM)FALSE);
  250. bSetRedraw = TRUE;
  251. }
  252. // deactivate any inplace active items on this frame
  253. COleClientItem* pItem = GetInPlaceActiveItem(pFrameArg);
  254. if (pItem != NULL)
  255. {
  256. pItem->Deactivate();
  257. pItem->Close(OLECLOSE_NOSAVE);
  258. }
  259. // turn redraw back on
  260. if (bSetRedraw)
  261. pFrameArg->SendMessage(WM_SETREDRAW, (WPARAM)TRUE);
  262. // should not have any inplace active items
  263. ASSERT(GetInPlaceActiveItem(pFrameArg) == NULL);
  264. }
  265. BOOL COleDocument::SaveModified()
  266. {
  267. // determine if necessary to discard changes
  268. if (::InSendMessage())
  269. {
  270. POSITION pos = GetStartPosition();
  271. COleClientItem* pItem;
  272. while ((pItem = GetNextClientItem(pos)) != NULL)
  273. {
  274. ASSERT(pItem->m_lpObject != NULL);
  275. SCODE sc = pItem->m_lpObject->IsUpToDate();
  276. if (sc != OLE_E_NOTRUNNING && FAILED(sc))
  277. {
  278. // inside inter-app SendMessage limits the user's choices
  279. CString name = m_strPathName;
  280. if (name.IsEmpty())
  281. VERIFY(name.LoadString(AFX_IDS_UNTITLED));
  282. CString prompt;
  283. AfxFormatString1(prompt, AFX_IDP_ASK_TO_DISCARD, name);
  284. return AfxMessageBox(prompt, MB_OKCANCEL|MB_DEFBUTTON2,
  285. AFX_IDP_ASK_TO_DISCARD) == IDOK;
  286. }
  287. }
  288. }
  289. // sometimes items change without a notification, so we have to
  290. // update the document's modified flag before calling
  291. // CDocument::SaveModified.
  292. UpdateModifiedFlag();
  293. return CDocument::SaveModified();
  294. }
  295. void COleDocument::OnShowViews(BOOL /*bVisible*/)
  296. {
  297. // no default implementation
  298. }
  299. void COleDocument::OnIdle()
  300. {
  301. ASSERT_VALID(this);
  302. // determine if any visible views are on this document
  303. BOOL bVisible = FALSE;
  304. POSITION pos = GetFirstViewPosition();
  305. while (pos != NULL)
  306. {
  307. CView* pView = GetNextView(pos);
  308. ASSERT_VALID(pView);
  309. CFrameWnd* pFrameWnd = pView->GetParentFrame();
  310. ASSERT_VALID(pFrameWnd);
  311. if (pFrameWnd->GetStyle() & WS_VISIBLE)
  312. {
  313. bVisible = TRUE;
  314. break;
  315. }
  316. }
  317. // when state has changed, call OnShowViews
  318. if (bVisible != m_bLastVisible)
  319. {
  320. OnShowViews(bVisible);
  321. m_bLastVisible = bVisible;
  322. }
  323. }
  324. /////////////////////////////////////////////////////////////////////////////
  325. // COleDocument -> window mapping
  326. CFrameWnd* COleDocument::GetFirstFrame()
  327. {
  328. ASSERT_VALID(this);
  329. // get position of first view in the document
  330. POSITION pos = GetFirstViewPosition();
  331. // get view at that position
  332. CView* pView = GetNextView(pos);
  333. if (pView == NULL)
  334. return NULL;
  335. ASSERT_VALID(pView);
  336. // return the first frame window that is a parent of that view
  337. CFrameWnd* pFrameWnd = (CFrameWnd*)pView->GetParentFrame();
  338. ASSERT_VALID(pFrameWnd);
  339. ASSERT_KINDOF(CFrameWnd, pFrameWnd);
  340. return pFrameWnd;
  341. }
  342. /////////////////////////////////////////////////////////////////////////////
  343. // COleDocument helpers
  344. LPMONIKER COleDocument::GetMoniker(OLEGETMONIKER /*nAssign*/)
  345. {
  346. USES_CONVERSION;
  347. ASSERT_VALID(this);
  348. // no moniker for untitled documents
  349. if (m_strPathName.IsEmpty())
  350. return NULL;
  351. // return file moniker based on current path name
  352. LPMONIKER lpMoniker;
  353. CreateFileMoniker(T2COLE(m_strPathName), &lpMoniker);
  354. return lpMoniker;
  355. }
  356. LPOLEITEMCONTAINER COleDocument::GetContainer()
  357. {
  358. // COleDocument doesn't support IOleClientSite::GetContainer
  359. return NULL;
  360. }
  361. /////////////////////////////////////////////////////////////////////////////
  362. // 'Compound File' enabling in COleDocument
  363. BOOL COleDocument::OnNewDocument()
  364. {
  365. // call base class, which destroys all items
  366. if (!CDocument::OnNewDocument())
  367. return FALSE;
  368. // for file-based compound files, need to create temporary file
  369. if (m_bCompoundFile && !m_bEmbedded)
  370. {
  371. // abort changes to the current docfile
  372. RELEASE(m_lpRootStg);
  373. // create new temporary docfile
  374. LPSTORAGE lpStorage;
  375. SCODE sc = ::StgCreateDocfile(NULL, STGM_DELETEONRELEASE|
  376. STGM_READWRITE|STGM_TRANSACTED|STGM_SHARE_EXCLUSIVE|STGM_CREATE,
  377. 0, &lpStorage);
  378. if (sc != S_OK)
  379. return FALSE;
  380. ASSERT(lpStorage != NULL);
  381. m_lpRootStg = lpStorage;
  382. }
  383. return TRUE;
  384. }
  385. BOOL COleDocument::OnOpenDocument(LPCTSTR lpszPathName)
  386. {
  387. USES_CONVERSION;
  388. ASSERT(lpszPathName == NULL || AfxIsValidString(lpszPathName));
  389. // just use default implementation if 'docfile' not enabled
  390. if (!m_bCompoundFile && m_lpRootStg == NULL)
  391. {
  392. ASSERT(lpszPathName != NULL);
  393. return CDocument::OnOpenDocument(lpszPathName);
  394. }
  395. if (IsModified())
  396. TRACE0("Warning: OnOpenDocument replaces an unsaved document.\n");
  397. // abort changes to current docfile
  398. if (lpszPathName != NULL)
  399. {
  400. DeleteContents();
  401. RELEASE(m_lpRootStg);
  402. }
  403. SetModifiedFlag(); // dirty during de-serialize
  404. BOOL bResult = FALSE;
  405. TRY
  406. {
  407. if (m_lpRootStg == NULL)
  408. {
  409. LPCOLESTR lpsz = T2COLE(lpszPathName);
  410. // use STGM_CONVERT if necessary
  411. SCODE sc;
  412. LPSTORAGE lpStorage = NULL;
  413. if (StgIsStorageFile(lpsz) == S_FALSE)
  414. {
  415. // convert existing storage file
  416. sc = StgCreateDocfile(lpsz, STGM_READWRITE|
  417. STGM_TRANSACTED|STGM_SHARE_DENY_WRITE|STGM_CONVERT,
  418. 0, &lpStorage);
  419. if (FAILED(sc) || lpStorage == NULL)
  420. sc = StgCreateDocfile(lpsz, STGM_READ|
  421. STGM_TRANSACTED|STGM_CONVERT, 0, &lpStorage);
  422. }
  423. else
  424. {
  425. // open new storage file
  426. sc = StgOpenStorage(lpsz, NULL,
  427. STGM_READWRITE|STGM_TRANSACTED|STGM_SHARE_DENY_WRITE,
  428. 0, 0, &lpStorage);
  429. if (FAILED(sc) || lpStorage == NULL)
  430. sc = StgOpenStorage(lpsz, NULL,
  431. STGM_READ|STGM_TRANSACTED, 0, 0, &lpStorage);
  432. }
  433. if (FAILED(sc))
  434. AfxThrowOleException(sc);
  435. ASSERT(lpStorage != NULL);
  436. m_lpRootStg = lpStorage;
  437. }
  438. // use helper to read document from storage
  439. LoadFromStorage();
  440. SetModifiedFlag(FALSE); // start off with unmodified
  441. bResult = TRUE;
  442. }
  443. CATCH_ALL(e)
  444. {
  445. DeleteContents(); // removed failed contents
  446. RELEASE(m_lpRootStg);
  447. // if not file-based load, return exceptions to the caller
  448. if (lpszPathName == NULL)
  449. {
  450. THROW_LAST();
  451. ASSERT(FALSE); // not reached
  452. }
  453. TRY
  454. {
  455. ReportSaveLoadException(lpszPathName, e,
  456. FALSE, AFX_IDP_FAILED_TO_OPEN_DOC);
  457. }
  458. END_TRY
  459. DELETE_EXCEPTION(e);
  460. }
  461. END_CATCH_ALL
  462. return bResult;
  463. }
  464. BOOL COleDocument::OnSaveDocument(LPCTSTR lpszPathName)
  465. // lpszPathName must be fully qualified
  466. {
  467. USES_CONVERSION;
  468. ASSERT(lpszPathName == NULL || AfxIsValidString(lpszPathName));
  469. // use default implementation if 'docfile' not enabled
  470. if (!m_bCompoundFile && m_lpRootStg == NULL)
  471. {
  472. ASSERT(lpszPathName != NULL);
  473. return CDocument::OnSaveDocument(lpszPathName);
  474. }
  475. LPSTORAGE lpOrigStg = NULL;
  476. if (lpszPathName != NULL)
  477. m_bSameAsLoad = AfxComparePath(m_strPathName, lpszPathName);
  478. BOOL bResult = FALSE;
  479. TRY
  480. {
  481. // open new root storage if necessary
  482. if (lpszPathName != NULL && !m_bSameAsLoad)
  483. {
  484. // temporarily detach current storage
  485. lpOrigStg = m_lpRootStg;
  486. m_lpRootStg = NULL;
  487. LPSTORAGE lpStorage;
  488. SCODE sc = ::StgCreateDocfile(T2COLE(lpszPathName),
  489. STGM_READWRITE|STGM_TRANSACTED|STGM_SHARE_DENY_WRITE|STGM_CREATE,
  490. 0, &lpStorage);
  491. if (sc != S_OK)
  492. AfxThrowOleException(sc);
  493. ASSERT(lpStorage != NULL);
  494. m_lpRootStg = lpStorage;
  495. }
  496. ASSERT(m_lpRootStg != NULL);
  497. // use helper to save to root storage
  498. SaveToStorage();
  499. if (lpszPathName != NULL)
  500. {
  501. // commit each of the items
  502. CommitItems(m_bRemember && !m_bSameAsLoad);
  503. // mark document as clean if remembering the storage
  504. if (m_bRemember)
  505. SetModifiedFlag(FALSE);
  506. // remember correct storage or release save copy as storage
  507. if (!m_bSameAsLoad)
  508. {
  509. if (m_bRemember)
  510. {
  511. // Save As case -- m_stgRoot is new storage, forget old storage
  512. lpOrigStg->Release();
  513. }
  514. else
  515. {
  516. // Save Copy As case -- m_stgRoot should hook up to m_stgOrig.
  517. m_lpRootStg->Release();
  518. m_lpRootStg = lpOrigStg;
  519. }
  520. }
  521. }
  522. bResult = TRUE;
  523. }
  524. CATCH_ALL(e)
  525. {
  526. if (lpOrigStg != NULL)
  527. {
  528. // save as failed: abort new storage, and re-attach original
  529. RELEASE(m_lpRootStg);
  530. m_lpRootStg = lpOrigStg;
  531. }
  532. if (lpszPathName == NULL)
  533. {
  534. THROW_LAST();
  535. ASSERT(FALSE); // not reached
  536. }
  537. TRY
  538. {
  539. ReportSaveLoadException(lpszPathName, e,
  540. TRUE, AFX_IDP_FAILED_TO_SAVE_DOC);
  541. }
  542. END_TRY
  543. DELETE_EXCEPTION(e);
  544. }
  545. END_CATCH_ALL
  546. // cleanup
  547. m_bSameAsLoad = TRUE;
  548. m_bRemember = TRUE;
  549. return bResult;
  550. }
  551. void COleDocument::OnCloseDocument()
  552. {
  553. // close the document without deleting the memory
  554. BOOL bAutoDelete = m_bAutoDelete;
  555. m_bAutoDelete = FALSE;
  556. CDocument::OnCloseDocument();
  557. // release storage since document has been closed
  558. RELEASE(m_lpRootStg);
  559. // delete the document if necessary
  560. if (bAutoDelete)
  561. delete this;
  562. }
  563. /////////////////////////////////////////////////////////////////////////////
  564. // Helpers for saving to IStorage based files
  565. // (these are used in the 'docfile' implementation as well as for servers)
  566. void COleDocument::SaveToStorage(CObject* pObject)
  567. {
  568. ASSERT(m_lpRootStg != NULL);
  569. // create Contents stream
  570. COleStreamFile file;
  571. CFileException fe;
  572. if (!file.CreateStream(m_lpRootStg, _T("Contents"),
  573. CFile::modeReadWrite|CFile::shareExclusive|CFile::modeCreate, &fe))
  574. {
  575. if (fe.m_cause == CFileException::fileNotFound)
  576. AfxThrowArchiveException(CArchiveException::badSchema);
  577. else
  578. AfxThrowFileException(fe.m_cause, fe.m_lOsError);
  579. }
  580. // save to Contents stream
  581. CArchive saveArchive(&file, CArchive::store | CArchive::bNoFlushOnDelete);
  582. saveArchive.m_pDocument = this;
  583. saveArchive.m_bForceFlat = FALSE;
  584. TRY
  585. {
  586. // save the contents
  587. if (pObject != NULL)
  588. pObject->Serialize(saveArchive);
  589. else
  590. Serialize(saveArchive);
  591. saveArchive.Close();
  592. file.Close();
  593. // commit the root storage
  594. SCODE sc = m_lpRootStg->Commit(STGC_ONLYIFCURRENT);
  595. if (sc != S_OK)
  596. AfxThrowOleException(sc);
  597. }
  598. CATCH_ALL(e)
  599. {
  600. file.Abort(); // will not throw an exception
  601. CommitItems(FALSE); // abort save in progress
  602. NO_CPP_EXCEPTION(saveArchive.Abort());
  603. THROW_LAST();
  604. }
  605. END_CATCH_ALL
  606. }
  607. void COleDocument::LoadFromStorage()
  608. {
  609. ASSERT(m_lpRootStg != NULL);
  610. // open Contents stream
  611. COleStreamFile file;
  612. CFileException fe;
  613. if (!file.OpenStream(m_lpRootStg, _T("Contents"),
  614. CFile::modeRead|CFile::shareExclusive, &fe) &&
  615. !file.CreateStream(m_lpRootStg, _T("Contents"),
  616. CFile::modeRead|CFile::shareExclusive|CFile::modeCreate, &fe))
  617. {
  618. if (fe.m_cause == CFileException::fileNotFound)
  619. AfxThrowArchiveException(CArchiveException::badSchema);
  620. else
  621. AfxThrowFileException(fe.m_cause, fe.m_lOsError);
  622. }
  623. // load it with CArchive (loads from Contents stream)
  624. CArchive loadArchive(&file, CArchive::load | CArchive::bNoFlushOnDelete);
  625. loadArchive.m_pDocument = this;
  626. loadArchive.m_bForceFlat = FALSE;
  627. TRY
  628. {
  629. if (file.GetLength() != 0)
  630. Serialize(loadArchive); // load main contents
  631. loadArchive.Close();
  632. file.Close();
  633. }
  634. CATCH_ALL(e)
  635. {
  636. file.Abort(); // will not throw an exception
  637. DeleteContents(); // removed failed contents
  638. NO_CPP_EXCEPTION(loadArchive.Abort());
  639. THROW_LAST();
  640. }
  641. END_CATCH_ALL
  642. }
  643. /////////////////////////////////////////////////////////////////////////////
  644. // COleDocument diagnostics
  645. #ifdef _DEBUG
  646. void COleDocument::AssertValid() const
  647. {
  648. CDocument::AssertValid();
  649. ASSERT(m_ptd == NULL || AfxIsValidAddress(m_ptd, (size_t)m_ptd->tdSize, FALSE));
  650. ASSERT_VALID(&m_docItemList);
  651. ASSERT(!m_bEmbedded || m_strPathName.IsEmpty());
  652. }
  653. void COleDocument::Dump(CDumpContext& dc) const
  654. {
  655. CDocument::Dump(dc);
  656. dc << "with " << m_docItemList.GetCount() << " doc items";
  657. dc << "\nm_dwNextItemNumber = " << m_dwNextItemNumber;
  658. dc << "\nm_bLastVisible = " << m_bLastVisible;
  659. dc << "\nm_bEmbedded = " << m_bEmbedded;
  660. dc << "\nm_lpRootStg = " << m_lpRootStg;
  661. dc << "\nm_bSameAsLoad = " << m_bSameAsLoad;
  662. dc << "\nm_bRemember = " << m_bRemember;
  663. dc << "\nm_ptd = " << m_ptd;
  664. dc << "\n";
  665. }
  666. #endif //_DEBUG
  667. /////////////////////////////////////////////////////////////////////////////
  668. // CDocItem
  669. CDocItem::CDocItem()
  670. {
  671. m_pDocument = NULL;
  672. }
  673. CDocItem::~CDocItem()
  674. {
  675. ASSERT(m_pDocument == NULL); // must be detached from document
  676. }
  677. void CDocItem::Serialize(CArchive& ar)
  678. {
  679. if (ar.IsStoring())
  680. {
  681. ASSERT_VALID(m_pDocument);
  682. // nothing to do, there is no data
  683. }
  684. else
  685. {
  686. // if no document connected yet, attach it from the archive
  687. if (m_pDocument == NULL)
  688. {
  689. COleDocument* pContainerDoc = (COleDocument*)ar.m_pDocument;
  690. ASSERT_VALID(pContainerDoc);
  691. ASSERT_KINDOF(COleDocument, pContainerDoc);
  692. pContainerDoc->AddItem(this);
  693. ASSERT(pContainerDoc == m_pDocument);
  694. }
  695. }
  696. // perform ASSERT_VALID at the end because COleServerItem::AssertValid
  697. // checks the validity of the m_pDocument pointer
  698. ASSERT_VALID(this);
  699. }
  700. BOOL CDocItem::IsBlank() const
  701. {
  702. // by default, a CDocItem is not blank. COleClientItem is sometimes blank!
  703. // (a COleServerItem is blank by default)
  704. return FALSE;
  705. }
  706. /////////////////////////////////////////////////////////////////////////////
  707. // CDocItem diagnostics
  708. #ifdef _DEBUG
  709. void CDocItem::AssertValid() const
  710. {
  711. CObject::AssertValid();
  712. if (m_pDocument != NULL)
  713. m_pDocument->AssertValid();
  714. }
  715. void CDocItem::Dump(CDumpContext& dc) const
  716. {
  717. CCmdTarget::Dump(dc);
  718. dc << "m_pDocument = " << (void*)m_pDocument;
  719. dc << "\n";
  720. }
  721. #endif //_DEBUG
  722. /////////////////////////////////////////////////////////////////////////////
  723. // Inline function declarations expanded out-of-line
  724. #ifndef _AFX_ENABLE_INLINES
  725. // expand inlines for OLE general APIs
  726. static char _szAfxOleInl[] = "afxole.inl";
  727. #undef THIS_FILE
  728. #define THIS_FILE _szAfxOleInl
  729. #define _AFXOLE_INLINE
  730. #include "afxole.inl"
  731. #endif //!_AFX_ENABLE_INLINES
  732. #ifdef AFX_INIT_SEG
  733. #pragma code_seg(AFX_INIT_SEG)
  734. #endif
  735. IMPLEMENT_SERIAL(CDocItem, CCmdTarget, 0)
  736. IMPLEMENT_DYNAMIC(COleDocument, CDocument)
  737. // These IMPLEMENT_DYNAMICs here for .OBJ granularity reasons.
  738. IMPLEMENT_DYNAMIC(COleClientItem, CDocItem)
  739. IMPLEMENT_DYNAMIC(COleServerItem, CDocItem)
  740. /////////////////////////////////////////////////////////////////////////////