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

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