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