home *** CD-ROM | disk | FTP | other *** search
/ Supercompiler 1997 / SUPERCOMPILER97.iso / MS_VC.50 / VC / MFC / SRC / OLECLI1.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1996-10-30  |  56.6 KB  |  2,134 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. // COleClientItem - Container view of IOleObject and related interfaces
  26.  
  27. COleClientItem::COleClientItem(COleDocument* pContainerDoc)
  28. {
  29.     if (pContainerDoc != NULL)
  30.         ASSERT_VALID(pContainerDoc);
  31.  
  32.     // initialize OLE client side view of IOleObject
  33.     m_lpObject = NULL;
  34.     m_lpViewObject = NULL;
  35.     m_dwConnection = 0;
  36.     m_lpStorage = NULL;
  37.     m_lpLockBytes = NULL;
  38.     m_scLast = S_OK;
  39.     m_pView = NULL;
  40.     m_pInPlaceFrame = NULL;
  41.     m_pInPlaceDoc = NULL;
  42.     m_nItemState = emptyState;  // initially empty until OleLoad, OleCreate
  43.     m_bMoniker = FALSE;
  44.     m_nDrawAspect = DVASPECT_CONTENT;   // default draw aspect
  45.     m_dwItemNumber = 0;
  46.     m_bLinkUnavail = FALSE; // set to TRUE on failed DoVerb, or in links dialog
  47.     m_nItemType = OT_UNKNOWN;       // type unknown so far
  48.     m_hWndServer = NULL;
  49.     m_bClosing = FALSE; // COleClientItem::Close in process
  50.     m_bLocked = FALSE;  // need CoLockObjectExternal(..., FALSE, ...)
  51.  
  52.     // initialize compound file support
  53.     m_lpNewStorage = NULL;
  54.     m_bNeedCommit = FALSE;
  55.  
  56.     if (pContainerDoc != NULL)
  57.         pContainerDoc->AddItem(this);
  58.  
  59.     ASSERT(m_pDocument == pContainerDoc);
  60.     ASSERT_VALID(this);
  61.  
  62.     AfxOleLockApp();
  63. }
  64.  
  65. COleClientItem::~COleClientItem()
  66. {
  67.     ASSERT_VALID(this);
  68.  
  69.     // release any references we may have to other objects
  70.     Release();
  71.  
  72.     // only remove it from the associated document if it hasn't been detached
  73.     //  from the document already!
  74.     if (m_pDocument != NULL)
  75.         m_pDocument->RemoveItem(this);
  76.  
  77.     // make sure all outside connections are disconnected
  78.     ExternalDisconnect();
  79.     AfxOleUnlockApp();
  80. }
  81.  
  82. void COleClientItem::Delete(BOOL bAutoDelete)
  83. {
  84.     USES_CONVERSION;
  85.     ASSERT_VALID(this);
  86.  
  87.     Release();      // first close it
  88.  
  89.     COleDocument* pDoc = GetDocument();
  90.     if (pDoc != NULL && pDoc->m_bCompoundFile)
  91.     {
  92.         // cleanup docfile storage first
  93.         COleDocument* pDoc = GetDocument();
  94.         ASSERT_VALID(pDoc);
  95.  
  96.         if (pDoc->m_lpRootStg != NULL)
  97.         {
  98.             // get item name
  99.             TCHAR szItemName[OLE_MAXITEMNAME];
  100.             GetItemName(szItemName);
  101.  
  102.             // attempt to remove it from the storage, ignore errors
  103.             pDoc->m_lpRootStg->DestroyElement(T2COLE(szItemName));
  104.         }
  105.     }
  106.  
  107.     if (bAutoDelete)
  108.     {
  109.         // remove item from document
  110.         if (pDoc != NULL)
  111.             pDoc->RemoveItem(this);
  112.  
  113.         InternalRelease();  // remove the item from memory
  114.     }
  115. }
  116.  
  117. void COleClientItem::Release(OLECLOSE dwCloseOption)
  118. {
  119.     ASSERT_VALID(this);
  120.  
  121.     m_scLast = S_OK;
  122.  
  123.     // cleanup view advise
  124.     if (m_lpViewObject != NULL)
  125.     {
  126.         DWORD dwAspect;
  127.         VERIFY(m_lpViewObject->GetAdvise(&dwAspect, NULL, NULL) == S_OK);
  128.         VERIFY(m_lpViewObject->SetAdvise(dwAspect, 0, NULL) == S_OK);
  129.         RELEASE(m_lpViewObject);
  130.     }
  131.  
  132.     // cleanup the OLE object itself
  133.     if (m_lpObject != NULL)
  134.     {
  135.         // cleanup object advise
  136.         if (m_dwConnection != 0)
  137.         {
  138.             VERIFY(m_lpObject->Unadvise(m_dwConnection) == S_OK);
  139.             m_dwConnection = 0;
  140.         }
  141.  
  142.         // close object and save (except now when called from destructor)
  143.         //  (NOTE: errors are _not_ reported as an exception)
  144.         m_scLast = m_lpObject->Close(dwCloseOption);
  145.         RELEASE(m_lpObject);
  146.     }
  147.  
  148.     // cleanup storage related data
  149.     RELEASE(m_lpStorage);
  150.     RELEASE(m_lpLockBytes);
  151.  
  152.     // cleanup in-place editing data
  153.     if (m_pInPlaceFrame != NULL)
  154.     {
  155.         m_pInPlaceFrame->InternalRelease();
  156.         m_pInPlaceFrame = NULL;
  157.         if (m_pInPlaceDoc != NULL)
  158.         {
  159.             m_pInPlaceDoc->InternalRelease();
  160.             m_pInPlaceDoc = NULL;
  161.         }
  162.     }
  163.     ASSERT(m_pInPlaceFrame == NULL);
  164.     ASSERT(m_pInPlaceDoc == NULL);
  165. }
  166.  
  167. void COleClientItem::Close(OLECLOSE dwCloseOption)
  168. {
  169.     ASSERT_VALID(this);
  170.     ASSERT(m_lpObject != NULL);
  171.  
  172.     // gaurd against re-entry
  173.     if (m_bClosing)
  174.         return;
  175.  
  176.     m_bClosing = TRUE;
  177.  
  178.     // attempt to close the object
  179. #ifdef _MAC
  180.     // Some Mac servers (Excel) fail to allow the IP deactivation task switch
  181.     // to finish before issuing an RPC call, which gets Mac LRPC out of sync.
  182.     // Effectively suspend this thread until the RPC channel gets back in sync
  183.     int nTries = 0;
  184.     do
  185.     {
  186.         m_scLast = m_lpObject->Close(dwCloseOption);
  187.         nTries++;
  188.     } while (FAILED(m_scLast) && nTries < 10);
  189. #else
  190.     m_scLast = m_lpObject->Close(dwCloseOption);
  191. #endif
  192.  
  193.     // remove external lock placed on item during in-place activation
  194.     if (m_bLocked)
  195.     {
  196.         OleLockRunning(m_lpObject, FALSE, TRUE);
  197.         m_bLocked = FALSE;
  198.     }
  199.  
  200.     // handle failure cases -- COleClientItem::Close can be used to
  201.     //  robustly handle a server crashing (ie. something unexpected happens,
  202.     //  we'll call COleClientItem::Close to attempt safe shutdown)
  203.     if (GetItemState() != loadedState)
  204.     {
  205.         // We'll call COleClientItem::Close anywhere a catastrophe
  206.         //  happens inside of other portions of COleClientItem.  We must
  207.         //  completely exit from any in-place/open state.
  208.  
  209.         // force transition from activeUIState to activeState
  210.         if (GetItemState() == activeUIState)
  211.             OnDeactivateUI(FALSE);
  212.  
  213.         // force transition from activeState to loadedState
  214.         if (GetItemState() == activeState)
  215.             OnDeactivate();
  216.  
  217.         if (m_nItemState != loadedState)
  218.         {
  219.             // in case of extreme failure, force loadedState
  220.             OnChange(OLE_CHANGED_STATE, (DWORD)loadedState);
  221.             m_nItemState = loadedState; // force it to loaded state
  222.         }
  223.     }
  224.  
  225.     m_bClosing = FALSE; // now safe for further close calls
  226. }
  227.  
  228. /////////////////////////////////////////////////////////////////////////////
  229. // COleClientItem name management
  230.  
  231. DWORD COleClientItem::GetNewItemNumber()
  232. {
  233.     ASSERT_VALID(this);
  234.  
  235.     COleDocument* pDoc = GetDocument();
  236.     ASSERT_VALID(pDoc);
  237.     DWORD dwNextItemNumber = pDoc->m_dwNextItemNumber;
  238.  
  239.     for (;;)
  240.     {
  241.         // make sure that m_dwNextItemNumber is not used in another item first
  242.         POSITION pos = pDoc->GetStartPosition();
  243.         COleClientItem* pItem;
  244.         while ((pItem = pDoc->GetNextClientItem(pos)) != NULL)
  245.         {
  246.             if (pItem->m_dwItemNumber == dwNextItemNumber)
  247.                 break;
  248.         }
  249.         if (pItem == NULL)
  250.             break;  // no item using m_dwNextItemNumber
  251.  
  252.         // m_dwNextItemNumber is in use, bump to next one!
  253.         ++dwNextItemNumber;
  254.     }
  255.  
  256.     pDoc->m_dwNextItemNumber = dwNextItemNumber + 1;
  257.     return dwNextItemNumber;
  258. }
  259.  
  260. void COleClientItem::GetItemName(LPTSTR lpszItemName) const
  261. {
  262.     ASSERT_VALID(this);
  263.     ASSERT(lpszItemName != NULL);
  264.  
  265.     wsprintf(lpszItemName, _T("Embedding %lu"), m_dwItemNumber);
  266.     ASSERT(lstrlen(lpszItemName) < OLE_MAXITEMNAME);
  267. }
  268.  
  269. /////////////////////////////////////////////////////////////////////////////
  270. // COleClientItem creation helpers
  271.  
  272. void COleClientItem::UpdateItemType()
  273. {
  274.     ASSERT_VALID(this);
  275.     ASSERT(m_lpObject != NULL);
  276.  
  277.     // check for linked object
  278.     LPOLELINK lpOleLink = QUERYINTERFACE(m_lpObject, IOleLink);
  279.     if (lpOleLink != NULL)
  280.     {
  281.         lpOleLink->Release();
  282.         m_nItemType = OT_LINK;
  283.         return;
  284.     }
  285.  
  286.     // check for static object
  287.     DWORD dwStatus;
  288.     if (m_lpObject->GetMiscStatus(DVASPECT_CONTENT, &dwStatus) == S_OK
  289.         && (dwStatus & OLEMISC_STATIC) == 0)
  290.     {
  291.         m_nItemType = OT_EMBEDDED;
  292.         return;
  293.     }
  294.  
  295.     // not not link, not embedding -- must be static
  296.     m_nItemType = OT_STATIC;
  297. }
  298.  
  299. BOOL COleClientItem::FinishCreate(SCODE sc)
  300. {
  301.     USES_CONVERSION;
  302.  
  303.     ASSERT_VALID(this);
  304.     ASSERT(m_pView == NULL);
  305.  
  306.     TRY
  307.     {
  308.         // m_lpObject is currently an IUnknown, convert to IOleObject
  309.         if (m_lpObject != NULL)
  310.         {
  311.             LPUNKNOWN lpUnk = m_lpObject;
  312.             m_lpObject = QUERYINTERFACE(lpUnk, IOleObject);
  313.             lpUnk->Release();
  314.             if (m_lpObject == NULL)
  315.                 AfxThrowOleException(E_OUTOFMEMORY);
  316.         }
  317.  
  318.         // check return code from create function
  319.         CheckGeneral(sc);
  320.  
  321.         UpdateItemType();
  322.  
  323.         // cache the IViewObject interface
  324.         m_lpViewObject = QUERYINTERFACE(m_lpObject, IViewObject2);
  325.         if (m_lpViewObject == NULL)
  326.             CheckGeneral(E_NOINTERFACE);
  327.         ASSERT(m_lpViewObject != NULL);
  328.  
  329.         if (GetType() != OT_STATIC)
  330.         {
  331.             // setup for advises; we assume that OLE cleans them up properly
  332.             LPADVISESINK lpAdviseSink =
  333.                 (LPADVISESINK)GetInterface(&IID_IAdviseSink);
  334.             ASSERT(lpAdviseSink != NULL);
  335.             CheckGeneral(m_lpObject->Advise(lpAdviseSink, &m_dwConnection));
  336.             ASSERT(m_dwConnection != 0);
  337.  
  338.             // set up view advise
  339.             VERIFY(m_lpViewObject->SetAdvise(DVASPECT_CONTENT, 0, lpAdviseSink)
  340.                 == S_OK);
  341.  
  342.             // the server shows these in its user-interface
  343.             //  (as document title and in File Exit menu)
  344.             m_lpObject->SetHostNames(T2COLE(AfxGetAppName()),
  345.                 T2COLE(m_pDocument->GetTitle()));
  346.         }
  347.  
  348.         // all items are "contained" -- this makes our reference to this object
  349.         //  weak -- which is needed for links to embedding silent update.
  350.         OleSetContainedObject(m_lpObject, TRUE);
  351.  
  352.         // considered loaded at this point
  353.         m_nItemState = loadedState;
  354.     }
  355.     CATCH_ALL(e)
  356.     {
  357.         Release();  // release the object just in case
  358.         ASSERT_VALID(this);
  359.         DELETE_EXCEPTION(e);
  360.         return FALSE;
  361.     }
  362.     END_CATCH_ALL
  363.  
  364.     // set state to loaded
  365.     ASSERT(m_nItemState != emptyState);
  366.  
  367.     // otherwise no errors, return success!
  368.     ASSERT_VALID(this);
  369.     return TRUE;
  370. }
  371.  
  372. //////////////////////////////////////////////////////////////////////////////
  373. // COleClientItem create API variants
  374.  
  375. BOOL COleClientItem::CreateFromClipboard(
  376.     OLERENDER render, CLIPFORMAT cfFormat, LPFORMATETC lpFormatEtc)
  377. {
  378.     ASSERT_VALID(this);
  379.     ASSERT(m_lpObject == NULL);     // one time only
  380.     ASSERT(m_pDocument != NULL);
  381.     ASSERT(lpFormatEtc == NULL ||
  382.         AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
  383.  
  384.     // get clipboard contents
  385.     COleDataObject dataObject;
  386.     if (!dataObject.AttachClipboard())
  387.         return FALSE;
  388.  
  389.     // create from IDataObject
  390.     BOOL bResult = CreateFromData(&dataObject, render, cfFormat, lpFormatEtc);
  391.  
  392.     ASSERT_VALID(this);
  393.     return bResult;
  394. }
  395.  
  396. BOOL COleClientItem::CreateLinkFromClipboard(
  397.     OLERENDER render, CLIPFORMAT cfFormat, LPFORMATETC lpFormatEtc)
  398. {
  399.     ASSERT_VALID(this);
  400.     ASSERT(m_lpObject == NULL);     // one time only
  401.     ASSERT(m_pDocument != NULL);
  402.     ASSERT(lpFormatEtc == NULL ||
  403.         AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
  404.  
  405.     // get clipboard contents
  406.     COleDataObject dataObject;
  407.     if (!dataObject.AttachClipboard())
  408.         return FALSE;
  409.  
  410.     // create from IDataObject
  411.     BOOL bResult = CreateLinkFromData(&dataObject, render, cfFormat, lpFormatEtc);
  412.     ASSERT_VALID(this);
  413.  
  414.     return bResult;
  415. }
  416.  
  417. BOOL COleClientItem::CreateStaticFromClipboard(
  418.     OLERENDER render, CLIPFORMAT cfFormat, LPFORMATETC lpFormatEtc)
  419. {
  420.     ASSERT_VALID(this);
  421.     ASSERT(m_lpObject == NULL);     // one time only
  422.     ASSERT(m_pDocument != NULL);
  423.     ASSERT(lpFormatEtc == NULL ||
  424.         AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
  425.  
  426.     // get clipboard contents
  427.     COleDataObject dataObject;
  428.     if (!dataObject.AttachClipboard())
  429.         return FALSE;
  430.  
  431.     // create from IDataObject
  432.     BOOL bResult = CreateStaticFromData(&dataObject, render, cfFormat,
  433.         lpFormatEtc);
  434.  
  435.     ASSERT_VALID(this);
  436.     return bResult;
  437. }
  438.  
  439. // Creation from IDataObject (used for drag-drop)
  440. BOOL COleClientItem::CreateFromData(COleDataObject* pDataObject,
  441.     OLERENDER render, CLIPFORMAT cfFormat, LPFORMATETC lpFormatEtc)
  442. {
  443.     ASSERT_VALID(this);
  444.     ASSERT(m_lpObject == NULL);     // one time only
  445.     ASSERT(m_pDocument != NULL);
  446.     ASSERT(lpFormatEtc == NULL ||
  447.         AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
  448.  
  449.     // get storage for the object via virtual function call
  450.     m_dwItemNumber = GetNewItemNumber();
  451.     GetItemStorage();
  452.     ASSERT(m_lpStorage != NULL);
  453.  
  454.     // fill in FORMATETC struct
  455.     FORMATETC formatEtc;
  456.     lpFormatEtc = _AfxFillFormatEtc(lpFormatEtc, cfFormat, &formatEtc);
  457.  
  458.     // attempt to create the object
  459.     LPOLECLIENTSITE lpClientSite = GetClientSite();
  460.     LPDATAOBJECT lpDataObject = pDataObject->GetIDataObject(FALSE);
  461.     SCODE sc = ::OleCreateFromData(lpDataObject, IID_IUnknown, render,
  462.         lpFormatEtc, lpClientSite, m_lpStorage, (LPLP)&m_lpObject);
  463.     BOOL bResult = FinishCreate(sc);
  464.  
  465.     ASSERT_VALID(this);
  466.     return bResult;
  467. }
  468.  
  469. BOOL COleClientItem::CreateLinkFromData(COleDataObject* pDataObject,
  470.     OLERENDER render, CLIPFORMAT cfFormat, LPFORMATETC lpFormatEtc)
  471. {
  472.     ASSERT_VALID(this);
  473.     ASSERT(m_lpObject == NULL);     // one time only
  474.     ASSERT(m_pDocument != NULL);
  475.     ASSERT(lpFormatEtc == NULL ||
  476.         AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
  477.  
  478.     // get storage for the object via virtual function call
  479.     m_dwItemNumber = GetNewItemNumber();
  480.     GetItemStorage();
  481.     ASSERT(m_lpStorage != NULL);
  482.  
  483.     // fill in FORMATETC struct
  484.     FORMATETC formatEtc;
  485.     lpFormatEtc = _AfxFillFormatEtc(lpFormatEtc, cfFormat, &formatEtc);
  486.  
  487.     // attempt to create the link
  488.     LPOLECLIENTSITE lpClientSite = GetClientSite();
  489.     LPDATAOBJECT lpDataObject = pDataObject->GetIDataObject(FALSE);
  490.     SCODE sc = ::OleCreateLinkFromData(lpDataObject, IID_IUnknown,
  491.         render, lpFormatEtc, lpClientSite, m_lpStorage, (LPLP)&m_lpObject);
  492.     BOOL bResult = FinishCreate(sc);
  493.  
  494.     ASSERT_VALID(this);
  495.     return bResult;
  496. }
  497.  
  498. BOOL COleClientItem::CreateStaticFromData(COleDataObject* pDataObject,
  499.     OLERENDER render, CLIPFORMAT cfFormat, LPFORMATETC lpFormatEtc)
  500. {
  501.     ASSERT_VALID(this);
  502.     ASSERT(m_lpObject == NULL);     // one time only
  503.     ASSERT(m_pDocument != NULL);
  504.     ASSERT(lpFormatEtc == NULL ||
  505.         AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
  506.  
  507.     // get storage for the object via virtual function call
  508.     m_dwItemNumber = GetNewItemNumber();
  509.     GetItemStorage();
  510.     ASSERT(m_lpStorage != NULL);
  511.  
  512.     // fill in FORMATETC struct
  513.     FORMATETC formatEtc;
  514.     lpFormatEtc = _AfxFillFormatEtc(lpFormatEtc, cfFormat, &formatEtc);
  515.  
  516.     // attempt to create the link
  517.     LPOLECLIENTSITE lpClientSite = GetClientSite();
  518.     LPDATAOBJECT lpDataObject = pDataObject->GetIDataObject(FALSE);
  519.     SCODE sc = ::OleCreateStaticFromData(lpDataObject, IID_IUnknown,
  520.         render, lpFormatEtc, lpClientSite, m_lpStorage, (LPLP)&m_lpObject);
  521.     BOOL bResult = FinishCreate(sc);
  522.  
  523.     ASSERT_VALID(this);
  524.     return bResult;
  525. }
  526.  
  527. // Creation from files (in OLE 1.0, the user did this through packager)
  528. BOOL COleClientItem::CreateFromFile(LPCTSTR lpszFileName, REFCLSID clsid,
  529.     OLERENDER render, CLIPFORMAT cfFormat, LPFORMATETC lpFormatEtc)
  530. {
  531.     USES_CONVERSION;
  532.  
  533.     ASSERT_VALID(this);
  534.     ASSERT(m_lpObject == NULL);     // one time only
  535.     ASSERT(m_pDocument != NULL);
  536.     ASSERT(lpFormatEtc == NULL ||
  537.         AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
  538.  
  539.     // get storage for the object via virtual function call
  540.     m_dwItemNumber = GetNewItemNumber();
  541.     GetItemStorage();
  542.     ASSERT(m_lpStorage != NULL);
  543.  
  544.     // fill in FORMATETC struct
  545.     FORMATETC formatEtc;
  546.     lpFormatEtc = _AfxFillFormatEtc(lpFormatEtc, cfFormat, &formatEtc);
  547.  
  548.     // attempt to create the object
  549.     LPOLECLIENTSITE lpClientSite = GetClientSite();
  550.     SCODE sc = ::OleCreateFromFile(clsid, T2COLE(lpszFileName),
  551.         IID_IUnknown, render, lpFormatEtc, lpClientSite, m_lpStorage,
  552.         (LPLP)&m_lpObject);
  553.     BOOL bResult = FinishCreate(sc);
  554.  
  555.     ASSERT_VALID(this);
  556.     return bResult;
  557. }
  558.  
  559. BOOL COleClientItem::CreateLinkFromFile(LPCTSTR lpszFileName,
  560.     OLERENDER render, CLIPFORMAT cfFormat, LPFORMATETC lpFormatEtc)
  561. {
  562.     USES_CONVERSION;
  563.  
  564.     ASSERT_VALID(this);
  565.     ASSERT(m_lpObject == NULL);     // one time only
  566.     ASSERT(m_pDocument != NULL);
  567.     ASSERT(lpFormatEtc == NULL ||
  568.         AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
  569.  
  570.     // get storage for the object via virtual function call
  571.     m_dwItemNumber = GetNewItemNumber();
  572.     GetItemStorage();
  573.     ASSERT(m_lpStorage != NULL);
  574.  
  575.     // fill in FORMATETC struct
  576.     FORMATETC formatEtc;
  577.     lpFormatEtc = _AfxFillFormatEtc(lpFormatEtc, cfFormat, &formatEtc);
  578.  
  579.     // attempt to create the link
  580.     LPOLECLIENTSITE lpClientSite = GetClientSite();
  581.     SCODE sc = ::OleCreateLinkToFile(T2COLE(lpszFileName),
  582.         IID_IUnknown, render, lpFormatEtc, lpClientSite, m_lpStorage,
  583.         (LPLP)&m_lpObject);
  584.     BOOL bResult = FinishCreate(sc);
  585.  
  586.     ASSERT_VALID(this);
  587.     return bResult;
  588. }
  589.  
  590. // create from class name (for insert item dialog)
  591. BOOL COleClientItem::CreateNewItem(REFCLSID clsid,
  592.     OLERENDER render, CLIPFORMAT cfFormat, LPFORMATETC lpFormatEtc)
  593. {
  594.     ASSERT_VALID(this);
  595.     ASSERT(m_lpObject == NULL);     // one time only
  596.     ASSERT(m_pDocument != NULL);
  597.     ASSERT(lpFormatEtc == NULL ||
  598.         AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
  599.  
  600.     // get storage for the object via virtual function call
  601.     m_dwItemNumber = GetNewItemNumber();
  602.     GetItemStorage();
  603.     ASSERT(m_lpStorage != NULL);
  604.  
  605.     // fill in FORMATETC struct
  606.     FORMATETC formatEtc;
  607.     lpFormatEtc = _AfxFillFormatEtc(lpFormatEtc, cfFormat, &formatEtc);
  608.  
  609.     // attempt to create the object
  610.     LPOLECLIENTSITE lpClientSite = GetClientSite();
  611.     SCODE sc = ::OleCreate(clsid, IID_IUnknown,
  612.         render, lpFormatEtc, lpClientSite, m_lpStorage, (LPLP)&m_lpObject);
  613.     BOOL bResult = FinishCreate(sc);
  614.  
  615.     ASSERT_VALID(this);
  616.     return bResult;
  617. }
  618.  
  619. /////////////////////////////////////////////////////////////////////////////
  620. // More advanced creation
  621.  
  622. BOOL COleClientItem::CreateCloneFrom(const COleClientItem* pSrcItem)
  623. {
  624.     ASSERT_VALID(this);
  625.     ASSERT(m_lpObject == NULL);     // one time only
  626.     ASSERT_VALID(pSrcItem);
  627.     ASSERT(m_pDocument != NULL);
  628.  
  629.     // create storage for the item
  630.     m_dwItemNumber = GetNewItemNumber();
  631.     GetItemStorage();
  632.     ASSERT(m_lpStorage != NULL);
  633.  
  634.     // save the object first
  635.     LPPERSISTSTORAGE lpPersistStorage =
  636.         QUERYINTERFACE(pSrcItem->m_lpObject, IPersistStorage);
  637.     ASSERT(lpPersistStorage != NULL);
  638.     SCODE sc = ::OleSave(lpPersistStorage, m_lpStorage, FALSE);
  639.     lpPersistStorage->SaveCompleted(NULL);
  640.     lpPersistStorage->Release();
  641.     if (sc != S_OK)
  642.     {
  643.         // failed the save, do not attempt to create clone
  644.         m_scLast = sc;
  645.         return FALSE;
  646.     }
  647.  
  648.     // get information on the view advise type
  649.     ASSERT(pSrcItem->m_lpViewObject != NULL);
  650.     DWORD dwAspect;
  651.     VERIFY(pSrcItem->m_lpViewObject->GetAdvise(&dwAspect, NULL, NULL) == S_OK);
  652.  
  653.     // then load the new object from the new storage
  654.     LPOLECLIENTSITE lpClientSite = GetClientSite();
  655.     sc = ::OleLoad(m_lpStorage, IID_IUnknown,
  656.         lpClientSite, (LPLP)&m_lpObject);
  657.     BOOL bResult = FinishCreate(sc);
  658.  
  659.     ASSERT_VALID(this);
  660.     return bResult;
  661. }
  662.  
  663. /////////////////////////////////////////////////////////////////////////////
  664. // Storage for COleClientItem objects (memory and compound files)
  665.  
  666. BOOL COleClientItem::IsModified() const
  667. {
  668.     ASSERT_VALID(this);
  669.     ASSERT(m_lpObject != NULL);
  670.  
  671.     // get IPersistStorage interface, and call IsDirty
  672.     LPPERSISTSTORAGE lpPersistStorage =
  673.         QUERYINTERFACE(m_lpObject, IPersistStorage);
  674.     ASSERT(lpPersistStorage != NULL);
  675.     SCODE sc = lpPersistStorage->IsDirty();
  676.     lpPersistStorage->Release();
  677.  
  678.     // S_OK == S_TRUE, therefore object dirty!
  679.     return sc == S_OK || FAILED(sc);
  680. }
  681.  
  682. void COleClientItem::GetItemStorageFlat()
  683. {
  684.     ASSERT_VALID(this);
  685.     ASSERT(m_lpStorage == NULL);
  686.     ASSERT(m_lpLockBytes == NULL);
  687.  
  688.     SCODE sc = ::CreateILockBytesOnHGlobal(NULL, TRUE, &m_lpLockBytes);
  689.     if (sc != S_OK)
  690.         AfxThrowOleException(sc);
  691.     ASSERT(m_lpLockBytes != NULL);
  692.  
  693.     sc = ::StgCreateDocfileOnILockBytes(m_lpLockBytes,
  694.         STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0, &m_lpStorage);
  695.     if (sc != S_OK)
  696.     {
  697.         VERIFY(m_lpLockBytes->Release() == 0);
  698.         m_lpLockBytes = NULL;
  699.         AfxThrowOleException(sc);
  700.     }
  701.     ASSERT(m_lpStorage != NULL);
  702.  
  703.     ASSERT_VALID(this);
  704. }
  705.  
  706. void COleClientItem::ReadItemFlat(CArchive& ar)
  707. {
  708.     ASSERT_VALID(this);
  709.     ASSERT(m_lpStorage == NULL);
  710.     ASSERT(m_lpLockBytes == NULL);
  711.  
  712.     // read number of bytes in the ILockBytes
  713.     DWORD dwBytes;
  714.     ar >> dwBytes;
  715.  
  716.     // allocate enough memory to read entire block
  717.     HGLOBAL hStorage = ::GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, dwBytes);
  718.     if (hStorage == NULL)
  719.         AfxThrowMemoryException();
  720.  
  721.     LPVOID lpBuf = ::GlobalLock(hStorage);
  722.     ASSERT(lpBuf != NULL);
  723.     DWORD dwBytesRead = ar.Read(lpBuf, dwBytes);
  724.     ::GlobalUnlock(hStorage);
  725.  
  726.     // throw exception in case of partial object
  727.     if (dwBytesRead != dwBytes)
  728.     {
  729.         ::GlobalFree(hStorage);
  730.         AfxThrowArchiveException(CArchiveException::endOfFile);
  731.     }
  732.  
  733.     SCODE sc = CreateILockBytesOnHGlobal(hStorage, TRUE, &m_lpLockBytes);
  734.     if (sc != S_OK)
  735.     {
  736.         ::GlobalFree(hStorage);
  737.         AfxThrowOleException(sc);
  738.     }
  739.     ASSERT(m_lpLockBytes != NULL);
  740.     ASSERT(::StgIsStorageILockBytes(m_lpLockBytes) == S_OK);
  741.  
  742.     sc = ::StgOpenStorageOnILockBytes(m_lpLockBytes, NULL,
  743.         STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &m_lpStorage);
  744.     if (sc != S_OK)
  745.     {
  746.         VERIFY(m_lpLockBytes->Release() == 0);
  747.         m_lpLockBytes = NULL;
  748.             // ILockBytes::Release will GlobalFree the hStorage
  749.         AfxThrowOleException(sc);
  750.     }
  751.  
  752.     // attempt to load the object from the storage
  753.     LPUNKNOWN lpUnk = NULL;
  754.     sc = ::OleLoad(m_lpStorage, IID_IUnknown, GetClientSite(),
  755.         (LPLP)&lpUnk);
  756.     CheckGeneral(sc);
  757.  
  758.     ASSERT(lpUnk != NULL);
  759.     m_lpObject = QUERYINTERFACE(lpUnk, IOleObject);
  760.     lpUnk->Release();
  761.     if (m_lpObject == NULL)
  762.         AfxThrowOleException(E_OUTOFMEMORY);
  763.  
  764.     ASSERT_VALID(this);
  765. }
  766.  
  767. void COleClientItem::WriteItemFlat(CArchive& ar)
  768. {
  769.     ASSERT_VALID(this);
  770.     ASSERT(m_lpStorage != NULL);
  771.     ASSERT(m_lpLockBytes != NULL);
  772.  
  773.     // save the OLE object to its storage first
  774.     LPPERSISTSTORAGE lpPersistStorage =
  775.         QUERYINTERFACE(m_lpObject, IPersistStorage);
  776.     ASSERT(lpPersistStorage != NULL);
  777.     SCODE sc;
  778.     if (GetDocument()->m_bCompoundFile || lpPersistStorage->IsDirty() == S_OK)
  779.     {
  780.         sc = ::OleSave(lpPersistStorage, m_lpStorage,
  781.             !GetDocument()->m_bCompoundFile);
  782.         lpPersistStorage->SaveCompleted(NULL);
  783.     }
  784.     lpPersistStorage->Release();
  785.     m_lpStorage->Commit(STGC_OVERWRITE);
  786.     ASSERT(::StgIsStorageILockBytes(m_lpLockBytes) == S_OK);
  787.  
  788.     // attempt to get the handle to the global memory
  789.     HGLOBAL hStorage;
  790.     sc = ::GetHGlobalFromILockBytes(m_lpLockBytes, &hStorage);
  791.     if (sc != S_OK)
  792.         AfxThrowOleException(sc);
  793.  
  794.     // first write a byte count
  795.     STATSTG statstg;
  796.     sc = m_lpLockBytes->Stat(&statstg, STATFLAG_NONAME);
  797.     if (sc != S_OK)
  798.         AfxThrowOleException(sc);
  799.     ASSERT(statstg.cbSize.HighPart == 0);   // don't support >4GB objects
  800.     DWORD dwBytes = statstg.cbSize.LowPart;
  801.     ar << dwBytes;
  802.  
  803.     // write the contents of the block
  804.     LPVOID lpBuf = GlobalLock(hStorage);
  805.     ASSERT(lpBuf != NULL);
  806.     ar.Write(lpBuf, (UINT)dwBytes);
  807.     ::GlobalUnlock(hStorage);
  808. #ifdef _MAC
  809.     char **ppch;
  810.     UnwrapHandle(hStorage, &ppch);
  811. #endif
  812. }
  813.  
  814. void COleClientItem::GetItemStorageCompound()
  815. {
  816.     USES_CONVERSION;
  817.  
  818.     COleDocument* pDoc = GetDocument();
  819.     ASSERT_VALID(pDoc);
  820.     ASSERT(pDoc->m_bCompoundFile);
  821.     if (pDoc->m_lpRootStg == NULL)
  822.     {
  823.         ASSERT(pDoc->m_bEmbedded);
  824.         pDoc->m_bEmbedded = FALSE;
  825.         if (!pDoc->OnNewDocument())
  826.         {
  827.             TRACE0("Warning OnNewDocument failed during COleClientItem::CreateXXXX\n");
  828.             AfxThrowMemoryException();
  829.         }
  830.     }
  831.     ASSERT(pDoc->m_lpRootStg != NULL);
  832.  
  833.     // get item name
  834.     TCHAR szItemName[OLE_MAXITEMNAME];
  835.     GetItemName(szItemName);
  836.  
  837.     // create storage for this item
  838.     LPSTORAGE lpStorage;
  839.     SCODE sc = pDoc->m_lpRootStg->CreateStorage(T2COLE(szItemName),
  840.         STGM_CREATE|STGM_READWRITE|STGM_TRANSACTED|STGM_SHARE_EXCLUSIVE,
  841.         0, 0, &lpStorage);
  842.     if (sc != S_OK)
  843.     {
  844.         TRACE1("Warning: unable to create child storage %s.\n", szItemName);
  845.         // upon failure throw file exception (item will be cleaned up)
  846.         AfxThrowOleException(sc);
  847.     }
  848.     ASSERT(lpStorage != NULL);
  849.  
  850.     // everything should have worked
  851.     m_lpStorage = lpStorage;
  852.     ASSERT(m_lpStorage != NULL);
  853. }
  854.  
  855. void COleClientItem::ReadItemCompound(CArchive& ar)
  856. {
  857.     USES_CONVERSION;
  858.  
  859.     COleDocument* pDoc = GetDocument();
  860.     ASSERT_VALID(pDoc);
  861.     ASSERT(pDoc->m_lpRootStg != NULL);
  862.     ASSERT(pDoc->m_bCompoundFile);
  863.     ASSERT(m_lpStorage == NULL);
  864.     ASSERT(m_lpLockBytes == NULL);
  865.  
  866.     if (ar.m_bForceFlat)
  867.     {
  868.         ReadItemFlat(ar);
  869.         RELEASE(m_lpStorage);
  870.         RELEASE(m_lpLockBytes);
  871.  
  872.         // change the number to something definitely unique
  873.         m_dwItemNumber = GetNewItemNumber();
  874.  
  875.         // create new storage
  876.         GetItemStorageCompound();
  877.         LPPERSISTSTORAGE lpPersistStorage =
  878.             QUERYINTERFACE(m_lpObject, IPersistStorage);
  879.         ASSERT(lpPersistStorage != NULL);
  880.         SCODE sc = ::OleSave(lpPersistStorage, m_lpStorage, FALSE);
  881.         if (FAILED(sc))
  882.         {
  883.             lpPersistStorage->Release();
  884.             CheckGeneral(sc);
  885.         }
  886.         VERIFY(lpPersistStorage->SaveCompleted(m_lpStorage) == S_OK);
  887.         lpPersistStorage->Release();
  888.     }
  889.     else
  890.     {
  891.         // get item name
  892.         TCHAR szItemName[OLE_MAXITEMNAME];
  893.         GetItemName(szItemName);
  894.  
  895.         // open storage for this item
  896.         LPSTORAGE lpStorage;
  897.         SCODE sc = pDoc->m_lpRootStg->OpenStorage(T2COLE(szItemName), NULL,
  898.             STGM_READWRITE|STGM_TRANSACTED|STGM_SHARE_EXCLUSIVE,
  899.             0, 0, &lpStorage);
  900.         if (sc != S_OK)
  901.         {
  902.             TRACE1("Warning: unable to open child storage %s.\n", szItemName);
  903.             // upon failure throw file exception (item will be cleaned up)
  904.             AfxThrowOleException(sc);
  905.         }
  906.         ASSERT(lpStorage != NULL);
  907.  
  908.         // remember the storage
  909.         m_lpStorage = lpStorage;
  910.         ASSERT(m_lpStorage != NULL);
  911.  
  912.         // attempt to load the object from the storage
  913.         LPUNKNOWN lpUnk = NULL;
  914.         sc = ::OleLoad(m_lpStorage, IID_IUnknown, GetClientSite(),
  915.             (LPLP)&lpUnk);
  916.         CheckGeneral(sc);
  917.  
  918.         // get IOleObject interface for the newly loaded object
  919.         ASSERT(lpUnk != NULL);
  920.         m_lpObject = QUERYINTERFACE(lpUnk, IOleObject);
  921.         lpUnk->Release();
  922.         if (m_lpObject == NULL)
  923.             AfxThrowOleException(E_OUTOFMEMORY);
  924.     }
  925. }
  926.  
  927. void COleClientItem::WriteItemCompound(CArchive& ar)
  928. {
  929.     USES_CONVERSION;
  930.  
  931.     COleDocument* pDoc = GetDocument();
  932.     ASSERT_VALID(pDoc);
  933.     ASSERT(pDoc->m_lpRootStg != NULL);
  934.     ASSERT(pDoc->m_bCompoundFile);
  935.     ASSERT(m_lpNewStorage == NULL);
  936.  
  937.     if (ar.m_bForceFlat)
  938.     {
  939.         LPSTORAGE pTempStorage = m_lpStorage;
  940.         LPLOCKBYTES pTempLockBytes = m_lpLockBytes;
  941.         m_lpStorage = NULL;
  942.         m_lpLockBytes = NULL;
  943.         GetItemStorageFlat();
  944.         WriteItemFlat(ar);
  945.         RELEASE(m_lpStorage);
  946.         RELEASE(m_lpLockBytes);
  947.         m_lpStorage = pTempStorage;
  948.         m_lpLockBytes = pTempLockBytes;
  949.         return;
  950.     }
  951.  
  952.     // get item name
  953.     TCHAR szItemName[OLE_MAXITEMNAME];
  954.     GetItemName(szItemName);
  955.  
  956.     // determine destination storage
  957.     ASSERT(m_lpStorage != NULL);
  958.     LPSTORAGE lpStorage = m_lpStorage;
  959.     if (!pDoc->m_bSameAsLoad)
  960.     {
  961.         // need to create new storage for this item
  962.         SCODE sc = pDoc->m_lpRootStg->CreateStorage(T2COLE(szItemName),
  963.             STGM_CREATE|STGM_READWRITE|STGM_TRANSACTED|STGM_SHARE_EXCLUSIVE,
  964.             0, 0, &lpStorage);
  965.         if (sc != S_OK)
  966.         {
  967.             TRACE1("Warning: unable to create child storage %s.\n",
  968.                 szItemName);
  969.             AfxThrowOleException(sc);
  970.         }
  971.         // remember the storage for CommitItem stage
  972.         m_lpNewStorage = lpStorage;
  973.         m_bNeedCommit = TRUE;
  974.     }
  975.     ASSERT(lpStorage != NULL);
  976.  
  977.     // save dirty object
  978.     LPPERSISTSTORAGE lpPersistStorage =
  979.         QUERYINTERFACE(m_lpObject, IPersistStorage);
  980.     ASSERT(lpPersistStorage != NULL);
  981.     SCODE sc = S_OK;
  982.     if (!pDoc->m_bSameAsLoad || lpPersistStorage->IsDirty() == S_OK)
  983.     {
  984.         // call OleSave now and IPersistStorage::SaveCompleted later
  985.         sc = ::OleSave(lpPersistStorage, lpStorage, pDoc->m_bSameAsLoad);
  986.     }
  987.     lpPersistStorage->Release();
  988.  
  989.     // if it fails, abort the save
  990.     if (FAILED(sc))
  991.         AfxThrowOleException(sc);
  992.  
  993.     // now will need to call CommitItem for this item
  994.     m_bNeedCommit = TRUE;
  995.     lpStorage->Commit(STGC_ONLYIFCURRENT);
  996. }
  997.  
  998. void COleClientItem::GetItemStorage()
  999. {
  1000.     if (GetDocument()->m_bCompoundFile)
  1001.         GetItemStorageCompound();
  1002.     else
  1003.         GetItemStorageFlat();
  1004. }
  1005.  
  1006. void COleClientItem::ReadItem(CArchive& ar)
  1007. {
  1008.     if (GetDocument()->m_bCompoundFile)
  1009.         ReadItemCompound(ar);
  1010.     else
  1011.         ReadItemFlat(ar);
  1012. }
  1013.  
  1014. void COleClientItem::WriteItem(CArchive& ar)
  1015. {
  1016.     if (GetDocument()->m_bCompoundFile)
  1017.         WriteItemCompound(ar);
  1018.     else
  1019.         WriteItemFlat(ar);
  1020. }
  1021.  
  1022. void COleClientItem::CommitItem(BOOL bSuccess)
  1023. {
  1024.     ASSERT_VALID(this);
  1025.     ASSERT(m_lpObject != NULL);
  1026.  
  1027.     if (!m_bNeedCommit)
  1028.         return;
  1029.  
  1030.     LPPERSISTSTORAGE lpPersistStorage =
  1031.         QUERYINTERFACE(m_lpObject, IPersistStorage);
  1032.     ASSERT(lpPersistStorage != NULL);
  1033.  
  1034.     // forget about new storage if save failed along the way...
  1035.     if (m_lpNewStorage != NULL && !bSuccess)
  1036.         RELEASE(m_lpNewStorage);
  1037.  
  1038.     // let the object remember the new storage
  1039.     VERIFY(lpPersistStorage->SaveCompleted(m_lpNewStorage) == S_OK);
  1040.     lpPersistStorage->Release();
  1041.  
  1042.     // determine/remember new storage
  1043.     if (m_lpNewStorage != NULL)
  1044.     {
  1045.         m_lpStorage->Release();
  1046.         m_lpStorage = m_lpNewStorage;
  1047.         m_lpNewStorage = NULL;
  1048.     }
  1049.  
  1050.     m_bNeedCommit = FALSE;
  1051. }
  1052.  
  1053. /////////////////////////////////////////////////////////////////////////////
  1054. // COleClientItem serialization
  1055.  
  1056. void COleClientItem::Serialize(CArchive& ar)
  1057. {
  1058.     ASSERT_VALID(this);
  1059.  
  1060.     CDocItem::Serialize(ar);
  1061.     ASSERT(m_pDocument != NULL);  // must 'SetDocument' first
  1062.  
  1063.     if (ar.IsStoring())
  1064.     {
  1065.         ASSERT(m_lpObject != NULL);
  1066.  
  1067.         // first, save the type flag (this is used for versioning)
  1068.         ar << (DWORD)OT_OLE2;
  1069.  
  1070.         ar << m_dwItemNumber;   // save the item number
  1071.  
  1072.         // write the view advise type to storage
  1073.         ASSERT(m_lpViewObject != NULL);
  1074.         DWORD dwAspect;
  1075.         VERIFY(m_lpViewObject->GetAdvise(&dwAspect, NULL, NULL) == S_OK);
  1076.         ar << dwAspect;         // save the display aspect
  1077.  
  1078.         // write flag indicating whether to create moniker upon load
  1079.         ar << (WORD)m_bMoniker;
  1080.  
  1081.         // save current default display aspect
  1082.         ar << (DWORD)m_nDrawAspect;
  1083.  
  1084.         // save object to storage (calls OleSave)
  1085.         WriteItem(ar);
  1086.     }
  1087.     else
  1088.     {
  1089.         ASSERT(m_lpObject == NULL);
  1090.  
  1091.         // first, get the type flag (for OLE 1.0 compatible reading)
  1092.         DWORD dwType;
  1093.         ar >> dwType;
  1094.         if (dwType != OT_OLE2)
  1095.             AfxThrowArchiveException(CArchiveException::generic);
  1096.  
  1097.         ar >> m_dwItemNumber;   // get the item number
  1098.  
  1099.         DWORD dwAspect; // read the display aspect (aspects that are cached)
  1100.         ar >> dwAspect;
  1101.  
  1102.         WORD bMoniker;  // see if we should create & set the moniker
  1103.         ar >> bMoniker;
  1104.  
  1105.         DWORD nDrawAspect;  // read the default display aspect
  1106.         ar >> nDrawAspect;
  1107.         m_nDrawAspect = (DVASPECT)nDrawAspect;
  1108.  
  1109.         // read the OLE object from storage (calls OleLoad)
  1110.         ReadItem(ar);
  1111.  
  1112.         // finish OLE object creation process, setup advises, etc.
  1113.         if (!FinishCreate(S_OK))
  1114.             AfxThrowArchiveException(CArchiveException::generic);
  1115.  
  1116.         if (bMoniker)
  1117.         {
  1118.             // force moniker creation by calling GetMoniker
  1119.             LPMONIKER lpMoniker;
  1120.             if (GetClientSite()->GetMoniker(OLEGETMONIKER_FORCEASSIGN,
  1121.                 OLEWHICHMK_OBJREL, &lpMoniker) == S_OK)
  1122.             {
  1123.                 ASSERT(lpMoniker != NULL);
  1124.                 lpMoniker->Release();
  1125.                 ASSERT(m_bMoniker); // moniker should have been assigned
  1126.             }
  1127.         }
  1128.  
  1129.         // fix up the document's m_dwNextItemNumber
  1130.         if (m_dwItemNumber >= GetDocument()->m_dwNextItemNumber)
  1131.             GetDocument()->m_dwNextItemNumber = m_dwItemNumber + 1;
  1132.     }
  1133. }
  1134.  
  1135. /////////////////////////////////////////////////////////////////////////////
  1136. // default callback implementation
  1137.  
  1138. void COleClientItem::OnChange(OLE_NOTIFICATION nCode, DWORD /*dwParam*/)
  1139. {
  1140.     ASSERT_VALID(this);
  1141.  
  1142.     switch (nCode)
  1143.     {
  1144.     case OLE_CLOSED:
  1145.         break;  // no default implementation
  1146.  
  1147.     case OLE_CHANGED:
  1148.     case OLE_SAVED:
  1149.         ASSERT(m_pDocument != NULL);
  1150.         m_pDocument->SetModifiedFlag();
  1151.         break;
  1152.  
  1153.     case OLE_CHANGED_STATE:
  1154.     case OLE_CHANGED_ASPECT:
  1155.         break;  // no default implementation
  1156.  
  1157.     default:
  1158.         ASSERT(FALSE);
  1159.     }
  1160.  
  1161.     ASSERT_VALID(this);
  1162. }
  1163.  
  1164. void COleClientItem::OnDataChange(
  1165.     LPFORMATETC /*lpFormatEtc*/, LPSTGMEDIUM /*lpStgMedium*/)
  1166. {
  1167.     ASSERT(FALSE);  // derivative must override -- must not call base class
  1168. }
  1169.  
  1170. void COleClientItem::OnGetItemPosition(CRect& /*rPosition*/)
  1171. {
  1172.     // default does nothing
  1173. }
  1174.  
  1175. void COleClientItem::OnGetClipRect(CRect& rClipRect)
  1176. {
  1177.     ASSERT_VALID(this);
  1178.     ASSERT(AfxIsValidAddress(&rClipRect, sizeof(RECT)));
  1179.  
  1180.     // default clips rectClip to client area of the active view
  1181.     ASSERT_VALID(m_pView);
  1182.     m_pView->GetClientRect(&rClipRect);
  1183. }
  1184.  
  1185. void COleClientItem::OnShowItem()
  1186. {
  1187.     ASSERT_VALID(this);
  1188.  
  1189.     CDocument* pDoc = GetDocument();
  1190.     ASSERT_VALID(pDoc);
  1191.  
  1192.     // attempt to use m_pView set during activation
  1193.     CView* pView = m_pView;
  1194.     if (pView == NULL)
  1195.     {
  1196.         // otherwise, find the first view of this document
  1197.         POSITION pos = pDoc->GetFirstViewPosition();
  1198.         if (pos == NULL || (pView = pDoc->GetNextView(pos)) == NULL)
  1199.             return;
  1200.     }
  1201.  
  1202.     CFrameWnd* pFrameWnd = pView->GetParentFrame();
  1203.     if (pFrameWnd != NULL)
  1204.     {
  1205.         // activate frame holding view
  1206.         pFrameWnd->ActivateFrame();
  1207.         pFrameWnd->OnUpdateFrameTitle(TRUE);
  1208.  
  1209.         // activate app frame if necessary
  1210.         pFrameWnd = pFrameWnd->GetParentFrame();
  1211.         if (pFrameWnd != NULL)
  1212.         {
  1213.             ASSERT_KINDOF(CFrameWnd, pFrameWnd);
  1214.             pFrameWnd->ActivateFrame();
  1215.             pFrameWnd->OnUpdateFrameTitle(TRUE);
  1216.         }
  1217.     }
  1218.  
  1219.     if (!pDoc->GetPathName().IsEmpty())
  1220.     {
  1221.         // user is also in control of the application, when a file-based
  1222.         //  document becomes visible.
  1223.         AfxOleSetUserCtrl(TRUE);
  1224.     }
  1225. }
  1226.  
  1227. /////////////////////////////////////////////////////////////////////////////
  1228. // COleClientItem - attributes
  1229.  
  1230. void COleClientItem::GetClassID(CLSID* pClassID) const
  1231. {
  1232.     ASSERT_VALID(this);
  1233.     ASSERT(m_lpObject != NULL);
  1234.     ASSERT(AfxIsValidAddress(pClassID, sizeof(CLSID)));
  1235.  
  1236.     if (m_lpObject->GetUserClassID(pClassID) != S_OK)
  1237.         *pClassID = CLSID_NULL;
  1238. }
  1239.  
  1240. BOOL COleClientItem::GetExtent(LPSIZE lpSize, DVASPECT nDrawAspect)
  1241. {
  1242.     ASSERT_VALID(this);
  1243.     ASSERT(m_lpObject != NULL);
  1244.     ASSERT(AfxIsValidAddress(lpSize, sizeof(CSize)));
  1245.  
  1246.     // use current default aspect if specific one not specified
  1247.     if (nDrawAspect == -1)
  1248.         nDrawAspect = m_nDrawAspect;
  1249.  
  1250.     // get the extent
  1251.     m_scLast = m_lpObject->GetExtent(nDrawAspect, lpSize);
  1252.     return m_scLast == S_OK;
  1253. }
  1254.  
  1255. BOOL COleClientItem::GetCachedExtent(LPSIZE lpSize, DVASPECT nDrawAspect)
  1256. {
  1257.     ASSERT_VALID(this);
  1258.     ASSERT(m_lpViewObject != NULL);
  1259.     ASSERT(AfxIsValidAddress(lpSize, sizeof(CSize)));
  1260.  
  1261.     // use current default aspect if specific one not specified
  1262.     if (nDrawAspect == -1)
  1263.         nDrawAspect = m_nDrawAspect;
  1264.  
  1265.     COleDocument* pDoc = (COleDocument*)GetDocument();
  1266.     ASSERT_VALID(pDoc);
  1267.  
  1268.     // get the extent
  1269.     m_scLast = m_lpViewObject->GetExtent(nDrawAspect, -1, pDoc->m_ptd, lpSize);
  1270.     return m_scLast == S_OK;
  1271. }
  1272.  
  1273. BOOL COleClientItem::SetIconicMetafile(HGLOBAL hMetaPict)
  1274. {
  1275.     ASSERT_VALID(this);
  1276.     ASSERT(m_lpObject != NULL);
  1277.  
  1278.     // get IOleCache interface
  1279.     LPOLECACHE lpOleCache = QUERYINTERFACE(m_lpObject, IOleCache);
  1280.     if (lpOleCache == NULL)
  1281.     {
  1282.         TRACE0("Warning: object does not support IOleCache interface.\n");
  1283.         return FALSE;
  1284.     }
  1285.     ASSERT(lpOleCache != NULL);
  1286.  
  1287.     // new cache is for CF_METAFILEPICT, DVASPECT_ICON
  1288.     FORMATETC formatEtc;
  1289.     formatEtc.cfFormat = CF_METAFILEPICT;
  1290.     formatEtc.ptd = NULL;
  1291.     formatEtc.dwAspect = DVASPECT_ICON;
  1292.     formatEtc.lindex = -1;
  1293.     formatEtc.tymed = TYMED_MFPICT;
  1294.  
  1295.     // setup the cache so iconic aspect is now included
  1296.     DWORD dwConnection;
  1297.     SCODE sc = lpOleCache->Cache(&formatEtc,
  1298.         ADVF_NODATA|ADVF_PRIMEFIRST|ADVF_ONLYONCE, &dwConnection);
  1299.     if (FAILED(sc))
  1300.     {
  1301.         lpOleCache->Release();
  1302.         return FALSE;
  1303.     }
  1304.  
  1305.     // set data if iconic image provided
  1306.     if (hMetaPict != NULL)
  1307.     {
  1308.         STGMEDIUM stgMedium;
  1309.         stgMedium.tymed = TYMED_MFPICT;
  1310.         stgMedium.hGlobal = hMetaPict;
  1311.         stgMedium.pUnkForRelease = NULL;
  1312.  
  1313.         sc = lpOleCache->SetData(&formatEtc, &stgMedium, FALSE);
  1314.         if (FAILED(sc))
  1315.         {
  1316.             lpOleCache->Release();
  1317.             return FALSE;
  1318.         }
  1319.     }
  1320.     lpOleCache->Release();
  1321.  
  1322.     return TRUE;
  1323. }
  1324.  
  1325. HGLOBAL COleClientItem::GetIconicMetafile()
  1326. {
  1327.     USES_CONVERSION;
  1328.  
  1329.     ASSERT_VALID(this);
  1330.     ASSERT(m_lpObject != NULL);
  1331.  
  1332.     // get IDataObject interface
  1333.     LPDATAOBJECT lpDataObject = QUERYINTERFACE(m_lpObject, IDataObject);
  1334.     ASSERT(lpDataObject != NULL);
  1335.  
  1336.     // cache is for CF_METAFILEPICT, DVASPECT_ICON
  1337.     FORMATETC formatEtc;
  1338.     formatEtc.cfFormat = CF_METAFILEPICT;
  1339.     formatEtc.ptd = NULL;
  1340.     formatEtc.dwAspect = DVASPECT_ICON;
  1341.     formatEtc.lindex = -1;
  1342.     formatEtc.tymed = TYMED_MFPICT;
  1343.  
  1344.     // attempt to get the icon picture
  1345.     STGMEDIUM stgMedium;
  1346.     if (lpDataObject->GetData(&formatEtc, &stgMedium) != S_OK)
  1347.     {
  1348.         lpDataObject->Release();
  1349.  
  1350.         // no current picture, attempt to get from class ID
  1351.         CLSID clsid;
  1352.         if (m_lpObject->GetUserClassID(&clsid) != S_OK)
  1353.             return NULL;
  1354.  
  1355.         TCHAR szTemp[_MAX_PATH];
  1356.         LPTSTR lpszLabel = NULL;
  1357.         if (GetType() == OT_LINK)
  1358.         {
  1359.             // it is a link, attempt to get link name
  1360.             LPOLELINK lpOleLink = QUERYINTERFACE(m_lpObject, IOleLink);
  1361.             if (lpOleLink != NULL)
  1362.             {
  1363.                 LPOLESTR lpszDisplayName = NULL;
  1364.                 lpOleLink->GetSourceDisplayName(&lpszDisplayName);
  1365.                 if (lpszDisplayName != NULL)
  1366.                 {
  1367.                     szTemp[0] = 0;
  1368.                     AfxGetFileTitle(OLE2CT(lpszDisplayName), szTemp, _countof(szTemp));
  1369.                     if (szTemp[0] != '\0')
  1370.                         lpszLabel = szTemp;
  1371.                     CoTaskMemFree(lpszDisplayName);
  1372.                 }
  1373.                 lpOleLink->Release();
  1374.             }
  1375.         }
  1376.  
  1377.         HGLOBAL hMetaPict = OleGetIconOfClass(clsid, T2OLE(lpszLabel), lpszLabel == NULL);
  1378.         if (hMetaPict != NULL)
  1379.         {
  1380.             // cache it for later GetData (or drawing)
  1381.             SetIconicMetafile(hMetaPict);
  1382.             return hMetaPict;
  1383.         }
  1384.         return NULL;
  1385.     }
  1386.     lpDataObject->Release();
  1387.  
  1388.     // can't handle data where punkForRelease is set
  1389.     if (stgMedium.pUnkForRelease != NULL)
  1390.     {
  1391.         ::ReleaseStgMedium(&stgMedium);
  1392.         return NULL;
  1393.     }
  1394.     ASSERT(stgMedium.tymed == TYMED_MFPICT);
  1395.     ASSERT(stgMedium.hGlobal != NULL);
  1396.  
  1397.     return stgMedium.hGlobal;   // return HGLOBAL to METAFILEPICT
  1398. }
  1399.  
  1400. void COleClientItem::SetDrawAspect(DVASPECT nDrawAspect)
  1401. {
  1402.     ASSERT_VALID(this);
  1403.  
  1404.     // prime iconic cache (in case object has never displayed iconic)
  1405.     if (nDrawAspect == DVASPECT_ICON)
  1406.     {
  1407.         SetIconicMetafile(NULL);    // allow object to provide own icon
  1408.         HGLOBAL hMetaPict = GetIconicMetafile();
  1409.         _AfxDeleteMetafilePict(hMetaPict);
  1410.     }
  1411.  
  1412.     // Note: the aspect you are setting may be uncached and therefore blank.
  1413.     //  To make sure it is cached use SetIconPicture or use IOleCache to
  1414.     //  set the cache yourself.
  1415.     m_nDrawAspect = nDrawAspect;
  1416.  
  1417.     // mark document as dirty (m_nDrawAspect is part of persistent state)
  1418.     ASSERT_VALID(m_pDocument);
  1419.     m_pDocument->SetModifiedFlag();
  1420. }
  1421.  
  1422. // Helper used to get the DVTARGETDEVICE pointer for the first printer.
  1423. BOOL COleClientItem::GetPrintDeviceInfo(
  1424.     LPOLECACHE* plpOleCache, DVTARGETDEVICE** pptd, DWORD* pdwConnection)
  1425. {
  1426.     *plpOleCache = NULL;
  1427.     *pptd = NULL;
  1428.  
  1429.     // get IOleCache interface
  1430.     LPOLECACHE lpOleCache = QUERYINTERFACE(m_lpObject, IOleCache);
  1431.     if (lpOleCache == NULL)
  1432.     {
  1433.         TRACE0("Warning: object does not support IOleCache interface.\n");
  1434.         return FALSE;   // no cache -- no possible print device
  1435.     }
  1436.     ASSERT(lpOleCache != NULL);
  1437.  
  1438.     // get enumerator for the cache
  1439.     LPENUMSTATDATA lpEnumSTATDATA;
  1440.     if (lpOleCache->EnumCache(&lpEnumSTATDATA) != S_OK || lpEnumSTATDATA == NULL)
  1441.     {
  1442.         lpOleCache->Release();
  1443.         return FALSE;
  1444.     }
  1445.     // enumerate entries in the cache (look for one with ptd != NULL)
  1446.     STATDATA statData;
  1447.     while (lpEnumSTATDATA->Next(1, &statData, NULL) == S_OK)
  1448.     {
  1449.         ASSERT(statData.pAdvSink == NULL);
  1450.  
  1451.         // return first non-NULL ptd (we assume this is a printer cache)
  1452.         if (statData.formatetc.ptd != NULL)
  1453.         {
  1454.             if (pdwConnection != NULL)
  1455.                 *pdwConnection = statData.dwConnection;
  1456.             *pptd = statData.formatetc.ptd;
  1457.             lpEnumSTATDATA->Release();
  1458.  
  1459.             *plpOleCache = lpOleCache;
  1460.             return TRUE;    // Note: lpOleCache pointer is still alive
  1461.         }
  1462.     }
  1463.     // release interfaces
  1464.     lpEnumSTATDATA->Release();
  1465.     lpOleCache->Release();
  1466.     return FALSE;   // data not found
  1467. }
  1468.  
  1469. void COleClientItem::AttachDataObject(COleDataObject& rDataObject) const
  1470. {
  1471.     ASSERT_VALID(this);
  1472.     ASSERT(m_lpObject != NULL);
  1473.  
  1474.     // get the IDataObject interface for the item
  1475.     LPDATAOBJECT lpDataObject = QUERYINTERFACE(m_lpObject, IDataObject);
  1476.     ASSERT(lpDataObject != NULL);
  1477.  
  1478.     // return it by attaching it
  1479.     rDataObject.Attach(lpDataObject, TRUE);
  1480. }
  1481.  
  1482. /////////////////////////////////////////////////////////////////////////////
  1483. // COleClientItem - general operations
  1484.  
  1485. BOOL COleClientItem::Draw(CDC* pDC, LPCRECT lpBounds, DVASPECT nDrawAspect)
  1486. {
  1487.     ASSERT_VALID(this);
  1488.     ASSERT(AfxIsValidAddress(lpBounds, sizeof(RECT), FALSE));
  1489.     ASSERT_VALID(pDC);
  1490.  
  1491.     if (m_lpObject == NULL || m_lpViewObject == NULL)
  1492.         return FALSE;   // partially created COleClientItem object
  1493.  
  1494.     // use current draw aspect if aspect is -1 (default)
  1495.     if (nDrawAspect == -1)
  1496.         nDrawAspect = m_nDrawAspect;
  1497.  
  1498.     // convert RECT lpBounds to RECTL rclBounds
  1499.     RECTL rclBounds;
  1500.     rclBounds.left = lpBounds->left;
  1501.     rclBounds.top = lpBounds->top;
  1502.     rclBounds.right = lpBounds->right;
  1503.     rclBounds.bottom = lpBounds->bottom;
  1504.  
  1505.     // get RECTL describing window extents and origin
  1506.     RECTL rclWBounds;
  1507.     CPoint ptOrg = pDC->GetWindowOrg();
  1508.     CSize sizeExt = pDC->GetWindowExt();
  1509.     rclWBounds.left = ptOrg.x;
  1510.     rclWBounds.top = ptOrg.y;
  1511.     rclWBounds.right = sizeExt.cx;
  1512.     rclWBounds.bottom = sizeExt.cy;
  1513.  
  1514.     // get target device to use for draw
  1515.     COleDocument* pDoc = GetDocument();
  1516.     const DVTARGETDEVICE* ptd = NULL;
  1517.     HDC hdcTarget = NULL;
  1518.     if (pDC->IsPrinting() && pDoc->m_ptd != NULL)
  1519.     {
  1520.         ptd = pDoc->m_ptd;
  1521.         hdcTarget = pDC->m_hAttribDC;
  1522.     }
  1523.  
  1524.     // attempt draw with target device
  1525.     SCODE sc = m_lpViewObject->Draw(nDrawAspect, -1, NULL,
  1526.         (DVTARGETDEVICE*)ptd, hdcTarget, pDC->m_hDC,
  1527.         &rclBounds, &rclWBounds, NULL, 0);
  1528.     if (ptd != NULL && sc == OLE_E_BLANK)
  1529.     {
  1530.         // attempt draw without target device
  1531.         sc = m_lpViewObject->Draw(nDrawAspect, -1, NULL,
  1532.             NULL, NULL, pDC->m_hDC,
  1533.             &rclBounds, &rclWBounds, NULL, 0);
  1534.     }
  1535.  
  1536.     if (sc != S_OK && sc == OLE_E_BLANK)
  1537.         return FALSE;   // return FALSE if the object is blank
  1538.  
  1539.     CheckGeneral(sc);   // otherwise, may throw exception on error
  1540.     return TRUE;
  1541. }
  1542.  
  1543. /////////////////////////////////////////////////////////////////////////////
  1544. // COleClientItem clipboard helpers
  1545.  
  1546. void COleClientItem::GetEmbeddedItemData(LPSTGMEDIUM lpStgMedium)
  1547. {
  1548.     ASSERT_VALID(this);
  1549.     ASSERT(AfxIsValidAddress(lpStgMedium, sizeof(STGMEDIUM)));
  1550.  
  1551.     LPLOCKBYTES lpLockBytes;
  1552.     SCODE sc = ::CreateILockBytesOnHGlobal(NULL, TRUE, &lpLockBytes);
  1553.     if (sc != S_OK)
  1554.         AfxThrowOleException(sc);
  1555.     ASSERT(lpLockBytes != NULL);
  1556.  
  1557.     LPSTORAGE lpStorage;
  1558.     sc = ::StgCreateDocfileOnILockBytes(lpLockBytes,
  1559.         STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0, &lpStorage);
  1560.     if (sc != S_OK)
  1561.     {
  1562.         VERIFY(lpLockBytes->Release() == 0);
  1563.         AfxThrowOleException(sc);
  1564.     }
  1565.     ASSERT(lpStorage != NULL);
  1566.     lpLockBytes->Release();
  1567.  
  1568.     // save the object into the storage
  1569.     LPPERSISTSTORAGE lpPersistStorage =
  1570.         QUERYINTERFACE(m_lpObject, IPersistStorage);
  1571.     ASSERT(lpPersistStorage != NULL);
  1572.     sc = ::OleSave(lpPersistStorage, lpStorage, FALSE);
  1573.     lpPersistStorage->SaveCompleted(NULL);
  1574.     lpPersistStorage->Release();
  1575.     if (sc != S_OK)
  1576.     {
  1577.         VERIFY(lpStorage->Release() == 0);
  1578.         AfxThrowOleException(sc);
  1579.     }
  1580.  
  1581.     // add it to the data source
  1582.     lpStgMedium->tymed = TYMED_ISTORAGE;
  1583.     lpStgMedium->pstg = lpStorage;
  1584.     lpStgMedium->pUnkForRelease = NULL;
  1585. }
  1586.  
  1587. void COleClientItem::AddCachedData(COleDataSource* pDataSource)
  1588. {
  1589.     ASSERT_VALID(this);
  1590.     ASSERT_VALID(pDataSource);
  1591.  
  1592.     // get IOleCache interface
  1593.     LPOLECACHE lpOleCache = QUERYINTERFACE(m_lpObject, IOleCache);
  1594.     if (lpOleCache == NULL)
  1595.     {
  1596.         TRACE0("Warning: object does not support IOleCache interface.\n");
  1597.         return;
  1598.     }
  1599.     ASSERT(lpOleCache != NULL);
  1600.  
  1601.     // Get IEnumSTATDATA interface for IOleCache
  1602.     LPENUMSTATDATA lpEnumSTATDATA;
  1603.     if (lpOleCache->EnumCache(&lpEnumSTATDATA) != S_OK || lpEnumSTATDATA == NULL)
  1604.     {
  1605.         lpOleCache->Release();
  1606.         return;
  1607.     }
  1608.  
  1609.     // get IDataObject interface
  1610.     LPDATAOBJECT lpDataObject = QUERYINTERFACE(m_lpObject, IDataObject);
  1611.     ASSERT(lpDataObject != NULL);
  1612.  
  1613.     // enumerate all of the cached formats
  1614.     STATDATA statData;
  1615.     while (lpEnumSTATDATA->Next(1, &statData, NULL) == S_OK)
  1616.     {
  1617.         ASSERT(statData.pAdvSink == NULL);
  1618.  
  1619.         // for each format supported, attempt to get copy of the data
  1620.         STGMEDIUM stgMedium;
  1621.         if (lpDataObject->GetData(&statData.formatetc, &stgMedium) != S_OK)
  1622.         {
  1623.             // data is not available
  1624.             CoTaskMemFree(statData.formatetc.ptd);
  1625.         }
  1626.         else if (stgMedium.pUnkForRelease != NULL)
  1627.         {
  1628.             // don't cache data with pUnkForRelease != NULL
  1629.             ::ReleaseStgMedium(&stgMedium);
  1630.             CoTaskMemFree(statData.formatetc.ptd);
  1631.         }
  1632.         else
  1633.         {
  1634.             // format was acceptable -- add it to the clipboard
  1635.             pDataSource->CacheData(0, &stgMedium, &statData.formatetc);
  1636.         }
  1637.     }
  1638.  
  1639.     // release interfaces
  1640.     lpEnumSTATDATA->Release();
  1641.     lpDataObject->Release();
  1642.     lpOleCache->Release();
  1643. }
  1644.  
  1645. BOOL COleClientItem::GetLinkSourceData(LPSTGMEDIUM lpStgMedium)
  1646. {
  1647.     ASSERT_VALID(this);
  1648.     ASSERT(AfxIsValidAddress(lpStgMedium, sizeof(STGMEDIUM)));
  1649.  
  1650.     LPMONIKER lpMoniker = NULL;
  1651.     LPOLELINK lpOleLink = QUERYINTERFACE(m_lpObject, IOleLink);
  1652.     if (lpOleLink == NULL)
  1653.     {
  1654.         // get moniker from client site
  1655.         LPOLECLIENTSITE lpClientSite = GetClientSite();
  1656.         ASSERT(lpClientSite != NULL);
  1657.         SCODE sc = lpClientSite->GetMoniker(OLEGETMONIKER_TEMPFORUSER,
  1658.             OLEWHICHMK_OBJFULL, &lpMoniker);
  1659.         if (sc != S_OK)
  1660.         {
  1661.             TRACE0("Warning: unable to get moniker from client site.\n");
  1662.             return FALSE;
  1663.         }
  1664.         ASSERT(lpMoniker != NULL);
  1665.     }
  1666.     else
  1667.     {
  1668.         // get moniker from the link object itself
  1669.         SCODE sc = lpOleLink->GetSourceMoniker(&lpMoniker);
  1670.         lpOleLink->Release();
  1671.         if (sc != S_OK)
  1672.         {
  1673.             TRACE0("Warning: unable to get moniker from link source.\n");
  1674.             return FALSE;
  1675.         }
  1676.         ASSERT(lpMoniker != NULL);
  1677.     }
  1678.  
  1679.     // create a memory based stream to write the moniker to
  1680.     LPSTREAM lpStream;
  1681.     if (::CreateStreamOnHGlobal(NULL, TRUE, &lpStream) != S_OK)
  1682.     {
  1683.         lpMoniker->Release();
  1684.         AfxThrowMemoryException();
  1685.     }
  1686.     ASSERT(lpStream != NULL);
  1687.  
  1688.     // write the moniker to the stream, and add it to the clipboard
  1689.     SCODE sc = ::OleSaveToStream(lpMoniker, lpStream);
  1690.     lpMoniker->Release();
  1691.     if (sc != S_OK)
  1692.     {
  1693.         lpStream->Release();
  1694.         AfxThrowOleException(sc);
  1695.     }
  1696.  
  1697.     // write the class ID of the document to the stream as well
  1698.     CLSID clsid;
  1699.     sc = m_lpObject->GetUserClassID(&clsid);
  1700.     if (sc != S_OK)
  1701.     {
  1702.         lpStream->Release();
  1703.         AfxThrowOleException(sc);
  1704.     }
  1705.     sc = WriteClassStm(lpStream, clsid);
  1706.     if (sc != S_OK)
  1707.     {
  1708.         lpStream->Release();
  1709.         AfxThrowOleException(sc);
  1710.     }
  1711.  
  1712.     // add it to the data source
  1713.     lpStgMedium->tymed = TYMED_ISTREAM;
  1714.     lpStgMedium->pstm = lpStream;
  1715.     lpStgMedium->pUnkForRelease = NULL;
  1716.     return TRUE;
  1717. }
  1718.  
  1719. void COleClientItem::GetObjectDescriptorData(
  1720.     LPPOINT lpOffset, LPSIZE lpSize, LPSTGMEDIUM lpStgMedium)
  1721. {
  1722.     USES_CONVERSION;
  1723.  
  1724.     ASSERT_VALID(this);
  1725.     ASSERT(AfxIsValidAddress(lpStgMedium, sizeof(STGMEDIUM)));
  1726.     ASSERT(lpOffset == NULL ||
  1727.         AfxIsValidAddress(lpOffset, sizeof(CPoint), FALSE));
  1728.  
  1729.     POINTL pointT;
  1730.     if (lpOffset != NULL)
  1731.     {
  1732.         pointT.x = lpOffset->x;
  1733.         pointT.y = lpOffset->y;
  1734. #ifndef _MAC
  1735.         ((CDC*)NULL)->DPtoHIMETRIC((SIZE*)&pointT);
  1736. #endif
  1737.     }
  1738.     else
  1739.     {
  1740.         pointT.x = 0;
  1741.         pointT.y = 0;
  1742.     }
  1743.  
  1744.     SIZE sizeT;
  1745.     if (lpSize != NULL)
  1746.     {
  1747.         sizeT.cx = lpSize->cx;
  1748.         sizeT.cy = lpSize->cy;
  1749. #ifndef _MAC
  1750.         ((CDC*)NULL)->DPtoHIMETRIC(&sizeT);
  1751. #endif
  1752.     }
  1753.     else
  1754.     {
  1755.         sizeT.cx = 0;
  1756.         sizeT.cy = 0;
  1757.     }
  1758.  
  1759.     COleDocument* pDoc = GetDocument();
  1760.  
  1761.     // get the object descriptor for the IOleObject
  1762.     InterlockedIncrement(&m_dwRef);
  1763.     HGLOBAL hGlobal = _AfxOleGetObjectDescriptorData(
  1764.         m_lpObject, T2COLE(pDoc->GetPathName()), m_nDrawAspect, pointT, &sizeT);
  1765.     InterlockedDecrement(&m_dwRef);
  1766.  
  1767.     if (hGlobal == NULL)
  1768.         AfxThrowMemoryException();
  1769.  
  1770.     // setup the STGMEDIUM
  1771.     lpStgMedium->tymed = TYMED_HGLOBAL;
  1772.     lpStgMedium->hGlobal = hGlobal;
  1773.     lpStgMedium->pUnkForRelease = NULL;
  1774. }
  1775.  
  1776. /////////////////////////////////////////////////////////////////////////////
  1777. // Embedded COleClientItem operations
  1778.  
  1779. void COleClientItem::SetHostNames(LPCTSTR lpszHost, LPCTSTR lpszHostObj)
  1780. {
  1781.     USES_CONVERSION;
  1782.  
  1783.     ASSERT_VALID(this);
  1784.     ASSERT(m_lpObject != NULL);
  1785.     ASSERT(AfxIsValidString(lpszHost));
  1786.  
  1787.     ASSERT(AfxIsValidString(lpszHostObj));
  1788.     CheckGeneral(m_lpObject->SetHostNames(T2COLE(lpszHost),
  1789.         T2COLE(lpszHostObj)));
  1790. }
  1791.  
  1792. void COleClientItem::SetExtent(const CSize& size, DVASPECT nDrawAspect)
  1793. {
  1794.     ASSERT_VALID(this);
  1795.     ASSERT(m_lpObject != NULL);
  1796.  
  1797.     CheckGeneral(m_lpObject->SetExtent(nDrawAspect, (SIZE*)&size));
  1798. }
  1799.  
  1800. /////////////////////////////////////////////////////////////////////////////
  1801. // COleClientItem OLE interface implementation
  1802.  
  1803. BEGIN_INTERFACE_MAP(COleClientItem, CDocItem)
  1804.     INTERFACE_PART(COleClientItem, IID_IOleClientSite, OleClientSite)
  1805.     INTERFACE_PART(COleClientItem, IID_IAdviseSink, AdviseSink)
  1806.     INTERFACE_PART(COleClientItem, IID_IOleWindow, OleIPSite)
  1807.     INTERFACE_PART(COleClientItem, IID_IOleInPlaceSite, OleIPSite)
  1808. END_INTERFACE_MAP()
  1809.  
  1810. /////////////////////////////////////////////////////////////////////////////
  1811. // Implementation of IOleClientSite
  1812.  
  1813. STDMETHODIMP_(ULONG) COleClientItem::XOleClientSite::AddRef()
  1814. {
  1815.     METHOD_PROLOGUE_EX_(COleClientItem, OleClientSite)
  1816.     return pThis->ExternalAddRef();
  1817. }
  1818.  
  1819. STDMETHODIMP_(ULONG) COleClientItem::XOleClientSite::Release()
  1820. {
  1821.     METHOD_PROLOGUE_EX_(COleClientItem, OleClientSite)
  1822.     return pThis->ExternalRelease();
  1823. }
  1824.  
  1825. STDMETHODIMP COleClientItem::XOleClientSite::QueryInterface(
  1826.     REFIID iid, LPVOID* ppvObj)
  1827. {
  1828.     METHOD_PROLOGUE_EX_(COleClientItem, OleClientSite)
  1829.     return pThis->ExternalQueryInterface(&iid, ppvObj);
  1830. }
  1831.  
  1832. STDMETHODIMP COleClientItem::XOleClientSite::SaveObject()
  1833. {
  1834.     METHOD_PROLOGUE_EX(COleClientItem, OleClientSite)
  1835.     ASSERT_VALID(pThis);
  1836.  
  1837.     LPPERSISTSTORAGE lpPersistStorage =
  1838.         QUERYINTERFACE(pThis->m_lpObject, IPersistStorage);
  1839.     ASSERT(lpPersistStorage != NULL);
  1840.     SCODE sc = S_OK;
  1841.     if (lpPersistStorage->IsDirty() == S_OK)
  1842.     {
  1843.         // S_OK == S_OK != S_FALSE, therefore object is dirty!
  1844.         sc = ::OleSave(lpPersistStorage, pThis->m_lpStorage, TRUE);
  1845.         if (sc != S_OK)
  1846.             sc = lpPersistStorage->SaveCompleted(NULL);
  1847.  
  1848.         // mark the document as dirty, if save sucessful.
  1849.         pThis->m_pDocument->SetModifiedFlag();
  1850.     }
  1851.     lpPersistStorage->Release();
  1852.     return sc;
  1853. }
  1854.  
  1855. STDMETHODIMP COleClientItem::XOleClientSite::GetMoniker(
  1856.     DWORD dwAssign, DWORD dwWhichMoniker, LPMONIKER* ppMoniker)
  1857. {
  1858.     METHOD_PROLOGUE_EX(COleClientItem, OleClientSite)
  1859.     ASSERT_VALID(pThis);
  1860.  
  1861.     USES_CONVERSION;
  1862.  
  1863.     COleDocument* pDoc = pThis->GetDocument();
  1864.     ASSERT_VALID(pDoc);
  1865.     ASSERT(ppMoniker != NULL);
  1866.     *ppMoniker = NULL;
  1867.  
  1868.     switch (dwWhichMoniker)
  1869.     {
  1870.     case OLEWHICHMK_CONTAINER:
  1871.         // return the current moniker for the document
  1872.         *ppMoniker = pDoc->GetMoniker((OLEGETMONIKER)dwAssign);
  1873.         break;
  1874.  
  1875.     case OLEWHICHMK_OBJREL:
  1876.         {
  1877.             if (!pDoc->IsKindOf(RUNTIME_CLASS(COleLinkingDoc)))
  1878.                 break;
  1879.  
  1880.             // don't return relative moniker if no document moniker
  1881.             LPMONIKER lpMoniker = pDoc->GetMoniker((OLEGETMONIKER)dwAssign);
  1882.             if (lpMoniker == NULL)
  1883.                 break;
  1884.             lpMoniker->Release();
  1885.  
  1886.             // relative monikers have to handle assignment correctly
  1887.             switch (dwAssign)
  1888.             {
  1889.             case OLEGETMONIKER_ONLYIFTHERE:
  1890.                 if (!pThis->m_bMoniker)
  1891.                     break;  // no moniker assigned, don't return one
  1892.                 // fall through...
  1893.  
  1894.             case OLEGETMONIKER_TEMPFORUSER:
  1895.             case OLEGETMONIKER_FORCEASSIGN:
  1896.                 {
  1897.                     // create item moniker from item name
  1898.                     TCHAR szItemName[OLE_MAXITEMNAME];
  1899.                     pThis->GetItemName(szItemName);
  1900.                     CreateItemMoniker(OLESTDDELIMOLE, T2COLE(szItemName),
  1901.                         ppMoniker);
  1902.  
  1903.                     // notify the object of the assignment
  1904.                     if (dwAssign != OLEGETMONIKER_TEMPFORUSER &&
  1905.                         *ppMoniker != NULL && !pThis->m_bMoniker)
  1906.                     {
  1907.                         pThis->m_bMoniker = TRUE;
  1908.                         VERIFY(pThis->m_lpObject->SetMoniker(
  1909.                             OLEWHICHMK_OBJREL, *ppMoniker) == S_OK);
  1910.                         ASSERT_VALID(pThis->m_pDocument);
  1911.                         pThis->m_pDocument->SetModifiedFlag();
  1912.                     }
  1913.                 }
  1914.                 break;
  1915.  
  1916.             case OLEGETMONIKER_UNASSIGN:
  1917.                 pThis->m_bMoniker = FALSE;
  1918.                 break;
  1919.             }
  1920.         }
  1921.         break;
  1922.  
  1923.     case OLEWHICHMK_OBJFULL:
  1924.         {
  1925.             // get each sub-moniker: item & document
  1926.             LPMONIKER lpMoniker1, lpMoniker2;
  1927.             GetMoniker(dwAssign, OLEWHICHMK_CONTAINER, &lpMoniker1);
  1928.             GetMoniker(dwAssign, OLEWHICHMK_OBJREL, &lpMoniker2);
  1929.  
  1930.             // create composite moniker
  1931.             if (lpMoniker1 != NULL && lpMoniker2 != NULL)
  1932.                 ::CreateGenericComposite(lpMoniker1, lpMoniker2, ppMoniker);
  1933.  
  1934.             // release sub-monikers
  1935.             RELEASE(lpMoniker1);
  1936.             RELEASE(lpMoniker2);
  1937.         }
  1938.         break;
  1939.     }
  1940.  
  1941.     return *ppMoniker != NULL ? S_OK : E_FAIL;
  1942. }
  1943.  
  1944. STDMETHODIMP COleClientItem::XOleClientSite::GetContainer(
  1945.     LPOLECONTAINER* ppContainer)
  1946. {
  1947. #ifdef _DEBUG
  1948.     METHOD_PROLOGUE_EX(COleClientItem, OleClientSite)
  1949. #else
  1950.     METHOD_PROLOGUE_EX_(COleClientItem, OleClientSite)
  1951. #endif
  1952.  
  1953.     // return the IOleItemContainer interface in the document
  1954.     COleDocument* pDoc = pThis->GetDocument();
  1955.     ASSERT_VALID(pDoc);
  1956.     *ppContainer = pDoc->GetContainer();
  1957.  
  1958.     return *ppContainer != NULL ? S_OK : E_NOINTERFACE;
  1959. }
  1960.  
  1961. STDMETHODIMP COleClientItem::XOleClientSite::ShowObject()
  1962. {
  1963.     METHOD_PROLOGUE_EX(COleClientItem, OleClientSite)
  1964.     ASSERT_VALID(pThis);
  1965.  
  1966.     TRY
  1967.     {
  1968.         pThis->OnShowItem();
  1969.     }
  1970.     END_TRY
  1971.  
  1972.     return S_OK;
  1973. }
  1974.  
  1975. STDMETHODIMP COleClientItem::XOleClientSite::OnShowWindow(BOOL fShow)
  1976. {
  1977.     METHOD_PROLOGUE_EX(COleClientItem, OleClientSite)
  1978.     ASSERT_VALID(pThis);
  1979.  
  1980.     // ignore this if the item is already in-place
  1981.     if (pThis->IsInPlaceActive())
  1982.         return S_OK;
  1983.  
  1984.     TRY
  1985.     {
  1986.         // store new state of object -- determines how object may be drawn
  1987.         COleClientItem::ItemState uNewState;
  1988.         uNewState = fShow ? COleClientItem::openState :
  1989.             COleClientItem::loadedState;
  1990.         if (uNewState != pThis->m_nItemState)
  1991.         {
  1992.             pThis->OnChange(OLE_CHANGED_STATE, (DWORD)uNewState);
  1993.             pThis->m_nItemState = uNewState;
  1994.         }
  1995.     }
  1996.     END_TRY
  1997.  
  1998.     return S_OK;
  1999. }
  2000.  
  2001. STDMETHODIMP COleClientItem::XOleClientSite::RequestNewObjectLayout()
  2002. {
  2003.     return E_NOTIMPL;
  2004. }
  2005.  
  2006. /////////////////////////////////////////////////////////////////////////////
  2007. // Implementation of IAdviseSink
  2008.  
  2009. STDMETHODIMP_(ULONG) COleClientItem::XAdviseSink::AddRef()
  2010. {
  2011.     METHOD_PROLOGUE_EX_(COleClientItem, AdviseSink)
  2012.     return pThis->ExternalAddRef();
  2013. }
  2014.  
  2015. STDMETHODIMP_(ULONG) COleClientItem::XAdviseSink::Release()
  2016. {
  2017.     METHOD_PROLOGUE_EX_(COleClientItem, AdviseSink)
  2018.     return pThis->ExternalRelease();
  2019. }
  2020.  
  2021. STDMETHODIMP COleClientItem::XAdviseSink::QueryInterface(
  2022.     REFIID iid, LPVOID* ppvObj)
  2023. {
  2024.     METHOD_PROLOGUE_EX_(COleClientItem, AdviseSink)
  2025.     return pThis->ExternalQueryInterface(&iid, ppvObj);
  2026. }
  2027.  
  2028. STDMETHODIMP_(void) COleClientItem::XAdviseSink::OnDataChange(
  2029.     LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium)
  2030. {
  2031.     METHOD_PROLOGUE_EX(COleClientItem, AdviseSink)
  2032.     ASSERT_VALID(pThis);
  2033.  
  2034.     // Only interesting for advanced containers.  Forward it such that
  2035.     // containers do not have to implement the entire interface.
  2036.     pThis->OnDataChange(lpFormatEtc, lpStgMedium);
  2037. }
  2038.  
  2039. STDMETHODIMP_(void) COleClientItem::XAdviseSink::OnViewChange(
  2040.     DWORD aspects, LONG /*lindex*/)
  2041. {
  2042.     METHOD_PROLOGUE_EX(COleClientItem, AdviseSink)
  2043.     ASSERT_VALID(pThis);
  2044.  
  2045.     pThis->OnChange(OLE_CHANGED, (DVASPECT)aspects);
  2046. }
  2047.  
  2048. STDMETHODIMP_(void) COleClientItem::XAdviseSink::OnRename(
  2049.     LPMONIKER /*lpMoniker*/)
  2050. {
  2051.     // only interesting to the OLE link object.  Containers ignore this.
  2052. }
  2053.  
  2054. STDMETHODIMP_(void) COleClientItem::XAdviseSink::OnSave()
  2055. {
  2056.     METHOD_PROLOGUE_EX(COleClientItem, AdviseSink)
  2057.     ASSERT_VALID(pThis);
  2058.  
  2059.     pThis->OnChange(OLE_SAVED, (DVASPECT)0);
  2060. }
  2061.  
  2062. STDMETHODIMP_(void) COleClientItem::XAdviseSink::OnClose()
  2063. {
  2064.     METHOD_PROLOGUE_EX(COleClientItem, AdviseSink)
  2065.     ASSERT_VALID(pThis);
  2066.  
  2067.     pThis->OnChange(OLE_CLOSED, (DVASPECT)0);
  2068. }
  2069.  
  2070. /////////////////////////////////////////////////////////////////////////////
  2071. // COleClientItem diagnostics
  2072.  
  2073. #ifdef _DEBUG
  2074. void COleClientItem::AssertValid() const
  2075. {
  2076.     CDocItem::AssertValid();
  2077.     if (m_lpNewStorage != NULL)
  2078.         ASSERT(m_bNeedCommit);
  2079.     if (m_pView != NULL)
  2080.         m_pView->AssertValid();
  2081.     if (m_pInPlaceFrame != NULL)
  2082.         m_pInPlaceFrame->AssertValid();
  2083.     if (m_pInPlaceDoc != NULL)
  2084.         m_pInPlaceDoc->AssertValid();
  2085. }
  2086.  
  2087. void COleClientItem::Dump(CDumpContext& dc) const
  2088. {
  2089.     CDocItem::Dump(dc);
  2090.  
  2091.     // shallow dump
  2092.     dc << "m_lpObject = " << (void*)m_lpObject;
  2093.     dc << "\nm_dwItemNumber = " << m_dwItemNumber;
  2094.     dc << "\nm_nDrawAspect = " << (int)m_nDrawAspect;
  2095.     dc << "\nm_scLast = " << m_scLast;
  2096.     dc << "\nm_lpStorage = " << m_lpStorage;
  2097.     dc << "\nm_lpLockBytes = " << m_lpLockBytes;
  2098.     dc << "\nm_dwConnection = " << m_dwConnection;
  2099.     dc << "\nm_bLinkUnavail = " << m_bLinkUnavail;
  2100.     dc << "\nm_bMoniker = " << m_bMoniker;
  2101.     dc << "\nm_lpNewStorage = " << m_lpNewStorage;
  2102.     dc << "\nm_bNeedCommit = " << m_bNeedCommit;
  2103.     dc << "\nm_nItemState = " << (int)m_nItemState;
  2104.     dc << "\nm_pView = " << (void*)m_pView;
  2105.     dc << "\nm_dwContainerStyle = " << m_dwContainerStyle;
  2106.     dc << "\nm_pInPlaceFrame = " << (void*)m_pInPlaceFrame;
  2107.     dc << "\nm_hWndServer = " << m_hWndServer;
  2108. }
  2109. #endif //_DEBUG
  2110.  
  2111. /////////////////////////////////////////////////////////////////////////////
  2112. // Inline function declarations expanded out-of-line
  2113.  
  2114. #ifndef _AFX_ENABLE_INLINES
  2115.  
  2116. // expand inlines for OLE client APIs
  2117. static char _szAfxOleInl[] = "afxole.inl";
  2118. #undef THIS_FILE
  2119. #define THIS_FILE _szAfxOleInl
  2120. #define _AFXOLECLI_INLINE
  2121. #define _AFXOLEDOBJ_INLINE
  2122. #include "afxole.inl"
  2123.  
  2124. #endif //!_AFX_ENABLE_INLINES
  2125.  
  2126. #ifdef AFX_INIT_SEG
  2127. #pragma code_seg(AFX_INIT_SEG)
  2128. #endif
  2129.  
  2130. // IMPLEMENT_DYNAMIC for COleLinkingDoc here for better .OBJ granularity
  2131. IMPLEMENT_DYNAMIC(COleLinkingDoc, COleDocument)
  2132.  
  2133. /////////////////////////////////////////////////////////////////////////////
  2134.