home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / mfc / src / olesvr2.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-06-16  |  36.3 KB  |  1,453 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_OLE4_SEG
  14. #pragma code_seg(AFX_OLE4_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. // COleServerItem implementation
  26.  
  27. COleServerItem::COleServerItem(COleServerDoc* pServerDoc, BOOL bAutoDelete)
  28. {
  29.     if (pServerDoc != NULL)
  30.         ASSERT_VALID(pServerDoc);
  31.  
  32.     m_dwRef = 0;    // always start in disconnected state
  33.     m_bAutoDelete = bAutoDelete;
  34.     m_bNeedUnlock = FALSE;
  35.  
  36.     // initially, item does not have an extent
  37.     m_sizeExtent.cx = 0;
  38.     m_sizeExtent.cy = 0;
  39.  
  40.     // initialize advise holders
  41.     m_lpOleAdviseHolder = NULL;
  42.     m_lpDataAdviseHolder = NULL;
  43.  
  44.     // add presentation formats to the data source
  45.     m_dataSource.m_nGrowBy = 1;
  46.     FORMATETC formatEtc;
  47.     formatEtc.ptd = NULL;
  48.     formatEtc.dwAspect = DVASPECT_CONTENT;
  49.     formatEtc.lindex = -1;
  50.  
  51.     // by default, a COleServerItem supports CF_METAFILEPICT
  52.     formatEtc.cfFormat = CF_METAFILEPICT;
  53.     formatEtc.tymed = TYMED_MFPICT;
  54.     m_dataSource.DelayRenderData(0, &formatEtc);
  55.  
  56.     // add item to server document
  57.     m_pDocument = NULL;
  58.     if (pServerDoc != NULL)
  59.         pServerDoc->AddItem(this);
  60.     ASSERT(m_pDocument == pServerDoc);
  61.  
  62.     AfxOleLockApp();
  63. }
  64.  
  65. COleServerItem::~COleServerItem()
  66. {
  67.     m_bAutoDelete = FALSE;  // no delete during destructor
  68.  
  69.     // release any advise holders
  70.     RELEASE(m_lpOleAdviseHolder);
  71.     RELEASE(m_lpDataAdviseHolder);
  72.  
  73.     ExternalDisconnect();
  74.  
  75.     // disconnect from the document
  76.     COleServerDoc* pDoc = GetDocument();
  77.     if (pDoc != NULL)
  78.     {
  79.         // remove external lock from it
  80.         if (m_bNeedUnlock)
  81.         {
  82.             pDoc->LockExternal(FALSE, TRUE);
  83.             m_bNeedUnlock = FALSE;
  84.         }
  85.  
  86.         // reset m_pEmbeddedItem if destroying embedded item
  87.         if (pDoc->m_pEmbeddedItem == this)
  88.             pDoc->m_pEmbeddedItem = NULL;
  89.  
  90.         // remove from list
  91.         pDoc->RemoveItem(this);
  92.     }
  93.  
  94.     // cleanup any references
  95.     AfxOleUnlockApp();
  96. }
  97.  
  98. BOOL COleServerItem::IsBlank() const
  99. {
  100.     // server items are blank in order to keep them from serializing when
  101.     //  COleDocument::Serialize is called.
  102.  
  103.     return TRUE;
  104. }
  105.  
  106. BOOL COleServerItem::IsConnected() const
  107. {
  108.     // if item is connected in any way, return TRUE
  109.     if (m_dwRef != 0)
  110.         return TRUE;
  111.  
  112.     // otherwise check if embedded item and document is connected
  113.     if (!IsLinkedItem() && GetDocument()->m_lpClientSite != NULL)
  114.         return TRUE;
  115.  
  116.     return FALSE;   // not connected
  117. }
  118.  
  119. void COleServerItem::NotifyClient(OLE_NOTIFICATION nCode, DWORD dwParam)
  120. {
  121.     switch (nCode)
  122.     {
  123.     // IDataObject notifications
  124.     case OLE_CHANGED:
  125.         if (m_lpDataAdviseHolder != NULL)
  126.             m_lpDataAdviseHolder->SendOnDataChange(GetDataObject(), dwParam, 0);
  127.         break;
  128.  
  129.     // IOleObject notifications
  130.     case OLE_SAVED:
  131.         if (m_lpOleAdviseHolder != NULL)
  132.             m_lpOleAdviseHolder->SendOnSave();
  133.         break;
  134.     case OLE_CLOSED:
  135.         if (m_lpOleAdviseHolder != NULL)
  136.             m_lpOleAdviseHolder->SendOnClose();
  137.         break;
  138.     case OLE_RENAMED:
  139.         if (m_lpOleAdviseHolder != NULL)
  140.         {
  141.             // Note: the moniker should already be updated for this to work
  142.             LPMONIKER lpMoniker = (LPMONIKER)dwParam;
  143.             m_lpOleAdviseHolder->SendOnRename(lpMoniker);
  144.         }
  145.         break;
  146.  
  147.     default:
  148.         ASSERT(FALSE);
  149.     }
  150. }
  151.  
  152. /////////////////////////////////////////////////////////////////////////////
  153. // Helpers for getting commonly used interfaces through interface map
  154.  
  155. LPDATAOBJECT COleServerItem::GetDataObject()
  156. {
  157.     LPDATAOBJECT lpDataObject =
  158.         (LPDATAOBJECT)GetInterface(&IID_IDataObject);
  159.     ASSERT(lpDataObject != NULL);
  160.     return lpDataObject;
  161. }
  162.  
  163. LPOLEOBJECT COleServerItem::GetOleObject()
  164. {
  165.     LPOLEOBJECT lpOleObject =
  166.         (LPOLEOBJECT)GetInterface(&IID_IOleObject);
  167.     ASSERT(lpOleObject != NULL);
  168.     return lpOleObject;
  169. }
  170.  
  171. /////////////////////////////////////////////////////////////////////////////
  172. // COleServerItem overrides
  173.  
  174. BOOL COleServerItem::OnQueryUpdateItems()
  175. {
  176.     COleDocument* pDoc = GetDocument();
  177.     ASSERT_VALID(pDoc);
  178.  
  179.     // update all of the embedded objects
  180.     POSITION pos = pDoc->GetStartPosition();
  181.     COleClientItem* pItem;
  182.     while ((pItem = pDoc->GetNextClientItem(pos)) != NULL)
  183.     {
  184.         // if any item is out-of-date, then this item is out-of-date
  185.         if (pItem->m_lpObject->IsUpToDate() != NULL)
  186.             return TRUE;    // update needed
  187.     }
  188.     return FALSE;   // update not needed
  189. }
  190.  
  191. void COleServerItem::OnUpdateItems()
  192. {
  193.     COleDocument* pDoc = GetDocument();
  194.     ASSERT_VALID(pDoc);
  195.  
  196.     // update all of the embedded objects
  197.     POSITION pos = pDoc->GetStartPosition();
  198.     COleClientItem* pItem;
  199.     while ((pItem = pDoc->GetNextClientItem(pos)) != NULL)
  200.     {
  201.         // update any out-of-date item
  202.         if (pItem->m_lpObject->IsUpToDate() != NULL)
  203.             pItem->m_lpObject->Update();
  204.     }
  205. }
  206.  
  207. BOOL COleServerItem::OnSetExtent(DVASPECT dwDrawAspect, const CSize& size)
  208. {
  209.     ASSERT_VALID(this);
  210.  
  211.     if (dwDrawAspect == DVASPECT_CONTENT)
  212.     {
  213.         m_sizeExtent = size;    // simply remember the extent
  214.         return TRUE;
  215.     }
  216.     return FALSE;   // not implemented for that dwDrawAspect
  217. }
  218.  
  219. BOOL COleServerItem::OnGetExtent(DVASPECT /*dwDrawAspect*/, CSize& rSize)
  220. {
  221.     ASSERT_VALID(this);
  222.     ASSERT(AfxIsValidAddress(&rSize, sizeof(CSize)));
  223.  
  224.     // the default implementation doesn't know what the extent is
  225.  
  226.     rSize.cx = 0;
  227.     rSize.cy = 0;
  228.  
  229.     return FALSE;
  230. }
  231.  
  232. void COleServerItem::OnDoVerb(LONG iVerb)
  233. {
  234.     switch (iVerb)
  235.     {
  236.     // open - maps to OnOpen
  237.     case OLEIVERB_OPEN:
  238.     case -OLEIVERB_OPEN-1:  // allows positive OLEIVERB_OPEN-1 in registry
  239.         OnOpen();
  240.         break;
  241.  
  242.     // primary, show, and unknown map to OnShow
  243.     case OLEIVERB_PRIMARY:  // OLEIVERB_PRIMARY is 0 and "Edit" in registry
  244.     case OLEIVERB_SHOW:
  245.         OnShow();
  246.         break;
  247.  
  248.     // hide maps to OnHide
  249.     case OLEIVERB_HIDE:
  250.     case -OLEIVERB_HIDE-1:  // allows positive OLEIVERB_HIDE-1 in registry
  251.         OnHide();
  252.         break;
  253.  
  254.     default:
  255.         // negative verbs not understood should return E_NOTIMPL
  256.         if (iVerb < 0)
  257.             AfxThrowOleException(E_NOTIMPL);
  258.  
  259.         // positive verb not processed --
  260.         //  according to OLE spec, primary verb should be executed
  261.         //  instead.
  262.         OnDoVerb(OLEIVERB_PRIMARY);
  263.  
  264.         // also, OLEOBJ_S_INVALIDVERB should be returned.
  265.         AfxThrowOleException(OLEOBJ_S_INVALIDVERB);
  266.     }
  267. }
  268.  
  269. BOOL COleServerItem::OnDrawEx(CDC* pDC, DVASPECT nDrawAspect, CSize& rSize)
  270. {
  271.     ASSERT_VALID(pDC);
  272.     ASSERT(AfxIsValidAddress(&rSize, sizeof(CSize)));
  273.  
  274.     if (nDrawAspect != DVASPECT_CONTENT)
  275.         return FALSE;
  276.  
  277.     return OnDraw(pDC, rSize);
  278. }
  279.  
  280. void COleServerItem::OnShow()
  281. {
  282.     ASSERT_VALID(this);
  283.  
  284.     // attempt in place activation (if not supported, fall back on "Open")
  285.     COleServerDoc* pDoc = GetDocument();
  286.     if (!pDoc->ActivateInPlace())
  287.     {
  288.         // by default OnShow() maps to OnOpen() if in-place activation
  289.         //  not supported
  290.         OnOpen();
  291.     }
  292. }
  293.  
  294. void COleServerItem::OnOpen()
  295. {
  296.     ASSERT_VALID(this);
  297.  
  298.     // default implementation shows the document
  299.     COleServerDoc* pDoc = GetDocument();
  300.     ASSERT(pDoc != NULL);
  301.     pDoc->OnShowDocument(TRUE);
  302. }
  303.  
  304. void COleServerItem::OnHide()
  305. {
  306.     ASSERT_VALID(this);
  307.  
  308.     // default implementation hides the document
  309.     COleServerDoc* pDoc = GetDocument();
  310.     ASSERT_VALID(pDoc);
  311.     pDoc->OnShowDocument(FALSE);
  312. }
  313.  
  314. BOOL COleServerItem::GetMetafileData(LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium)
  315. {
  316.     ASSERT_VALID(this);
  317.     ASSERT(AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
  318.     ASSERT(AfxIsValidAddress(lpStgMedium, sizeof(STGMEDIUM)));
  319.     ASSERT(lpStgMedium->tymed == TYMED_NULL);   // GetDataHere not valid
  320.     ASSERT(lpStgMedium->pUnkForRelease == NULL);
  321.  
  322.     // medium must be TYMED_MFPICT -- cannot fill in existing HGLOBAL
  323.     if (!(lpFormatEtc->tymed & TYMED_MFPICT) || lpStgMedium->hGlobal != NULL)
  324.         return FALSE;
  325.  
  326.     // create appropriate memory metafile DC
  327.     CMetaFileDC dc;
  328.     if (!dc.Create())
  329.         return FALSE;
  330.  
  331.     // create attribute DC according to lpFormatEtc->ptd
  332.     HDC hAttribDC = _AfxOleCreateDC(lpFormatEtc->ptd);
  333.     if (hAttribDC == NULL)
  334.         return FALSE;
  335.     dc.SetAttribDC(hAttribDC);
  336.  
  337.     // Paint directly into the metafile.
  338.     CSize size(0, 0);
  339.     BOOL bResult = OnDrawEx(&dc, (DVASPECT)lpFormatEtc->dwAspect, size);
  340.  
  341.     // attribute DC is no longer necessary
  342.     dc.SetAttribDC(NULL);
  343.     ::DeleteDC(hAttribDC);
  344.  
  345.     if (!bResult)
  346.     {
  347. #ifdef _DEBUG
  348.         if (afxTraceFlags & traceOle)
  349.             TRACE0("calling COleServerItem::OnDrawEx()failed.\n");
  350. #endif
  351.         return FALSE;
  352.     }
  353.  
  354.     HMETAFILE hMF = dc.Close();
  355.     if (hMF == NULL)
  356.         return FALSE;
  357.  
  358.     HGLOBAL hPict;
  359.     if ((hPict =
  360.         ::GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, sizeof(METAFILEPICT))) == NULL)
  361.     {
  362.         DeleteMetaFile(hMF);
  363.         return FALSE;
  364.     }
  365.     LPMETAFILEPICT lpPict;
  366.     if ((lpPict = (LPMETAFILEPICT)::GlobalLock(hPict)) == NULL)
  367.     {
  368.         DeleteMetaFile(hMF);
  369.         ::GlobalFree(hPict);
  370.         return FALSE;
  371.     }
  372.  
  373.     // set the metafile size
  374.     lpPict->mm = MM_ANISOTROPIC;
  375.     lpPict->hMF = hMF;
  376.     if (size.cx == 0 && size.cy == 0 &&
  377.         !OnGetExtent((DVASPECT)lpFormatEtc->dwAspect, size))
  378.     {
  379.         TRACE0("Warning: OnGetExtent failed during OnDrawEx --\n");
  380.         TRACE0("\tpresentation metafile may be badly formed!\n");
  381.     }
  382.     lpPict->xExt = size.cx;
  383.     lpPict->yExt = size.cy;  // HIMETRIC height
  384.     if (lpPict->yExt < 0)
  385.     {
  386.         TRACE0("Warning: HIMETRIC natural size is negative.\n");
  387.         lpPict->yExt = -lpPict->yExt;   // backward compatibility fix
  388.     }
  389.  
  390. #ifdef _DEBUG
  391.     if (lpPict->xExt == 0 || lpPict->yExt == 0)
  392.     {
  393.         // usually the natural extent is set to something interesting
  394.         TRACE0("Warning: COleServerItem has no natural size --\n");
  395.         TRACE0("\twill not work with some apps like MS Write.\n");
  396.     }
  397. #endif
  398.  
  399.     // return the medium with the hGlobal to the METAFILEPICT
  400.     ::GlobalUnlock(hPict);
  401.     lpStgMedium->hGlobal = hPict;
  402.     lpStgMedium->tymed = TYMED_MFPICT;
  403.     return TRUE;
  404. }
  405.  
  406. BOOL COleServerItem::OnSetColorScheme(const LOGPALETTE* /*lpLogPalette*/)
  407. {
  408.     ASSERT_VALID(this);
  409.  
  410.     return FALSE;   // default does nothing
  411. }
  412.  
  413. BOOL COleServerItem::OnInitFromData(
  414.     COleDataObject* /*pDataObject*/, BOOL /*bCreation*/)
  415. {
  416.     ASSERT_VALID(this);
  417.  
  418.     AfxThrowOleException(E_NOTIMPL);
  419.     return FALSE;
  420. }
  421.  
  422. void COleServerItem::CopyToClipboard(BOOL bIncludeLink)
  423. {
  424.     ASSERT_VALID(this);
  425.  
  426.     COleDataSource* pDataSource = OnGetClipboardData(bIncludeLink, NULL, NULL);
  427.  
  428.     // put it on the clipboard
  429.     pDataSource->SetClipboard();
  430. }
  431.  
  432. COleDataSource* COleServerItem::OnGetClipboardData(BOOL bIncludeLink,
  433.     LPPOINT lpOffset, LPSIZE lpSize)
  434. {
  435.     ASSERT_VALID(this);
  436.  
  437.     COleDataSource* pDataSource = new COleDataSource;
  438.     TRY
  439.     {
  440.         GetClipboardData(pDataSource, bIncludeLink, lpOffset, lpSize);
  441.     }
  442.     CATCH_ALL(e)
  443.     {
  444.         delete pDataSource;
  445.         THROW_LAST();
  446.     }
  447.     END_CATCH_ALL
  448.  
  449.     ASSERT_VALID(pDataSource);
  450.     return pDataSource;
  451. }
  452.  
  453. DROPEFFECT COleServerItem::DoDragDrop(LPCRECT lpItemRect, CPoint ptOffset,
  454.     BOOL bIncludeLink, DWORD dwEffects, LPCRECT lpRectStartDrag)
  455. {
  456.     ASSERT(AfxIsValidAddress(lpItemRect, sizeof(RECT)));
  457.     ASSERT_VALID(this);
  458.  
  459.     ASSERT_VALID(this);
  460.  
  461.     DROPEFFECT dropEffect = DROPEFFECT_NONE;
  462.     COleDataSource *pDataSource = NULL;
  463.     TRY
  464.     {
  465.         // get clipboard data for this item
  466.         CSize sizeItem(
  467.             lpItemRect->right - lpItemRect->left,
  468.             lpItemRect->bottom - lpItemRect->top);
  469.         pDataSource = OnGetClipboardData(bIncludeLink, &ptOffset, &sizeItem);
  470.  
  471.         // add DROPEFFECT_LINK if link source is available
  472.         LPDATAOBJECT lpDataObject = (LPDATAOBJECT)
  473.             pDataSource->GetInterface(&IID_IDataObject);
  474.         ASSERT(lpDataObject != NULL);
  475.         FORMATETC formatEtc;
  476.         formatEtc.cfFormat = (CLIPFORMAT)_oleData.cfLinkSource;
  477.         formatEtc.ptd = NULL;
  478.         formatEtc.dwAspect = DVASPECT_CONTENT;
  479.         formatEtc.lindex = -1;
  480.         formatEtc.tymed = (DWORD) -1;
  481.         if (lpDataObject->QueryGetData(&formatEtc) == S_OK)
  482.             dwEffects |= DROPEFFECT_LINK;
  483.  
  484.         // calculate default sensitivity rectangle
  485.         CRect rectDrag;
  486.         if (lpRectStartDrag == NULL)
  487.         {
  488.             rectDrag.SetRect(lpItemRect->left, lpItemRect->top, lpItemRect->left,
  489.                 lpItemRect->top);
  490.             lpRectStartDrag = &rectDrag;
  491.         }
  492.  
  493.         // do drag drop operation
  494.         dropEffect = pDataSource->DoDragDrop(dwEffects, lpRectStartDrag);
  495.         pDataSource->InternalRelease();
  496.     }
  497.     CATCH_ALL(e)
  498.     {
  499.         if (pDataSource != NULL)
  500.             pDataSource->InternalRelease();
  501.  
  502.         THROW_LAST();
  503.     }
  504.     END_CATCH_ALL
  505.  
  506.     return dropEffect;
  507. }
  508.  
  509. void COleServerItem::GetClipboardData(COleDataSource* pDataSource,
  510.     BOOL bIncludeLink, LPPOINT lpOffset, LPSIZE lpSize)
  511. {
  512.     ASSERT_VALID(this);
  513.     ASSERT_VALID(pDataSource);
  514.     ASSERT(lpOffset == NULL ||
  515.         AfxIsValidAddress(lpOffset, sizeof(POINT), FALSE));
  516.  
  517.     // add CF_EMBEDDEDOBJECT by creating memory storage copy of the object
  518.     STGMEDIUM stgMedium;
  519.     GetEmbedSourceData(&stgMedium);
  520.     pDataSource->CacheData((CLIPFORMAT)_oleData.cfEmbedSource, &stgMedium);
  521.  
  522.     // add CF_OBJECTDESCRIPTOR
  523.     GetObjectDescriptorData(lpOffset, lpSize, &stgMedium);
  524.     pDataSource->CacheData((CLIPFORMAT)_oleData.cfObjectDescriptor,
  525.         &stgMedium);
  526.  
  527.     // add any presentation entries/conversion formats that the item
  528.     //  can produce.
  529.     AddOtherClipboardData(pDataSource);
  530.  
  531.     // add CF_LINKSOURCE if supporting links to pseudo objects
  532.     if (bIncludeLink && GetLinkSourceData(&stgMedium))
  533.     {
  534.         pDataSource->CacheData((CLIPFORMAT)_oleData.cfLinkSource, &stgMedium);
  535.  
  536.         // add CF_LINKSOURCEDESCRIPTOR
  537.         GetObjectDescriptorData(lpOffset, lpSize, &stgMedium);
  538.         pDataSource->CacheData((CLIPFORMAT)_oleData.cfLinkSourceDescriptor,
  539.             &stgMedium);
  540.     }
  541. }
  542.  
  543. void COleServerItem::GetEmbedSourceData(LPSTGMEDIUM lpStgMedium)
  544. {
  545.     ASSERT_VALID(this);
  546.     ASSERT(AfxIsValidAddress(lpStgMedium, sizeof(STGMEDIUM)));
  547.  
  548.     LPLOCKBYTES lpLockBytes;
  549.     SCODE sc = ::CreateILockBytesOnHGlobal(NULL, TRUE, &lpLockBytes);
  550.     if (sc != S_OK)
  551.         AfxThrowOleException(sc);
  552.     ASSERT(lpLockBytes != NULL);
  553.  
  554.     LPSTORAGE lpStorage;
  555.     sc = ::StgCreateDocfileOnILockBytes(lpLockBytes,
  556.         STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0, &lpStorage);
  557.     if (sc != S_OK)
  558.     {
  559.         VERIFY(lpLockBytes->Release() == 0);
  560.         AfxThrowOleException(sc);
  561.     }
  562.     ASSERT(lpStorage != NULL);
  563.  
  564.     // setup for save copy as
  565.     COleServerDoc* pDoc = GetDocument();
  566.     pDoc->m_bSameAsLoad = FALSE;
  567.     pDoc->m_bRemember = FALSE;
  568.  
  569.     TRY
  570.     {
  571.         OnSaveEmbedding(lpStorage);
  572.         pDoc->CommitItems(FALSE);
  573.     }
  574.     CATCH_ALL(e)
  575.     {
  576.         // release storage and lock bytes
  577.         VERIFY(lpStorage->Release() == 0);
  578.         VERIFY(lpLockBytes->Release() == 0);
  579.         pDoc->m_bSameAsLoad = TRUE;
  580.         pDoc->m_bRemember = TRUE;
  581.         THROW_LAST();
  582.     }
  583.     END_CATCH_ALL
  584.  
  585.     pDoc->m_bSameAsLoad = TRUE;
  586.     pDoc->m_bRemember = TRUE;
  587.     lpLockBytes->Release();
  588.  
  589.     // add it to the data source
  590.     lpStgMedium->tymed = TYMED_ISTORAGE;
  591.     lpStgMedium->pstg = lpStorage;
  592.     lpStgMedium->pUnkForRelease = NULL;
  593. }
  594.  
  595. void COleServerItem::AddOtherClipboardData(COleDataSource* pDataSource)
  596. {
  597.     ASSERT_VALID(this);
  598.     ASSERT_VALID(pDataSource);
  599.  
  600.     // get IEnumFORMATETC interface for the IDataObject
  601.     LPDATAOBJECT lpDataObject = GetDataObject();
  602.     LPENUMFORMATETC lpEnumFORMATETC;
  603.     if (lpDataObject->EnumFormatEtc(DATADIR_GET, &lpEnumFORMATETC) != S_OK)
  604.         return;
  605.     ASSERT(lpEnumFORMATETC != NULL);
  606.  
  607.     // get all formats that the object will give us
  608.     FORMATETC formatEtc;
  609.     while (lpEnumFORMATETC->Next(1, &formatEtc, NULL) == S_OK)
  610.     {
  611.         STGMEDIUM stgMedium;
  612.         if (lpDataObject->GetData(&formatEtc, &stgMedium) != S_OK)
  613.         {
  614.             // data is not available
  615.             CoTaskMemFree(formatEtc.ptd);
  616.         }
  617.         else if (stgMedium.pUnkForRelease != NULL)
  618.         {
  619.             // don't cache data with pUnkForRelease != NULL
  620.             ::ReleaseStgMedium(&stgMedium);
  621.             CoTaskMemFree(formatEtc.ptd);
  622.         }
  623.         else
  624.         {
  625.             // cache the data (now we own the stgMedium)
  626.             pDataSource->CacheData(0, &stgMedium, &formatEtc);
  627.         }
  628.     }
  629.  
  630.     // cleanup
  631.     lpEnumFORMATETC->Release();
  632. }
  633.  
  634. LPMONIKER COleServerItem::GetMoniker(OLEGETMONIKER nAssign)
  635. {
  636.     // get IOleObject interface for this item
  637.     LPOLEOBJECT lpOleObject = GetOleObject();
  638.     ASSERT(lpOleObject != NULL);
  639.  
  640.     // get moniker from OLE object
  641.     LPMONIKER lpMoniker = NULL;
  642.     lpOleObject->GetMoniker(nAssign, OLEWHICHMK_OBJFULL, &lpMoniker);
  643.     return lpMoniker;
  644. }
  645.  
  646. BOOL COleServerItem::GetLinkSourceData(LPSTGMEDIUM lpStgMedium)
  647. {
  648.     ASSERT_VALID(this);
  649.     ASSERT(AfxIsValidAddress(lpStgMedium, sizeof(STGMEDIUM)));
  650.  
  651.     LPOLEOBJECT lpOleObject = GetOleObject();
  652.     ASSERT(lpOleObject != NULL);
  653.  
  654.     // get moniker from ole object
  655.     LPMONIKER lpMoniker;
  656.     SCODE sc = lpOleObject->GetMoniker(OLEGETMONIKER_TEMPFORUSER,
  657.         OLEWHICHMK_OBJFULL, &lpMoniker);
  658.     if (sc != S_OK)
  659.     {
  660.         TRACE0("Warning: unable to get moniker for object.\n");
  661.         return FALSE;
  662.     }
  663.     ASSERT(lpMoniker != NULL);
  664.  
  665.     // create a memory based stream to write the moniker to
  666.     LPSTREAM lpStream;
  667.     if (::CreateStreamOnHGlobal(NULL, TRUE, &lpStream) != S_OK)
  668.     {
  669.         lpMoniker->Release();
  670.         AfxThrowMemoryException();
  671.     }
  672.     ASSERT(lpStream != NULL);
  673.  
  674.     // write the moniker to the stream, and add it to the clipboard
  675.     sc = ::OleSaveToStream(lpMoniker, lpStream);
  676.     lpMoniker->Release();
  677.     if (sc != S_OK)
  678.     {
  679.         lpStream->Release();
  680.         AfxThrowOleException(sc);
  681.     }
  682.  
  683.     // write the class ID of the document to the stream as well
  684.     COleLinkingDoc* pDoc = GetDocument();
  685.     ASSERT(pDoc->m_pFactory != NULL);
  686.     sc = WriteClassStm(lpStream, pDoc->m_pFactory->GetClassID());
  687.     if (sc != S_OK)
  688.     {
  689.         lpStream->Release();
  690.         AfxThrowOleException(sc);
  691.     }
  692.  
  693.     // setup the STGMEDIUM
  694.     lpStgMedium->tymed = TYMED_ISTREAM;
  695.     lpStgMedium->pstm = lpStream;
  696.     lpStgMedium->pUnkForRelease = NULL;
  697.     return TRUE;
  698. }
  699.  
  700. void COleServerItem::GetObjectDescriptorData(
  701.     LPPOINT lpOffset, LPSIZE lpSize, LPSTGMEDIUM lpStgMedium)
  702. {
  703.     ASSERT_VALID(this);
  704.     ASSERT(AfxIsValidAddress(lpStgMedium, sizeof(STGMEDIUM)));
  705.     ASSERT(lpOffset == NULL ||
  706.         AfxIsValidAddress(lpOffset, sizeof(POINT), FALSE));
  707.  
  708.     LPOLEOBJECT lpOleObject = GetOleObject();
  709.     ASSERT(lpOleObject != NULL);
  710.  
  711.     // get the object descriptor for the IOleObject
  712.     POINTL pointl = { 0, 0 };
  713.     if (lpOffset != NULL)
  714.     {
  715.         CSize ptOffset(lpOffset->x, lpOffset->y);
  716.         ((CDC*)NULL)->DPtoHIMETRIC(&ptOffset);
  717.         pointl.x = ptOffset.cx;
  718.         pointl.y = ptOffset.cy;
  719.     }
  720.     SIZEL sizel;
  721.     if (lpSize != NULL)
  722.     {
  723.         sizel.cx = lpSize->cx;
  724.         sizel.cy = lpSize->cy;
  725.         ((CDC*)NULL)->DPtoHIMETRIC(&sizel);
  726.     }
  727.     else
  728.     {
  729.         sizel.cx = 0;
  730.         sizel.cy = 0;
  731.     }
  732.  
  733.     InterlockedIncrement(&m_dwRef);  // protect against destruction during this call
  734.     HGLOBAL hGlobal = _AfxOleGetObjectDescriptorData(
  735.         lpOleObject, NULL, DVASPECT_CONTENT, pointl, &sizel);
  736.     InterlockedDecrement(&m_dwRef);
  737.  
  738.     if (hGlobal == NULL)
  739.         AfxThrowMemoryException();
  740.  
  741.     // setup the STGMEDIUM
  742.     lpStgMedium->tymed = TYMED_HGLOBAL;
  743.     lpStgMedium->hGlobal = hGlobal;
  744.     lpStgMedium->pUnkForRelease = NULL;
  745. }
  746.  
  747. void COleServerItem::OnSaveEmbedding(LPSTORAGE lpStorage)
  748. {
  749.     ASSERT(lpStorage != NULL);
  750.  
  751.     // always (logically) a "File.Save Copy As" operation
  752.     COleServerDoc* pDoc = GetDocument();
  753.     LPSTORAGE lpOrigStg = pDoc->m_lpRootStg;
  754.     pDoc->m_lpRootStg = lpStorage;
  755.  
  756.     TRY
  757.     {
  758.         ASSERT(pDoc->m_lpRootStg != NULL);
  759.         pDoc->SaveToStorage(this);  // use helper to serialize to storage
  760.     }
  761.     CATCH_ALL(e)
  762.     {
  763.         // save as failed: re-attach original storage
  764.         pDoc->m_lpRootStg = lpOrigStg;
  765.         THROW_LAST();
  766.     }
  767.     END_CATCH_ALL
  768.  
  769.     // re-attach original storage
  770.     pDoc->m_lpRootStg = lpOrigStg;
  771. }
  772.  
  773. /////////////////////////////////////////////////////////////////////////////
  774. // COleServerItem data-object callback default implementation
  775.  
  776. BOOL COleServerItem::OnRenderGlobalData(
  777.     LPFORMATETC /*lpFormatEtc*/, HGLOBAL* /*phGlobal*/)
  778. {
  779.     ASSERT_VALID(this);
  780.  
  781.     return FALSE;   // default does nothing
  782. }
  783.  
  784. BOOL COleServerItem::OnRenderFileData(
  785.     LPFORMATETC /*lpFormatEtc*/, CFile* /*pFile*/)
  786. {
  787.     ASSERT_VALID(this);
  788.  
  789.     return FALSE;   // default does nothing
  790. }
  791.  
  792. BOOL COleServerItem::OnRenderData(LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium)
  793. {
  794.     ASSERT_VALID(this);
  795.     ASSERT(AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
  796.     ASSERT(AfxIsValidAddress(lpStgMedium, sizeof(STGMEDIUM)));
  797.  
  798.     // default implementation does not support extended layout
  799.     if (lpFormatEtc->lindex != -1)
  800.         return FALSE;
  801.  
  802.     // default implementation supports both types of metafiles
  803.     if (lpFormatEtc->cfFormat == CF_METAFILEPICT)
  804.         return GetMetafileData(lpFormatEtc, lpStgMedium);
  805.  
  806.     return FALSE;   // cfFormat not supported
  807. }
  808.  
  809. BOOL COleServerItem::OnSetData(
  810.     LPFORMATETC /*lpFormatEtc*/, LPSTGMEDIUM /*lpStgMedium*/, BOOL /*bRelease*/)
  811. {
  812.     ASSERT_VALID(this);
  813.  
  814.     return FALSE;   // default does nothing
  815. }
  816.  
  817. /////////////////////////////////////////////////////////////////////////////
  818. // COleServerItem OLE interface implementation
  819.  
  820. BEGIN_INTERFACE_MAP(COleServerItem, CDocItem)
  821.     INTERFACE_PART(COleServerItem, IID_IOleObject, OleObject)
  822.     INTERFACE_PART(COleServerItem, IID_IDataObject, DataObject)
  823. END_INTERFACE_MAP()
  824.  
  825. /////////////////////////////////////////////////////////////////////////////
  826. // COleServerItem::XOleObject
  827.  
  828. STDMETHODIMP_(ULONG) COleServerItem::XOleObject::AddRef()
  829. {
  830.     METHOD_PROLOGUE_EX_(COleServerItem, OleObject)
  831.     return pThis->ExternalAddRef();
  832. }
  833.  
  834. STDMETHODIMP_(ULONG) COleServerItem::XOleObject::Release()
  835. {
  836.     METHOD_PROLOGUE_EX_(COleServerItem, OleObject)
  837.     return pThis->ExternalRelease();
  838. }
  839.  
  840. STDMETHODIMP COleServerItem::XOleObject::QueryInterface(
  841.     REFIID iid, LPVOID* ppvObj)
  842. {
  843.     METHOD_PROLOGUE_EX_(COleServerItem, OleObject)
  844.     return pThis->ExternalQueryInterface(&iid, ppvObj);
  845. }
  846.  
  847. // COleServerItem has special Release semantics.  In particular, the item
  848. //  is only deleted from memory if m_bAutoDelete is TRUE.
  849. //  Also, it unlocks the document if the reference count reaches zero.
  850.  
  851. void COleServerItem::OnFinalRelease()
  852. {
  853.     ASSERT_VALID(this);
  854.  
  855.     COleServerDoc* pDoc = GetDocument();
  856.     ASSERT_VALID(pDoc);
  857.  
  858.     pDoc->InternalAddRef(); // make document stable
  859.  
  860.     // if connected to a document -- remove external lock from it
  861.     if (m_bNeedUnlock)
  862.     {
  863.         pDoc->LockExternal(FALSE, TRUE);
  864.         m_bNeedUnlock = FALSE;
  865.     }
  866.  
  867.     // delete this item if no longer needed
  868.     if (m_bAutoDelete)
  869.         delete this;
  870.  
  871.     // release artificial reference (may destroy the document)
  872.     pDoc->InternalRelease();
  873. }
  874.  
  875. STDMETHODIMP COleServerItem::XOleObject::SetClientSite(
  876.     LPOLECLIENTSITE /*pClientSite*/)
  877. {
  878.     // linked objects do not support SetClientSite
  879.  
  880.     return E_NOTIMPL;
  881. }
  882.  
  883. STDMETHODIMP COleServerItem::XOleObject::GetClientSite(
  884.     LPOLECLIENTSITE* ppClientSite)
  885. {
  886.     // linked objects do not support GetClientSite
  887.  
  888.     *ppClientSite = NULL;
  889.     return E_NOTIMPL;
  890. }
  891.  
  892. STDMETHODIMP COleServerItem::XOleObject::SetHostNames(
  893.     LPCOLESTR /*szContainerApp*/, LPCOLESTR /*szContainerObj*/)
  894. {
  895.     // linked objects do not support SetHostNames
  896.  
  897.     return E_NOTIMPL;
  898. }
  899.  
  900. STDMETHODIMP COleServerItem::XOleObject::Close(DWORD /*dwSaveOption*/)
  901. {
  902.     // linked objects do not support close
  903.  
  904.     return E_NOTIMPL;
  905. }
  906.  
  907. STDMETHODIMP COleServerItem::XOleObject::SetMoniker(
  908.     DWORD /*dwWhichMoniker*/, LPMONIKER /*pmk*/)
  909. {
  910.     // linked objects do not support SetMoniker
  911.  
  912.     return E_NOTIMPL;
  913. }
  914.  
  915. STDMETHODIMP COleServerItem::XOleObject::GetMoniker(
  916.     DWORD dwAssign, DWORD dwWhichMoniker, LPMONIKER* ppMoniker)
  917. {
  918.     USES_CONVERSION;
  919.  
  920.     METHOD_PROLOGUE_EX(COleServerItem, OleObject)
  921.     ASSERT_VALID(pThis);
  922.  
  923.     COleServerDoc* pDoc = pThis->GetDocument();
  924.     ASSERT_VALID(pDoc);
  925.     ASSERT_KINDOF(COleServerDoc, pDoc);
  926.     ASSERT(ppMoniker != NULL);
  927.     *ppMoniker = NULL;
  928.  
  929.     switch (dwWhichMoniker)
  930.     {
  931.     case OLEWHICHMK_CONTAINER:
  932.         // simply return the moniker of the container document
  933.         *ppMoniker = pDoc->GetMoniker((OLEGETMONIKER)dwAssign);
  934.         break;
  935.  
  936.     case OLEWHICHMK_OBJREL:
  937.         {
  938.             // no relative moniker if no item name
  939.             if (pThis->m_strItemName.IsEmpty())
  940.                 break;
  941.  
  942.             // don't return relative moniker if no document moniker
  943.             LPMONIKER lpMoniker = pDoc->GetMoniker((OLEGETMONIKER)dwAssign);
  944.             if (lpMoniker == NULL)
  945.                 break;
  946.             lpMoniker->Release();   // don't need document moniker
  947.  
  948.             // relative monikers have to handle assignment correctly
  949.             switch (dwAssign)
  950.             {
  951.             case OLEGETMONIKER_TEMPFORUSER:
  952.             case OLEGETMONIKER_ONLYIFTHERE:
  953.             case OLEGETMONIKER_FORCEASSIGN:
  954.                 // create item moniker from name
  955.                 CreateItemMoniker(OLESTDDELIMOLE, T2COLE(pThis->m_strItemName),
  956.                     ppMoniker);
  957.                 break;
  958.  
  959.             case OLEGETMONIKER_UNASSIGN:
  960.                 ASSERT(FALSE);  // should never get UNASSIGN
  961.                 break;
  962.             }
  963.         }
  964.         break;
  965.  
  966.     case OLEWHICHMK_OBJFULL:
  967.         {
  968.             // get each sub-moniker: item & document
  969.             LPMONIKER lpMoniker1, lpMoniker2;
  970.             GetMoniker(dwAssign, OLEWHICHMK_CONTAINER, &lpMoniker1);
  971.             GetMoniker(dwAssign, OLEWHICHMK_OBJREL, &lpMoniker2);
  972.  
  973.             if (lpMoniker1 != NULL && lpMoniker2 != NULL)
  974.             {
  975.                 // create composite from two parts
  976.                 ::CreateGenericComposite(lpMoniker1, lpMoniker2, ppMoniker);
  977.             }
  978.             else if (lpMoniker1 != NULL)
  979.             {
  980.                 // just use container moniker
  981.                 *ppMoniker = lpMoniker1;
  982.                 lpMoniker1 = NULL;
  983.             }
  984.  
  985.             // release sub-monikers
  986.             RELEASE(lpMoniker1);
  987.             RELEASE(lpMoniker2);
  988.         }
  989.         break;
  990.     }
  991.  
  992.     return *ppMoniker == NULL ? E_FAIL : S_OK;
  993. }
  994.  
  995. STDMETHODIMP COleServerItem::XOleObject::InitFromData(
  996.     LPDATAOBJECT /*pDataObject*/, BOOL /*fCreation*/, DWORD /*dwReserved*/)
  997. {
  998.     // linked objects do not support InitFromData
  999.  
  1000.     return E_NOTIMPL;
  1001. }
  1002.  
  1003. STDMETHODIMP COleServerItem::XOleObject::GetClipboardData(
  1004.     DWORD /*dwReserved*/, LPDATAOBJECT* ppDataObject)
  1005. {
  1006.     METHOD_PROLOGUE_EX(COleServerItem, OleObject)
  1007.     ASSERT_VALID(pThis);
  1008.  
  1009.     *ppDataObject = NULL;
  1010.  
  1011.     SCODE sc;
  1012.     TRY
  1013.     {
  1014.         COleDataSource* pDataSource = pThis->OnGetClipboardData(TRUE, NULL, NULL);
  1015.         ASSERT(pDataSource != NULL);
  1016.  
  1017.         *ppDataObject =
  1018.             (LPDATAOBJECT)pDataSource->GetInterface(&IID_IDataObject);
  1019.         ASSERT(*ppDataObject != NULL);
  1020.         sc = S_OK;
  1021.     }
  1022.     CATCH_ALL(e)
  1023.     {
  1024.         sc = COleException::Process(e);
  1025.         DELETE_EXCEPTION(e);
  1026.     }
  1027.     END_CATCH_ALL
  1028.  
  1029.     return sc;
  1030. }
  1031.  
  1032. STDMETHODIMP COleServerItem::XOleObject::DoVerb(
  1033.     LONG iVerb, LPMSG /*lpmsg*/, LPOLECLIENTSITE /*pActiveSite*/, LONG /*lindex*/,
  1034.     HWND /*hwndParent*/, LPCRECT /*lpPosRect*/)
  1035. {
  1036.     METHOD_PROLOGUE_EX(COleServerItem, OleObject)
  1037.     ASSERT_VALID(pThis);
  1038.  
  1039.     pThis->InternalAddRef();    // protect this object
  1040.  
  1041.     SCODE sc;
  1042.     TRY
  1043.     {
  1044.         pThis->OnDoVerb(iVerb);
  1045.         sc = S_OK;
  1046.     }
  1047.     CATCH_ALL(e)
  1048.     {
  1049.         sc = COleException::Process(e);
  1050.         DELETE_EXCEPTION(e);
  1051.     }
  1052.     END_CATCH_ALL
  1053.  
  1054.     pThis->InternalRelease();   // may 'delete this'
  1055.  
  1056.     return sc;
  1057. }
  1058.  
  1059. STDMETHODIMP COleServerItem::XOleObject::EnumVerbs(
  1060.     IEnumOLEVERB** ppenumOleVerb)
  1061. {
  1062.     METHOD_PROLOGUE_EX_(COleServerItem, OleObject)
  1063.  
  1064.     *ppenumOleVerb = NULL;
  1065.  
  1066.     CLSID clsid;
  1067.     pThis->GetOleObject()->GetUserClassID(&clsid);
  1068.     return OleRegEnumVerbs(clsid, ppenumOleVerb);
  1069. }
  1070.  
  1071. STDMETHODIMP COleServerItem::XOleObject::Update()
  1072. {
  1073.     METHOD_PROLOGUE_EX(COleServerItem, OleObject)
  1074.     ASSERT_VALID(pThis);
  1075.  
  1076.     SCODE sc;
  1077.     TRY
  1078.     {
  1079.         pThis->OnUpdateItems();
  1080.         sc = S_OK;
  1081.     }
  1082.     CATCH_ALL(e)
  1083.     {
  1084.         sc = COleException::Process(e);
  1085.         DELETE_EXCEPTION(e);
  1086.     }
  1087.     END_CATCH_ALL
  1088.  
  1089.     return sc;
  1090. }
  1091.  
  1092. STDMETHODIMP COleServerItem::XOleObject::IsUpToDate()
  1093. {
  1094.     METHOD_PROLOGUE_EX(COleServerItem, OleObject)
  1095.     ASSERT_VALID(pThis);
  1096.  
  1097.     SCODE sc;
  1098.     TRY
  1099.     {
  1100.         sc = pThis->OnQueryUpdateItems() ? S_FALSE : S_OK;
  1101.     }
  1102.     CATCH_ALL(e)
  1103.     {
  1104.         sc = COleException::Process(e);
  1105.         DELETE_EXCEPTION(e);
  1106.     }
  1107.     END_CATCH_ALL
  1108.  
  1109.     return sc;
  1110. }
  1111.  
  1112. STDMETHODIMP COleServerItem::XOleObject::GetUserClassID(CLSID* pClsid)
  1113. {
  1114.     METHOD_PROLOGUE_EX_(COleServerItem, OleObject)
  1115.  
  1116.     COleServerDoc* pDoc = pThis->GetDocument();
  1117.     return pDoc->m_xPersistFile.GetClassID(pClsid);
  1118. }
  1119.  
  1120. STDMETHODIMP COleServerItem::XOleObject::GetUserType(
  1121.     DWORD dwFormOfType, LPOLESTR* ppszUserType)
  1122. {
  1123.     METHOD_PROLOGUE_EX_(COleServerItem, OleObject)
  1124.  
  1125.     *ppszUserType = NULL;
  1126.  
  1127.     CLSID clsid;
  1128.     pThis->GetOleObject()->GetUserClassID(&clsid);
  1129.     return OleRegGetUserType(clsid, dwFormOfType, ppszUserType);
  1130. }
  1131.  
  1132. STDMETHODIMP COleServerItem::XOleObject::SetExtent(
  1133.     DWORD /*dwDrawAspect*/, LPSIZEL /*lpsizel*/)
  1134. {
  1135.     // linked objects do not support SetExtent
  1136.  
  1137.     return E_FAIL;
  1138. }
  1139.  
  1140. STDMETHODIMP COleServerItem::XOleObject::GetExtent(
  1141.     DWORD dwDrawAspect, LPSIZEL lpsizel)
  1142. {
  1143.     METHOD_PROLOGUE_EX(COleServerItem, OleObject)
  1144.     ASSERT_VALID(pThis);
  1145.  
  1146.     SCODE sc = E_INVALIDARG;
  1147.     TRY
  1148.     {
  1149.         // call to get regular windows size
  1150.         CSize size;
  1151.         if (pThis->OnGetExtent((DVASPECT)dwDrawAspect, size))
  1152.         {
  1153.             if (size.cy < 0)
  1154.                 size.cy = -size.cy; // extents are always positive
  1155.             lpsizel->cx = size.cx;
  1156.             lpsizel->cy = size.cy;
  1157.  
  1158.             sc = S_OK;
  1159.         }
  1160.     }
  1161.     CATCH_ALL(e)
  1162.     {
  1163.         sc = COleException::Process(e);
  1164.         DELETE_EXCEPTION(e);
  1165.     }
  1166.     END_CATCH_ALL
  1167.  
  1168.     return sc;
  1169. }
  1170.  
  1171. STDMETHODIMP COleServerItem::XOleObject::Advise(
  1172.     IAdviseSink* pAdvSink, DWORD* pdwConnection)
  1173. {
  1174.     METHOD_PROLOGUE_EX_(COleServerItem, OleObject)
  1175.  
  1176.     *pdwConnection = 0;
  1177.  
  1178.     if (pThis->m_lpOleAdviseHolder == NULL &&
  1179.         ::CreateOleAdviseHolder(&pThis->m_lpOleAdviseHolder) != S_OK)
  1180.     {
  1181.         return E_OUTOFMEMORY;
  1182.     }
  1183.     ASSERT(pThis->m_lpOleAdviseHolder != NULL);
  1184.     return pThis->m_lpOleAdviseHolder->Advise(pAdvSink, pdwConnection);
  1185. }
  1186.  
  1187. STDMETHODIMP COleServerItem::XOleObject::Unadvise(DWORD dwConnection)
  1188. {
  1189.     METHOD_PROLOGUE_EX_(COleServerItem, OleObject)
  1190.  
  1191.     if (pThis->m_lpOleAdviseHolder == NULL)
  1192.         return E_FAIL;
  1193.  
  1194.     ASSERT(pThis->m_lpOleAdviseHolder != NULL);
  1195.     return pThis->m_lpOleAdviseHolder->Unadvise(dwConnection);
  1196. }
  1197.  
  1198. STDMETHODIMP COleServerItem::XOleObject::EnumAdvise(
  1199.     LPENUMSTATDATA* ppenumAdvise)
  1200. {
  1201.     METHOD_PROLOGUE_EX_(COleServerItem, OleObject)
  1202.  
  1203.     *ppenumAdvise = NULL;
  1204.  
  1205.     if (pThis->m_lpOleAdviseHolder == NULL)
  1206.         return E_FAIL;
  1207.  
  1208.     ASSERT(pThis->m_lpOleAdviseHolder != NULL);
  1209.     return pThis->m_lpOleAdviseHolder->EnumAdvise(ppenumAdvise);
  1210. }
  1211.  
  1212. STDMETHODIMP COleServerItem::XOleObject::GetMiscStatus(
  1213.     DWORD dwAspect, DWORD* pdwStatus)
  1214. {
  1215.     METHOD_PROLOGUE_EX_(COleServerItem, OleObject)
  1216.  
  1217.     *pdwStatus = 0;
  1218.  
  1219.     CLSID clsid;
  1220.     pThis->GetOleObject()->GetUserClassID(&clsid);
  1221.     return OleRegGetMiscStatus(clsid, dwAspect, pdwStatus);
  1222. }
  1223.  
  1224. STDMETHODIMP COleServerItem::XOleObject::SetColorScheme(LPLOGPALETTE lpLogpal)
  1225. {
  1226.     METHOD_PROLOGUE_EX(COleServerItem, OleObject)
  1227.     ASSERT_VALID(pThis);
  1228.  
  1229.     SCODE sc = E_NOTIMPL;
  1230.     TRY
  1231.     {
  1232.         // delegate to embedded item
  1233.         if (pThis->OnSetColorScheme(lpLogpal))
  1234.             sc = S_OK;
  1235.     }
  1236.     END_TRY
  1237.  
  1238.     return sc;
  1239. }
  1240.  
  1241. /////////////////////////////////////////////////////////////////////////////
  1242. // COleServerItem::XDataObject
  1243.  
  1244. STDMETHODIMP_(ULONG) COleServerItem::XDataObject::AddRef()
  1245. {
  1246.     METHOD_PROLOGUE_EX_(COleServerItem, DataObject)
  1247.     return pThis->ExternalAddRef();
  1248. }
  1249.  
  1250. STDMETHODIMP_(ULONG) COleServerItem::XDataObject::Release()
  1251. {
  1252.     METHOD_PROLOGUE_EX_(COleServerItem, DataObject)
  1253.     return pThis->ExternalRelease();
  1254. }
  1255.  
  1256. STDMETHODIMP COleServerItem::XDataObject::QueryInterface(
  1257.     REFIID iid, LPVOID* ppvObj)
  1258. {
  1259.     METHOD_PROLOGUE_EX_(COleServerItem, DataObject)
  1260.     return pThis->ExternalQueryInterface(&iid, ppvObj);
  1261. }
  1262.  
  1263. STDMETHODIMP COleServerItem::XDataObject::GetData(
  1264.     LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium)
  1265. {
  1266.     METHOD_PROLOGUE_EX_(COleServerItem, DataObject)
  1267.  
  1268.     return pThis->m_dataSource.m_xDataObject.GetData(lpFormatEtc, lpStgMedium);
  1269. }
  1270.  
  1271. STDMETHODIMP COleServerItem::XDataObject::GetDataHere(
  1272.     LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium)
  1273. {
  1274.     METHOD_PROLOGUE_EX_(COleServerItem, DataObject)
  1275.  
  1276.     return pThis->m_dataSource.m_xDataObject.GetDataHere(
  1277.         lpFormatEtc, lpStgMedium);
  1278. }
  1279.  
  1280. STDMETHODIMP COleServerItem::XDataObject::QueryGetData(LPFORMATETC lpFormatEtc)
  1281. {
  1282.     METHOD_PROLOGUE_EX_(COleServerItem, DataObject)
  1283.  
  1284.     return pThis->m_dataSource.m_xDataObject.QueryGetData(lpFormatEtc);
  1285. }
  1286.  
  1287. STDMETHODIMP COleServerItem::XDataObject::GetCanonicalFormatEtc(
  1288.     LPFORMATETC /*lpFormatEtcIn*/, LPFORMATETC /*lpFormatEtcOut*/)
  1289. {
  1290.     // because we support the target-device (ptd) for server metafile format,
  1291.     //  all members of the FORMATETC are significant.
  1292.  
  1293.     return DATA_S_SAMEFORMATETC;
  1294. }
  1295.  
  1296. STDMETHODIMP COleServerItem::XDataObject::SetData(
  1297.     LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium, BOOL bRelease)
  1298. {
  1299.     METHOD_PROLOGUE_EX_(COleServerItem, DataObject)
  1300.  
  1301.     return pThis->m_dataSource.m_xDataObject.SetData(
  1302.         lpFormatEtc, lpStgMedium, bRelease);
  1303. }
  1304.  
  1305. STDMETHODIMP COleServerItem::XDataObject::EnumFormatEtc(
  1306.     DWORD dwDirection, LPENUMFORMATETC* ppenumFormatEtc)
  1307. {
  1308.     METHOD_PROLOGUE_EX_(COleServerItem, DataObject)
  1309.  
  1310.     return pThis->m_dataSource.m_xDataObject.EnumFormatEtc(
  1311.         dwDirection, ppenumFormatEtc);
  1312. }
  1313.  
  1314. STDMETHODIMP COleServerItem::XDataObject::DAdvise(
  1315.     FORMATETC* pFormatEtc, DWORD advf,
  1316.     LPADVISESINK pAdvSink, DWORD* pdwConnection)
  1317. {
  1318.     METHOD_PROLOGUE_EX_(COleServerItem, DataObject)
  1319.  
  1320.     *pdwConnection = 0;
  1321.  
  1322.     // this special case is for apps like Excel which ask for DAdvise
  1323.     // on CF_METAFILEPICT, DVASPECT_ICON for insert as icon.
  1324.     FORMATETC formatEtc = *pFormatEtc;
  1325.     if (formatEtc.cfFormat == CF_METAFILEPICT &&
  1326.         formatEtc.dwAspect == DVASPECT_ICON)
  1327.     {
  1328.         formatEtc.dwAspect = DVASPECT_CONTENT;
  1329.     }
  1330.  
  1331.     // make sure the FORMATETC is valid
  1332.     if (!(pFormatEtc->cfFormat == 0 && pFormatEtc->ptd == NULL &&
  1333.           pFormatEtc->dwAspect == -1 && pFormatEtc->lindex == -1 &&
  1334.           pFormatEtc->tymed == -1) &&
  1335.         pThis->GetDataObject()->QueryGetData(&formatEtc) != S_OK)
  1336.     {
  1337.         // it is not a wildcard advise -and- the format is not acceptable
  1338.         return DATA_E_FORMATETC;
  1339.     }
  1340.  
  1341.     // create the advise holder, if necessary
  1342.     if (pThis->m_lpDataAdviseHolder == NULL &&
  1343.         CreateDataAdviseHolder(&pThis->m_lpDataAdviseHolder) != S_OK)
  1344.     {
  1345.         return E_OUTOFMEMORY;
  1346.     }
  1347.     ASSERT(pThis->m_lpDataAdviseHolder != NULL);
  1348.     return pThis->m_lpDataAdviseHolder->Advise(this, pFormatEtc, advf,
  1349.         pAdvSink, pdwConnection);
  1350. }
  1351.  
  1352. STDMETHODIMP COleServerItem::XDataObject::DUnadvise(DWORD dwConnection)
  1353. {
  1354.     METHOD_PROLOGUE_EX_(COleServerItem, DataObject)
  1355.  
  1356.     if (pThis->m_lpDataAdviseHolder == NULL)
  1357.         return E_FAIL;
  1358.  
  1359.     ASSERT(pThis->m_lpDataAdviseHolder != NULL);
  1360.     return pThis->m_lpDataAdviseHolder->Unadvise(dwConnection);
  1361. }
  1362.  
  1363. STDMETHODIMP COleServerItem::XDataObject::EnumDAdvise(
  1364.     LPENUMSTATDATA* ppenumAdvise)
  1365. {
  1366.     METHOD_PROLOGUE_EX_(COleServerItem, DataObject)
  1367.  
  1368.     *ppenumAdvise = NULL;
  1369.  
  1370.     if (pThis->m_lpDataAdviseHolder == NULL)
  1371.         return E_FAIL;
  1372.  
  1373.     ASSERT(pThis->m_lpDataAdviseHolder != NULL);
  1374.     return pThis->m_lpDataAdviseHolder->EnumAdvise(ppenumAdvise);
  1375. }
  1376.  
  1377. //////////////////////////////////////////////////////////////////////////////
  1378. // special CItemDataSource implementation
  1379.  
  1380. BOOL COleServerItem::CItemDataSource::OnRenderGlobalData(
  1381.     LPFORMATETC lpFormatEtc, HGLOBAL* phGlobal)
  1382. {
  1383.     ASSERT_VALID(this);
  1384.     COleServerItem* pItem = (COleServerItem*)
  1385.         ((BYTE*)this - offsetof(COleServerItem, m_dataSource));
  1386.  
  1387.     return pItem->OnRenderGlobalData(lpFormatEtc, phGlobal);
  1388.         // Note: COleDataSource has no implementation
  1389. }
  1390.  
  1391. BOOL COleServerItem::CItemDataSource::OnRenderFileData(
  1392.     LPFORMATETC lpFormatEtc, CFile* pFile)
  1393. {
  1394.     ASSERT_VALID(this);
  1395.     COleServerItem* pItem = (COleServerItem*)
  1396.         ((BYTE*)this - offsetof(COleServerItem, m_dataSource));
  1397.  
  1398.     return pItem->OnRenderFileData(lpFormatEtc, pFile);
  1399.         // Note: COleDataSource has no implementation
  1400. }
  1401.  
  1402. BOOL COleServerItem::CItemDataSource::OnRenderData(
  1403.     LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium)
  1404. {
  1405.     ASSERT_VALID(this);
  1406.     COleServerItem* pItem = (COleServerItem*)
  1407.         ((BYTE*)this - offsetof(COleServerItem, m_dataSource));
  1408.  
  1409.     if (pItem->OnRenderData(lpFormatEtc, lpStgMedium))
  1410.         return TRUE;
  1411.  
  1412.     return COleDataSource::OnRenderData(lpFormatEtc, lpStgMedium);
  1413. }
  1414.  
  1415. BOOL COleServerItem::CItemDataSource::OnSetData(
  1416.     LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium, BOOL bRelease)
  1417. {
  1418.     ASSERT_VALID(this);
  1419.     COleServerItem* pItem = (COleServerItem*)
  1420.         ((BYTE*)this - offsetof(COleServerItem, m_dataSource));
  1421.  
  1422.     return pItem->OnSetData(lpFormatEtc, lpStgMedium, bRelease);
  1423.         // Note: COleDataSource has no implementation
  1424. }
  1425.  
  1426. //////////////////////////////////////////////////////////////////////////////
  1427. // COleServerItem Diagnostics
  1428.  
  1429. #ifdef _DEBUG
  1430. void COleServerItem::AssertValid() const
  1431. {
  1432.     CDocItem::AssertValid();
  1433.  
  1434.     // must be attached to a document
  1435.     ASSERT(m_pDocument != NULL);
  1436.     m_dataSource.AssertValid();
  1437. }
  1438.  
  1439. void COleServerItem::Dump(CDumpContext& dc) const
  1440. {
  1441.     CDocItem::Dump(dc);
  1442.  
  1443.     dc << "m_bNeedUnlock = " << m_bNeedUnlock;
  1444.     dc << "\nm_bAutoDelete = " << m_bAutoDelete;
  1445.     dc << "\nm_strItemName = " << m_strItemName;
  1446.     dc << "\nm_lpOleAdviseHolder = " << m_lpOleAdviseHolder;
  1447.     dc << "\nm_lpDataAdviseHolder = " << m_lpDataAdviseHolder;
  1448.     dc << "\nwith m_dataSource: " << &m_dataSource;
  1449. }
  1450. #endif
  1451.  
  1452. /////////////////////////////////////////////////////////////////////////////
  1453.