home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / mfc / src / olecli3.cpp < prev    next >
C/C++ Source or Header  |  1998-06-16  |  17KB  |  650 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 activation
  26.  
  27. // helper to get client site -- this is called from a number of places
  28. LPOLECLIENTSITE COleClientItem::GetClientSite()
  29. {
  30.     ASSERT_VALID(this);
  31.  
  32.     LPOLECLIENTSITE lpClientSite =
  33.         (LPOLECLIENTSITE)GetInterface(&IID_IOleClientSite);
  34.     ASSERT(lpClientSite != NULL);
  35.     return lpClientSite;
  36. }
  37.  
  38. void COleClientItem::Activate(LONG nVerb, CView* pView, LPMSG lpMsg)
  39. {
  40.     ASSERT_VALID(this);
  41.     ASSERT(m_lpObject != NULL);
  42.     if (pView != NULL)
  43.         ASSERT_VALID(pView);
  44.     if (lpMsg != NULL)
  45.         ASSERT(AfxIsValidAddress(lpMsg, sizeof(MSG), FALSE));
  46.  
  47.     // store the container HWND for in place activation then do the verb
  48.     if (m_pView == NULL)
  49.         m_pView = pView;
  50.  
  51.     _AFX_OLE_STATE* pOleState = _afxOleState;
  52.     CView* pViewSave = pOleState->m_pActivateView;
  53.     pOleState->m_pActivateView = NULL;
  54.  
  55.     // get item rectangle for in-place players
  56.     //  (that may not support in-place activation)
  57.     LPCRECT lpPosRect = NULL;
  58.     CRect rectPos;
  59.     if (pView != NULL)
  60.     {
  61.         ASSERT_VALID(pView);
  62.         rectPos.SetRectEmpty();
  63.         OnGetItemPosition(rectPos);
  64.         if (!rectPos.IsRectEmpty())
  65.         {
  66.             lpPosRect = &rectPos;
  67.             pOleState->m_pActivateView = pView;
  68.         }
  69.     }
  70.  
  71.     // prepare DoVerb parameters and call into the server
  72.     LPOLECLIENTSITE lpClientSite = GetClientSite();
  73.     HWND hWnd = pView->GetSafeHwnd();
  74.     SCODE sc = m_lpObject->DoVerb(nVerb, lpMsg, lpClientSite, -1,
  75.         hWnd, lpPosRect);
  76.  
  77.     pOleState->m_pActivateView = pViewSave;
  78.  
  79.     // clear out m_pView in case in-place activation only partially worked
  80.     if (!IsInPlaceActive())
  81.         m_pView = NULL;
  82.  
  83.     // update available status based on the results of DoVerb
  84.     //  (this is used in the links dialog).
  85.     m_bLinkUnavail = (BYTE)FAILED(sc);
  86.  
  87.     CheckGeneral(sc);
  88. }
  89.  
  90. //////////////////////////////////////////////////////////////////////////////
  91. // Create error handling
  92.  
  93. void COleClientItem::CheckGeneral(SCODE sc)
  94.     // set 'm_scLast'
  95.     // throw exception if not ok to continue
  96. {
  97.     ASSERT_VALID(this);
  98.  
  99.     m_scLast = S_OK;    // assume things are ok
  100.  
  101.     // then, check for error
  102.     if (sc != S_OK)
  103.     {
  104.         m_scLast = sc;
  105.         if (!FAILED(sc))
  106.         {
  107. #ifdef _DEBUG
  108.             // warn about non-NULL success codes
  109.             TRACE1("Warning: operation returned scode = %s.\n",
  110.                 AfxGetFullScodeString(m_scLast));
  111. #endif
  112.             return;
  113.         }
  114.         // this error wasn't expected, so throw an exception
  115.         AfxThrowOleException(sc);
  116.     }
  117. }
  118.  
  119. /////////////////////////////////////////////////////////////////////////////
  120. // COleClientItem clipboard support
  121.  
  122. void COleClientItem::CopyToClipboard(BOOL bIncludeLink)
  123. {
  124.     ASSERT_VALID(this);
  125.     ASSERT(m_lpObject != NULL);
  126.  
  127.     // get clipboard data for this item
  128.     COleDataSource* pDataSource = OnGetClipboardData(bIncludeLink, NULL, NULL);
  129.     TRY
  130.     {
  131.         // put it on the clipboard
  132.         pDataSource->SetClipboard();
  133.     }
  134.     CATCH_ALL(e)
  135.     {
  136.         delete pDataSource;
  137.         THROW_LAST();
  138.     }
  139.     END_CATCH_ALL
  140. }
  141.  
  142. COleDataSource* COleClientItem::OnGetClipboardData(
  143.     BOOL bIncludeLink, LPPOINT lpOffset, LPSIZE lpSize)
  144. {
  145.     ASSERT_VALID(this);
  146.  
  147.     COleDataSource* pDataSource = new COleDataSource;
  148.     TRY
  149.     {
  150.         GetClipboardData(pDataSource, bIncludeLink, lpOffset, lpSize);
  151.     }
  152.     CATCH_ALL(e)
  153.     {
  154.         delete pDataSource;
  155.         THROW_LAST();
  156.     }
  157.     END_CATCH_ALL
  158.  
  159.     ASSERT_VALID(pDataSource);
  160.     return pDataSource;
  161. }
  162.  
  163.  
  164. DROPEFFECT COleClientItem::DoDragDrop(LPCRECT lpItemRect, CPoint ptOffset,
  165.     BOOL bIncludeLink, DWORD dwEffects, LPCRECT lpRectStartDrag)
  166. {
  167.     ASSERT(AfxIsValidAddress(lpItemRect, sizeof(RECT)));
  168.     ASSERT_VALID(this);
  169.     ASSERT(m_lpObject != NULL);
  170.  
  171.     DROPEFFECT dropEffect = DROPEFFECT_NONE;
  172.     COleDataSource *pDataSource = NULL;
  173.     TRY
  174.     {
  175.         // get clipboard data object for the item
  176.         CSize sizeItem(
  177.             lpItemRect->right - lpItemRect->left,
  178.             lpItemRect->bottom - lpItemRect->top);
  179.         pDataSource = OnGetClipboardData(bIncludeLink, &ptOffset, &sizeItem);
  180.  
  181.         // add DROPEFFECT_LINK only if link source is available
  182.         LPDATAOBJECT lpDataObject = (LPDATAOBJECT)
  183.             pDataSource->GetInterface(&IID_IDataObject);
  184.         ASSERT(lpDataObject != NULL);
  185.         FORMATETC formatEtc;
  186.         formatEtc.cfFormat = (CLIPFORMAT)_oleData.cfLinkSource;
  187.         formatEtc.ptd = NULL;
  188.         formatEtc.dwAspect = DVASPECT_CONTENT;
  189.         formatEtc.lindex = -1;
  190.         formatEtc.tymed = (DWORD) -1;
  191.         if (lpDataObject->QueryGetData(&formatEtc) == S_OK)
  192.             dwEffects |= DROPEFFECT_LINK;
  193.  
  194.         // calculate default sensitivity rectangle
  195.         CRect rectDrag;
  196.         if (lpRectStartDrag == NULL)
  197.         {
  198.             rectDrag.SetRect(lpItemRect->left, lpItemRect->bottom,
  199.                 lpItemRect->left, lpItemRect->bottom);
  200.             lpRectStartDrag = &rectDrag;
  201.         }
  202.  
  203.         // do drag drop operation
  204.         dropEffect = pDataSource->DoDragDrop(dwEffects, lpRectStartDrag);
  205.         pDataSource->InternalRelease();
  206.     }
  207.     CATCH_ALL(e)
  208.     {
  209.         if (pDataSource != NULL)
  210.             pDataSource->InternalRelease();
  211.  
  212.         THROW_LAST();
  213.     }
  214.     END_CATCH_ALL
  215.  
  216.     return dropEffect;
  217. }
  218.  
  219. void COleClientItem::GetClipboardData(COleDataSource* pDataSource,
  220.     BOOL bIncludeLink, LPPOINT lpOffset, LPSIZE lpSize)
  221. {
  222.     ASSERT_VALID(this);
  223.     ASSERT(m_lpObject != NULL);
  224.     ASSERT_VALID(pDataSource);
  225.  
  226.     // add CF_EMBEDDEDOBJECT by creating memory storage copy of the object
  227.     STGMEDIUM stgMedium;
  228.     GetEmbeddedItemData(&stgMedium);
  229.     pDataSource->CacheData((CLIPFORMAT)_oleData.cfEmbeddedObject, &stgMedium);
  230.  
  231.     // add CF_OBJECTDESCRIPTOR
  232.     GetObjectDescriptorData(lpOffset, lpSize, &stgMedium);
  233.     pDataSource->CacheData((CLIPFORMAT)_oleData.cfObjectDescriptor,
  234.         &stgMedium);
  235.  
  236.     // add any presentation entries in the object's cache
  237.     AddCachedData(pDataSource);
  238.  
  239.     // add CF_LINKSOURCE if supporting links to embeddings
  240.     if (bIncludeLink && GetLinkSourceData(&stgMedium))
  241.     {
  242.         pDataSource->CacheData((CLIPFORMAT)_oleData.cfLinkSource, &stgMedium);
  243.  
  244.         // add CF_LINKSOURCEDESCRIPTOR
  245.         GetObjectDescriptorData(lpOffset, lpSize, &stgMedium);
  246.         pDataSource->CacheData((CLIPFORMAT)_oleData.cfLinkSourceDescriptor,
  247.             &stgMedium);
  248.     }
  249. }
  250.  
  251. BOOL PASCAL COleClientItem::CanPaste()
  252. {
  253.     // it is faster and more reliable to use the Windows clipboard
  254.     //  APIs instead of OleQueryCreateFromData.
  255.     return IsClipboardFormatAvailable(_oleData.cfEmbedSource) ||
  256.         IsClipboardFormatAvailable(_oleData.cfEmbeddedObject) ||
  257.         IsClipboardFormatAvailable(_oleData.cfFileName) ||
  258.         IsClipboardFormatAvailable(_oleData.cfFileNameW) ||
  259.         IsClipboardFormatAvailable(CF_METAFILEPICT) ||
  260.         IsClipboardFormatAvailable(CF_DIB) ||
  261.         IsClipboardFormatAvailable(CF_BITMAP) ||
  262.         (IsClipboardFormatAvailable(_oleData.cfOwnerLink) &&
  263.             IsClipboardFormatAvailable(_oleData.cfNative));
  264. }
  265.  
  266. BOOL PASCAL COleClientItem::CanPasteLink()
  267. {
  268.     // it is faster and more reliable to use the Windows clipboard
  269.     //  APIs instead of OleQueryCreateFromData.
  270.     return IsClipboardFormatAvailable(_oleData.cfLinkSource) ||
  271.         IsClipboardFormatAvailable(_oleData.cfFileName) ||
  272.         IsClipboardFormatAvailable(_oleData.cfFileNameW) ||
  273.         IsClipboardFormatAvailable(_oleData.cfObjectLink);
  274. }
  275.  
  276. BOOL PASCAL
  277. COleClientItem::CanCreateFromData(const COleDataObject* pDataObject)
  278. {
  279.     if (pDataObject->m_bClipboard)
  280.         return COleClientItem::CanPaste();
  281.  
  282.     ((COleDataObject*)pDataObject)->EnsureClipboardObject();
  283.     if (pDataObject->m_lpDataObject == NULL)
  284.         return FALSE;
  285.  
  286.     SCODE sc = ::OleQueryCreateFromData(pDataObject->m_lpDataObject);
  287.     return !FAILED(sc) && sc != S_FALSE;
  288. }
  289.  
  290. BOOL PASCAL
  291. COleClientItem::CanCreateLinkFromData(const COleDataObject* pDataObject)
  292. {
  293.     if (pDataObject->m_bClipboard)
  294.         return COleClientItem::CanPasteLink();
  295.  
  296.     ((COleDataObject*)pDataObject)->EnsureClipboardObject();
  297.     if (pDataObject->m_lpDataObject == NULL)
  298.         return FALSE;
  299.  
  300.     SCODE sc = ::OleQueryLinkFromData(pDataObject->m_lpDataObject);
  301.     return !FAILED(sc) && sc != S_FALSE;
  302. }
  303.  
  304. /////////////////////////////////////////////////////////////////////////////
  305. // Conversion & Activate As support
  306.  
  307. BOOL COleClientItem::ConvertTo(REFCLSID clsidNew)
  308. {
  309.     ASSERT_VALID(this);
  310.     ASSERT(m_lpObject != NULL);
  311.  
  312.     // first, close the object
  313.     Close();
  314.  
  315.     // convert it
  316.     m_scLast = _AfxOleDoConvert(m_lpStorage, clsidNew);
  317.     if (FAILED(m_scLast))
  318.         return FALSE;
  319.  
  320.     // save IOleObject and IViewObject2 pointers
  321.     LPOLEOBJECT lpObject = m_lpObject;
  322.     LPVIEWOBJECT2 lpViewObject = m_lpViewObject;
  323.     DWORD dwConnection = m_dwConnection;
  324.  
  325.     // NULL out IOleObject and IViewObject2 cached pointers
  326.     m_lpObject = NULL;
  327.     m_lpViewObject = NULL;
  328.     m_dwConnection = 0;
  329.  
  330.     // then load the new object from the new storage
  331.     BOOL bResult = FinishCreate(::OleLoad(m_lpStorage, IID_IUnknown,
  332.         NULL, (LPLP)&m_lpObject));
  333.  
  334.     if (bResult)
  335.     {
  336.         RELEASE(lpObject);
  337.         RELEASE(lpViewObject);
  338.     }
  339.     else
  340.     {
  341.         m_lpObject = lpObject;
  342.         m_lpViewObject = lpViewObject;
  343.         m_dwConnection = dwConnection;
  344.         UpdateItemType();
  345.     }
  346.     ASSERT_VALID(this);
  347.  
  348.     return bResult;
  349. }
  350.  
  351. BOOL COleClientItem::Reload()
  352. {
  353.     // first, close the object
  354.     Close();
  355.  
  356.     // release any pointers we have to the object
  357.     RELEASE(m_lpObject);
  358.     RELEASE(m_lpViewObject);
  359.  
  360.     // then reload the object with OleLoad and finish creation process
  361.     BOOL bResult = FinishCreate(::OleLoad(m_lpStorage, IID_IUnknown,
  362.         NULL, (LPLP)&m_lpObject));
  363.  
  364.     ASSERT_VALID(this);
  365.     return bResult;
  366. }
  367.  
  368. BOOL COleClientItem::ActivateAs(LPCTSTR lpszUserType,
  369.     REFCLSID clsidOld, REFCLSID clsidNew)
  370. {
  371.     ASSERT_VALID(this);
  372.     ASSERT(lpszUserType == NULL || AfxIsValidString(lpszUserType));
  373.     ASSERT(m_lpObject != NULL);
  374.  
  375.     // enable activate as
  376.     m_scLast = _AfxOleDoTreatAsClass(lpszUserType, clsidOld, clsidNew);
  377.     if (FAILED(m_scLast))
  378.         return FALSE;
  379.  
  380.     // reload all items in this doucment
  381.     COleDocument* pDoc = GetDocument();
  382.     ASSERT_VALID(pDoc);
  383.     POSITION pos = pDoc->GetStartPosition();
  384.     COleClientItem* pItem;
  385.     while ((pItem = pDoc->GetNextClientItem(pos)) != NULL)
  386.     {
  387.         // reload it, so activate as works as appropriate
  388.         pItem->Reload();
  389.     }
  390.  
  391.     ASSERT_VALID(this);
  392.     return TRUE;
  393. }
  394.  
  395. /////////////////////////////////////////////////////////////////////////////
  396. // COleClientItem printing support
  397.  
  398. BOOL COleClientItem::SetPrintDevice(const DVTARGETDEVICE* ptd)
  399. {
  400.     ASSERT(ptd == NULL ||
  401.         AfxIsValidAddress(ptd, sizeof(DVTARGETDEVICE), FALSE));
  402.  
  403.     // get printer device information from cache
  404.     LPOLECACHE lpOleCache;
  405.     DVTARGETDEVICE* ptdCur = NULL;
  406.     DWORD dwConnection;
  407.     if (!GetPrintDeviceInfo(&lpOleCache, &ptdCur, &dwConnection))
  408.     {
  409.         lpOleCache = QUERYINTERFACE(m_lpObject, IOleCache);
  410.         if (lpOleCache == NULL)
  411.             return FALSE;   // no print device info available
  412.     }
  413.     ASSERT(lpOleCache != NULL);
  414.  
  415.     // both may have no target device (considered equal)
  416.     if (ptd == NULL && ptdCur == NULL)
  417.     {
  418.         lpOleCache->Release();
  419.         CoTaskMemFree(ptdCur);
  420.         return TRUE;
  421.     }
  422.  
  423.     if (ptd != NULL && ptdCur != NULL)
  424.     {
  425.         // should be non-NULL and valid addresses
  426.         ASSERT(AfxIsValidAddress(ptd, (size_t)ptd->tdSize));
  427.         ASSERT(AfxIsValidAddress(ptdCur, (size_t)ptdCur->tdSize));
  428.         // see if they compare equal
  429.         if (ptdCur->tdSize == ptd->tdSize &&
  430.             memcmp(ptdCur, ptd, (size_t)ptd->tdSize) == 0)
  431.         {
  432.             lpOleCache->Release();
  433.             CoTaskMemFree(ptdCur);
  434.             return TRUE;
  435.         }
  436.     }
  437.  
  438.     // calling this with NULL will just remove the prevous printer cache
  439.     if (ptd != NULL)
  440.     {
  441.         // new cache is for CF_METAFILEPICT, DVASPECT_CONTENT
  442.         FORMATETC formatEtc;
  443.         formatEtc.cfFormat = CF_METAFILEPICT;
  444.         formatEtc.ptd = (DVTARGETDEVICE*)ptd;
  445.         formatEtc.dwAspect = DVASPECT_CONTENT;
  446.         formatEtc.lindex = -1;
  447.         formatEtc.tymed = TYMED_MFPICT;
  448.  
  449.         // attempt to cache new format
  450.         DWORD dwNewConnection;
  451.         if (lpOleCache->Cache(&formatEtc, ADVFCACHE_ONSAVE,
  452.             &dwNewConnection) != S_OK)
  453.         {
  454.             lpOleCache->Release();
  455.             CoTaskMemFree(ptdCur);
  456.             return FALSE;
  457.         }
  458.     }
  459.     // new format is cached successfully, uncache old format
  460.     if (ptdCur != NULL)
  461.     {
  462.         lpOleCache->Uncache(dwConnection);
  463.         CoTaskMemFree(ptdCur);
  464.     }
  465.     // cleanup & return
  466.     lpOleCache->Release();
  467.     return TRUE;
  468. }
  469.  
  470. BOOL COleClientItem::SetPrintDevice(const PRINTDLG* ppd)
  471. {
  472.     ASSERT(ppd == NULL || AfxIsValidAddress(ppd, sizeof(*ppd), FALSE));
  473.     DVTARGETDEVICE* ptd = NULL;
  474.     if (ppd != NULL)
  475.         ptd = _AfxOleCreateTargetDevice((PRINTDLG*)ppd);
  476.  
  477.     BOOL bResult = SetPrintDevice(ptd);
  478.     CoTaskMemFree(ptd);
  479.     return bResult;
  480. }
  481.  
  482. /////////////////////////////////////////////////////////////////////////////
  483. // other advanced COleClientItem support
  484.  
  485. void COleClientItem::GetUserType(
  486.     USERCLASSTYPE nUserClassType, CString& rString)
  487. {
  488.     ASSERT_VALID(this);
  489.     ASSERT(m_lpObject != NULL);
  490.  
  491.     LPOLESTR lpszUserType;
  492.     CheckGeneral(m_lpObject->GetUserType(nUserClassType, &lpszUserType));
  493.     ASSERT(lpszUserType != NULL);
  494.     ASSERT(AfxIsValidString(lpszUserType));
  495.     rString = lpszUserType;
  496.     CoTaskMemFree(lpszUserType);
  497. }
  498.  
  499. void COleClientItem::Run()
  500. {
  501.     ASSERT_VALID(this);
  502.     ASSERT(m_lpObject != NULL);
  503.  
  504.     // is object already in running state?
  505.     if (::OleIsRunning(m_lpObject))
  506.         return;
  507.  
  508.     // run the object -- throw exception on errors
  509.     SCODE sc = ::OleRun(m_lpObject);
  510.     CheckGeneral(sc);
  511.  
  512.     // should be running now
  513.     ASSERT(::OleIsRunning(m_lpObject));
  514. }
  515.  
  516. /////////////////////////////////////////////////////////////////////////////
  517. // Linked COleClientItem operations
  518.  
  519. BOOL COleClientItem::UpdateLink()
  520. {
  521.     ASSERT_VALID(this);
  522.     ASSERT(m_lpObject != NULL);
  523.  
  524.     m_scLast = S_OK;
  525.     if (!IsLinkUpToDate())
  526.     {
  527.         m_scLast = m_lpObject->Update();
  528.         ASSERT_VALID(m_pDocument);
  529.         m_pDocument->SetModifiedFlag();
  530.     }
  531.     return m_scLast == S_OK;
  532. }
  533.  
  534. BOOL COleClientItem::FreezeLink()
  535. {
  536.     ASSERT_VALID(this);
  537.     ASSERT(m_lpObject != NULL);
  538.     ASSERT(m_pDocument != NULL);
  539.     ASSERT(GetType() == OT_LINK);
  540.  
  541.     // first save & close the item
  542.     Close();
  543.  
  544.     // get IDataObject interface
  545.     LPDATAOBJECT lpDataObject = QUERYINTERFACE(m_lpObject, IDataObject);
  546.     ASSERT(lpDataObject != NULL);
  547.     COleDataObject dataObject;
  548.     dataObject.Attach(lpDataObject, TRUE);
  549.  
  550.     // save important state of original item
  551.     LPOLEOBJECT lpObject = m_lpObject;
  552.     LPSTORAGE lpStorage = m_lpStorage;
  553.     LPLOCKBYTES lpLockBytes = m_lpLockBytes;
  554.     LPVIEWOBJECT2 lpViewObject = m_lpViewObject;
  555.     DWORD dwConnection = m_dwConnection;
  556.     DWORD dwItemNumber = m_dwItemNumber;
  557.     m_lpObject = NULL;
  558.     m_lpStorage = NULL;
  559.     m_lpLockBytes = NULL;
  560.     m_lpViewObject = NULL;
  561.     m_dwConnection = 0;
  562.  
  563.     // attempt to create new object from data
  564.     if (!CreateStaticFromData(&dataObject))
  565.     {
  566.         m_lpObject = lpObject;
  567.         m_lpStorage = lpStorage;
  568.         m_lpLockBytes = lpLockBytes;
  569.         m_lpViewObject = lpViewObject;
  570.         m_dwConnection = dwConnection;
  571.         return FALSE;
  572.     }
  573. #ifdef _DEBUG
  574.     UpdateItemType();
  575.     ASSERT(GetType() == OT_STATIC);
  576. #endif
  577.  
  578.     // save new state of that item
  579.     LPOLEOBJECT lpNewObject = m_lpObject;
  580.     LPSTORAGE lpNewStorage = m_lpStorage;
  581.     LPLOCKBYTES lpNewLockBytes = m_lpLockBytes;
  582.     LPVIEWOBJECT2 lpNewViewObject = m_lpViewObject;
  583.     DWORD dwNewConnection = m_dwConnection;
  584.     DWORD dwNewItemNumber = m_dwItemNumber;
  585.  
  586.     // shut down old item
  587.     m_lpObject = lpObject;
  588.     m_lpStorage = lpStorage;
  589.     m_lpLockBytes = lpLockBytes;
  590.     m_lpViewObject = lpViewObject;
  591.     m_dwConnection = dwConnection;
  592.     m_dwItemNumber = dwItemNumber;
  593. #ifdef _DEBUG
  594.     UpdateItemType();
  595.     ASSERT(GetType() == OT_LINK);
  596. #endif
  597.     Delete(FALSE);  // revokes item & removes storage
  598.  
  599.     // switch to new item
  600.     m_lpObject = lpNewObject;
  601.     m_lpStorage = lpNewStorage;
  602.     m_lpLockBytes = lpNewLockBytes;
  603.     m_lpViewObject = lpNewViewObject;
  604.     m_dwConnection = dwNewConnection;
  605.     m_dwItemNumber = dwNewItemNumber;
  606.     UpdateItemType();
  607.     ASSERT(GetType() == OT_STATIC);
  608.  
  609.     // send an on changed with same state to invalidate the item
  610.     OnChange(OLE_CHANGED_STATE, (DWORD)GetItemState());
  611.     ASSERT_VALID(m_pDocument);
  612.     m_pDocument->SetModifiedFlag();
  613.  
  614.     return TRUE;
  615. }
  616.  
  617. /////////////////////////////////////////////////////////////////////////////
  618. // Special link attributes
  619.  
  620. OLEUPDATE COleClientItem::GetLinkUpdateOptions()
  621. {
  622.     ASSERT_VALID(this);
  623.     ASSERT(m_lpObject != NULL);
  624.  
  625.     LPOLELINK lpOleLink = QUERYINTERFACE(m_lpObject, IOleLink);
  626.     ASSERT(lpOleLink != NULL);  // perhaps not a link?
  627.  
  628.     DWORD dwUpdateOpt;
  629.     SCODE sc = lpOleLink->GetUpdateOptions(&dwUpdateOpt);
  630.     lpOleLink->Release();
  631.     CheckGeneral(sc);   // may throw an exception
  632.  
  633.     return (OLEUPDATE)dwUpdateOpt;
  634. }
  635.  
  636. void COleClientItem::SetLinkUpdateOptions(OLEUPDATE dwUpdateOpt)
  637. {
  638.     ASSERT_VALID(this);
  639.     ASSERT(m_lpObject != NULL);
  640.  
  641.     LPOLELINK lpOleLink = QUERYINTERFACE(m_lpObject, IOleLink);
  642.     ASSERT(lpOleLink != NULL);  // perhaps not a link?
  643.  
  644.     SCODE sc = lpOleLink->SetUpdateOptions(dwUpdateOpt);
  645.     lpOleLink->Release();
  646.     CheckGeneral(sc);
  647. }
  648.  
  649. /////////////////////////////////////////////////////////////////////////////
  650.