home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / mfc / src / oledobj2.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-06-16  |  21.0 KB  |  760 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_OLE3_SEG
  14. #pragma code_seg(AFX_OLE3_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. // COleDataSource implementation
  26.  
  27. struct AFX_DATACACHE_ENTRY
  28. {
  29.     FORMATETC m_formatEtc;
  30.     STGMEDIUM m_stgMedium;
  31.     DATADIR m_nDataDir;
  32. };
  33.  
  34. /////////////////////////////////////////////////////////////////////////////
  35. // COleDataSource construction & destruction
  36.  
  37. COleDataSource::COleDataSource()
  38. {
  39.     m_pDataCache = NULL;
  40.     m_nMaxSize = 0;
  41.     m_nSize = 0;
  42.     m_nGrowBy = 10;
  43. }
  44.  
  45. COleDataSource::~COleDataSource()
  46. {
  47.     // clear clipboard source if this object was on the clipboard
  48.     _AFX_OLE_STATE* pOleState = _afxOleState;
  49.     if (this == pOleState->m_pClipboardSource)
  50.         pOleState->m_pClipboardSource = NULL;
  51.  
  52.     // free the clipboard data cache
  53.     Empty();
  54. }
  55.  
  56. void COleDataSource::Empty()
  57. {
  58.     if (m_pDataCache != NULL)
  59.     {
  60.         ASSERT(m_nMaxSize != 0);
  61.         ASSERT(m_nSize != 0);
  62.  
  63.         // release all of the STGMEDIUMs and FORMATETCs
  64.         for (UINT nIndex = 0; nIndex < m_nSize; nIndex++)
  65.         {
  66.             CoTaskMemFree(m_pDataCache[nIndex].m_formatEtc.ptd);
  67.             ::ReleaseStgMedium(&m_pDataCache[nIndex].m_stgMedium);
  68.         }
  69.  
  70.         // delete the cache
  71.         delete[] m_pDataCache;
  72.         m_pDataCache = NULL;
  73.         m_nMaxSize = 0;
  74.         m_nSize = 0;
  75.     }
  76.     ASSERT(m_pDataCache == NULL);
  77.     ASSERT(m_nMaxSize == 0);
  78.     ASSERT(m_nSize == 0);
  79. }
  80.  
  81. /////////////////////////////////////////////////////////////////////////////
  82. // COleDataSource clipboard API wrappers
  83.  
  84. void COleDataSource::SetClipboard()
  85. {
  86.     ASSERT_VALID(this);
  87.  
  88.     // attempt OLE set clipboard operation
  89.     LPDATAOBJECT lpDataObject = (LPDATAOBJECT)GetInterface(&IID_IDataObject);
  90.     SCODE sc = ::OleSetClipboard(lpDataObject);
  91.     if (sc != S_OK)
  92.         AfxThrowOleException(sc);
  93.  
  94.     // success - set as current clipboard source
  95.     _afxOleState->m_pClipboardSource = this;
  96.     ASSERT(::OleIsCurrentClipboard(lpDataObject) == S_OK);
  97.     InternalRelease();
  98. }
  99.  
  100. void PASCAL COleDataSource::FlushClipboard()
  101. {
  102.     if (GetClipboardOwner() != NULL)
  103.     {
  104.         // active clipboard source and it is on the clipboard - flush it
  105.         ::OleFlushClipboard();
  106.  
  107.         // shouldn't be clipboard owner any more...
  108.         ASSERT(GetClipboardOwner() == NULL);
  109.     }
  110. }
  111.  
  112. COleDataSource* PASCAL COleDataSource::GetClipboardOwner()
  113. {
  114.     _AFX_OLE_STATE* pOleState = _afxOleState;
  115.     if (pOleState->m_pClipboardSource == NULL)
  116.         return NULL;    // can't own the clipboard if pClipboardSource isn't set
  117.  
  118.     ASSERT_VALID(pOleState->m_pClipboardSource);
  119.     LPDATAOBJECT lpDataObject = (LPDATAOBJECT)
  120.         pOleState->m_pClipboardSource->GetInterface(&IID_IDataObject);
  121.     if (::OleIsCurrentClipboard(lpDataObject) != S_OK)
  122.     {
  123.         pOleState->m_pClipboardSource = NULL;
  124.         return NULL;    // don't own the clipboard anymore
  125.     }
  126.  
  127.     // return current clipboard source
  128.     return pOleState->m_pClipboardSource;
  129. }
  130.  
  131. /////////////////////////////////////////////////////////////////////////////
  132. // COleDataSource cache allocation
  133.  
  134. AFX_DATACACHE_ENTRY* COleDataSource::GetCacheEntry(
  135.     LPFORMATETC lpFormatEtc, DATADIR nDataDir)
  136. {
  137.     AFX_DATACACHE_ENTRY* pEntry = Lookup(lpFormatEtc, nDataDir);
  138.     if (pEntry != NULL)
  139.     {
  140.         // cleanup current entry and return it
  141.         CoTaskMemFree(pEntry->m_formatEtc.ptd);
  142.         ::ReleaseStgMedium(&pEntry->m_stgMedium);
  143.     }
  144.     else
  145.     {
  146.         // allocate space for item at m_nSize (at least room for 1 item)
  147.         if (m_pDataCache == NULL || m_nSize == m_nMaxSize)
  148.         {
  149.             ASSERT(m_nGrowBy != 0);
  150.             AFX_DATACACHE_ENTRY* pCache = new AFX_DATACACHE_ENTRY[m_nMaxSize+m_nGrowBy];
  151.             m_nMaxSize += m_nGrowBy;
  152.             if (m_pDataCache != NULL)
  153.             {
  154.                 memcpy(pCache, m_pDataCache, m_nSize * sizeof(AFX_DATACACHE_ENTRY));
  155.                 delete[] m_pDataCache;
  156.             }
  157.             m_pDataCache = pCache;
  158.         }
  159.         ASSERT(m_pDataCache != NULL);
  160.         ASSERT(m_nMaxSize != 0);
  161.  
  162.         pEntry = &m_pDataCache[m_nSize++];
  163.     }
  164.  
  165.     // fill the cache entry with the format and data direction and return it
  166.     pEntry->m_nDataDir = nDataDir;
  167.     pEntry->m_formatEtc = *lpFormatEtc;
  168.     return pEntry;
  169. }
  170.  
  171. /////////////////////////////////////////////////////////////////////////////
  172. // COleDataSource operations
  173.  
  174. // for HGLOBAL based cached render
  175. void COleDataSource::CacheGlobalData(CLIPFORMAT cfFormat, HGLOBAL hGlobal,
  176.     LPFORMATETC lpFormatEtc)
  177. {
  178.     ASSERT(hGlobal != NULL);
  179.     ASSERT(lpFormatEtc == NULL ||
  180.         AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
  181.  
  182.     // fill in FORMATETC struct
  183.     FORMATETC formatEtc;
  184.     lpFormatEtc = _AfxFillFormatEtc(lpFormatEtc, cfFormat, &formatEtc);
  185.     lpFormatEtc->tymed = TYMED_HGLOBAL;
  186.  
  187.     // add it to the cache
  188.     AFX_DATACACHE_ENTRY* pEntry = GetCacheEntry(lpFormatEtc, DATADIR_GET);
  189.     pEntry->m_stgMedium.tymed = TYMED_HGLOBAL;
  190.     pEntry->m_stgMedium.hGlobal = hGlobal;
  191.     pEntry->m_stgMedium.pUnkForRelease = NULL;
  192. }
  193.  
  194. // for raw LPSTGMEDIUM cached render
  195. void COleDataSource::CacheData(CLIPFORMAT cfFormat, LPSTGMEDIUM lpStgMedium,
  196.     LPFORMATETC lpFormatEtc)
  197. {
  198.     ASSERT(lpStgMedium == NULL || lpStgMedium->tymed != TYMED_NULL);
  199.     ASSERT(AfxIsValidAddress(lpStgMedium, sizeof(STGMEDIUM), FALSE));
  200.     ASSERT(lpFormatEtc == NULL ||
  201.         AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
  202.  
  203.     // fill in FORMATETC struct
  204.     FORMATETC formatEtc;
  205.     lpFormatEtc = _AfxFillFormatEtc(lpFormatEtc, cfFormat, &formatEtc);
  206.  
  207.     // Only these TYMED_GDI formats can be copied, so can't serve as
  208.     //  cache content (you must use DelayRenderData instead)
  209.     // When using COleServerItem::CopyToClipboard this means providing an
  210.     //  override of COleServerItem::OnGetClipboardData to provide a custom
  211.     //  delayed rendering clipboard object.
  212.     ASSERT(lpStgMedium->tymed != TYMED_GDI ||
  213.         lpFormatEtc->cfFormat == CF_METAFILEPICT ||
  214.         lpFormatEtc->cfFormat == CF_PALETTE ||
  215.         lpFormatEtc->cfFormat == CF_BITMAP);
  216.     lpFormatEtc->tymed = lpStgMedium->tymed;
  217.  
  218.     // add it to the cache
  219.     AFX_DATACACHE_ENTRY* pEntry = GetCacheEntry(lpFormatEtc, DATADIR_GET);
  220.     pEntry->m_stgMedium = *lpStgMedium;
  221. }
  222.  
  223. // for CFile* based delayed render
  224. void COleDataSource::DelayRenderFileData(CLIPFORMAT cfFormat,
  225.     LPFORMATETC lpFormatEtc)
  226. {
  227.     ASSERT(lpFormatEtc == NULL ||
  228.         AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
  229.  
  230.     // fill in FORMATETC struct
  231.     FORMATETC formatEtc;
  232.     lpFormatEtc = _AfxFillFormatEtc(lpFormatEtc, cfFormat, &formatEtc);
  233.     lpFormatEtc->tymed |= TYMED_ISTREAM|TYMED_HGLOBAL;
  234.  
  235.     // add it to the cache
  236.     AFX_DATACACHE_ENTRY* pEntry = GetCacheEntry(lpFormatEtc, DATADIR_GET);
  237.     pEntry->m_stgMedium.tymed = TYMED_NULL;
  238.     pEntry->m_stgMedium.hGlobal = NULL;
  239.     pEntry->m_stgMedium.pUnkForRelease = NULL;
  240. }
  241.  
  242. // for LPSTGMEDIUM or HGLOBAL based delayed render
  243. void COleDataSource::DelayRenderData(CLIPFORMAT cfFormat, LPFORMATETC lpFormatEtc)
  244. {
  245.     ASSERT(lpFormatEtc == NULL ||
  246.         AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
  247.  
  248.     // fill in FORMATETC struct
  249.     FORMATETC formatEtc;
  250.     if (lpFormatEtc == NULL)
  251.     {
  252.         lpFormatEtc = _AfxFillFormatEtc(lpFormatEtc, cfFormat, &formatEtc);
  253.         lpFormatEtc->tymed = TYMED_HGLOBAL;
  254.     }
  255.     // insure that cfFormat member is set
  256.     if (cfFormat != 0)
  257.         lpFormatEtc->cfFormat = cfFormat;
  258.  
  259.     // add it to the cache
  260.     AFX_DATACACHE_ENTRY* pEntry = GetCacheEntry(lpFormatEtc, DATADIR_GET);
  261.     memset(&pEntry->m_stgMedium, 0, sizeof pEntry->m_stgMedium);
  262. }
  263.  
  264. // DelaySetData -- used to allow SetData on given LPFORMATETC
  265. void COleDataSource::DelaySetData(CLIPFORMAT cfFormat, LPFORMATETC lpFormatEtc)
  266. {
  267.     ASSERT(lpFormatEtc == NULL ||
  268.         AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
  269.  
  270.     // fill in FORMATETC struct
  271.     FORMATETC formatEtc;
  272.     lpFormatEtc = _AfxFillFormatEtc(lpFormatEtc, cfFormat, &formatEtc);
  273.  
  274.     // add it to the cache
  275.     AFX_DATACACHE_ENTRY* pEntry = GetCacheEntry(lpFormatEtc, DATADIR_SET);
  276.     pEntry->m_stgMedium.tymed = TYMED_NULL;
  277.     pEntry->m_stgMedium.hGlobal = NULL;
  278.     pEntry->m_stgMedium.pUnkForRelease = NULL;
  279. }
  280.  
  281. /////////////////////////////////////////////////////////////////////////////
  282. // COleDataSource cache implementation
  283.  
  284. AFX_DATACACHE_ENTRY* COleDataSource::Lookup(
  285.     LPFORMATETC lpFormatEtc, DATADIR nDataDir) const
  286. {
  287.     AFX_DATACACHE_ENTRY* pLast = NULL;
  288.  
  289.     // look for suitable match to lpFormatEtc in cache
  290.     for (UINT nIndex = 0; nIndex < m_nSize; nIndex++)
  291.     {
  292.         // get entry from cache at nIndex
  293.         AFX_DATACACHE_ENTRY* pCache = &m_pDataCache[nIndex];
  294.         FORMATETC *pCacheFormat = &pCache->m_formatEtc;
  295.  
  296.         // check for match
  297.         if (pCacheFormat->cfFormat == lpFormatEtc->cfFormat &&
  298.             (pCacheFormat->tymed & lpFormatEtc->tymed) != 0 &&
  299.             (pCache->m_stgMedium.tymed == TYMED_NULL ||
  300.                 pCacheFormat->lindex == lpFormatEtc->lindex) &&
  301.             pCacheFormat->dwAspect == lpFormatEtc->dwAspect &&
  302.             pCache->m_nDataDir == nDataDir)
  303.         {
  304.             // for backward compatibility we match even if we never
  305.             // find an exact match for the DVTARGETDEVICE
  306.             pLast = pCache;
  307.             DVTARGETDEVICE* ptd1 = pCacheFormat->ptd;
  308.             DVTARGETDEVICE* ptd2 = lpFormatEtc->ptd;
  309.  
  310.             if (ptd1 == NULL && ptd2 == NULL)
  311.             {
  312.                 // both target devices are NULL (exact match), so return it
  313.                 break;
  314.             }
  315.             if (ptd1 != NULL && ptd2 != NULL &&
  316.                 ptd1->tdSize == ptd2->tdSize &&
  317.                 memcmp(ptd1, ptd2, ptd1->tdSize) == 0)
  318.             {
  319.                 // exact match, so return it
  320.                 break;
  321.             }
  322.             // continue looking for better match
  323.         }
  324.     }
  325.  
  326.     return pLast;    // not found
  327. }
  328.  
  329. /////////////////////////////////////////////////////////////////////////////
  330. // COleDataSource overidable default implementation
  331.  
  332. BOOL COleDataSource::OnRenderGlobalData(
  333.     LPFORMATETC /*lpFormatEtc*/, HGLOBAL* /*phGlobal*/)
  334. {
  335.     return FALSE;   // default does nothing
  336. }
  337.  
  338. BOOL COleDataSource::OnRenderFileData(
  339.     LPFORMATETC /*lpFormatEtc*/, CFile* /*pFile*/)
  340. {
  341.     return FALSE;   // default does nothing
  342. }
  343.  
  344. BOOL COleDataSource::OnRenderData(
  345.     LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium)
  346. {
  347.     // attempt TYMED_HGLOBAL as prefered format
  348.     if (lpFormatEtc->tymed & TYMED_HGLOBAL)
  349.     {
  350.         // attempt HGLOBAL delay render hook
  351.         HGLOBAL hGlobal = lpStgMedium->hGlobal;
  352.         if (OnRenderGlobalData(lpFormatEtc, &hGlobal))
  353.         {
  354.             ASSERT(lpStgMedium->tymed != TYMED_HGLOBAL ||
  355.                 (lpStgMedium->hGlobal == hGlobal));
  356.             ASSERT(hGlobal != NULL);
  357.             lpStgMedium->tymed = TYMED_HGLOBAL;
  358.             lpStgMedium->hGlobal = hGlobal;
  359.             return TRUE;
  360.         }
  361.  
  362.         // attempt CFile* based delay render hook
  363.         CSharedFile file;
  364.         if (lpStgMedium->tymed == TYMED_HGLOBAL)
  365.         {
  366.             ASSERT(lpStgMedium->hGlobal != NULL);
  367.             file.SetHandle(lpStgMedium->hGlobal, FALSE);
  368.         }
  369.         if (OnRenderFileData(lpFormatEtc, &file))
  370.         {
  371.             lpStgMedium->tymed = TYMED_HGLOBAL;
  372.             lpStgMedium->hGlobal = file.Detach();
  373.             ASSERT(lpStgMedium->hGlobal != NULL);
  374.             return TRUE;
  375.         }
  376.         if (lpStgMedium->tymed == TYMED_HGLOBAL)
  377.             file.Detach();
  378.     }
  379.  
  380.     // attempt TYMED_ISTREAM format
  381.     if (lpFormatEtc->tymed & TYMED_ISTREAM)
  382.     {
  383.         COleStreamFile file;
  384.         if (lpStgMedium->tymed == TYMED_ISTREAM)
  385.         {
  386.             ASSERT(lpStgMedium->pstm != NULL);
  387.             file.Attach(lpStgMedium->pstm);
  388.         }
  389.         else
  390.         {
  391.             if (!file.CreateMemoryStream())
  392.                 AfxThrowMemoryException();
  393.         }
  394.         // get data into the stream
  395.         if (OnRenderFileData(lpFormatEtc, &file))
  396.         {
  397.             lpStgMedium->tymed = TYMED_ISTREAM;
  398.             lpStgMedium->pstm = file.Detach();
  399.             return TRUE;
  400.         }
  401.         if (lpStgMedium->tymed == TYMED_ISTREAM)
  402.             file.Detach();
  403.     }
  404.  
  405.     return FALSE;   // default does nothing
  406. }
  407.  
  408. BOOL COleDataSource::OnSetData(
  409.     LPFORMATETC /*lpFormatEtc*/, LPSTGMEDIUM /*lpStgMedium*/, BOOL /*bRelease*/)
  410. {
  411.     return FALSE;   // default does nothing
  412. }
  413.  
  414. /////////////////////////////////////////////////////////////////////////////
  415. // CEnumFormatEtc - enumerator for array for FORMATETC structures
  416.  
  417. class CEnumFormatEtc : public CEnumArray
  418. {
  419. // Constructors
  420. public:
  421.     CEnumFormatEtc();
  422.  
  423. // Operations
  424.     void AddFormat(const FORMATETC* lpFormatEtc);
  425.  
  426. // Implementation
  427. public:
  428.     virtual ~CEnumFormatEtc();
  429.  
  430. protected:
  431.     virtual BOOL OnNext(void* pv);
  432.  
  433.     UINT m_nMaxSize;    // number of items allocated (>= m_nSize)
  434.     DECLARE_INTERFACE_MAP()
  435. };
  436.  
  437. BEGIN_INTERFACE_MAP(CEnumFormatEtc, CEnumArray)
  438.     INTERFACE_PART(CEnumFormatEtc, IID_IEnumFORMATETC, EnumVOID)
  439. END_INTERFACE_MAP()
  440.  
  441. CEnumFormatEtc::CEnumFormatEtc()
  442.     : CEnumArray(sizeof(FORMATETC), NULL, 0, TRUE)
  443. {
  444.     m_nMaxSize = 0;
  445. }
  446.  
  447. CEnumFormatEtc::~CEnumFormatEtc()
  448. {
  449.     if (m_pClonedFrom == NULL)
  450.     {
  451.         // release all of the pointers to DVTARGETDEVICE
  452.         LPFORMATETC lpFormatEtc = (LPFORMATETC)m_pvEnum;
  453.         for (UINT nIndex = 0; nIndex < m_nSize; nIndex++)
  454.             CoTaskMemFree(lpFormatEtc[nIndex].ptd);
  455.     }
  456.     // destructor will free the actual array (if it was not a clone)
  457. }
  458.  
  459. BOOL CEnumFormatEtc::OnNext(void* pv)
  460. {
  461.     if (!CEnumArray::OnNext(pv))
  462.         return FALSE;
  463.  
  464.     // any outgoing formatEtc may require the DVTARGETDEVICE to
  465.     //  be copied (the caller has responsibility to free it)
  466.     LPFORMATETC lpFormatEtc = (LPFORMATETC)pv;
  467.     if (lpFormatEtc->ptd != NULL)
  468.     {
  469.         lpFormatEtc->ptd = _AfxOleCopyTargetDevice(lpFormatEtc->ptd);
  470.         if (lpFormatEtc->ptd == NULL)
  471.             AfxThrowMemoryException();
  472.     }
  473.     // otherwise, copying worked...
  474.     return TRUE;
  475. }
  476.  
  477. void CEnumFormatEtc::AddFormat(const FORMATETC* lpFormatEtc)
  478. {
  479.     ASSERT(m_nSize <= m_nMaxSize);
  480.  
  481.     if (m_nSize == m_nMaxSize)
  482.     {
  483.         // not enough space for new item -- allocate more
  484.         FORMATETC* pListNew = new FORMATETC[m_nSize+10];
  485.         m_nMaxSize += 10;
  486.         memcpy(pListNew, m_pvEnum, m_nSize*sizeof(FORMATETC));
  487.         delete m_pvEnum;
  488.         m_pvEnum = (BYTE*)pListNew;
  489.     }
  490.  
  491.     // add this item to the list
  492.     ASSERT(m_nSize < m_nMaxSize);
  493.     FORMATETC* pFormat = &((FORMATETC*)m_pvEnum)[m_nSize];
  494.     pFormat->cfFormat = lpFormatEtc->cfFormat;
  495.     pFormat->ptd = lpFormatEtc->ptd;
  496.         // Note: ownership of lpFormatEtc->ptd is transfered with this call.
  497.     pFormat->dwAspect = lpFormatEtc->dwAspect;
  498.     pFormat->lindex = lpFormatEtc->lindex;
  499.     pFormat->tymed = lpFormatEtc->tymed;
  500.     ++m_nSize;
  501. }
  502.  
  503. /////////////////////////////////////////////////////////////////////////////
  504. // COleDataSource::XDataObject
  505.  
  506. BEGIN_INTERFACE_MAP(COleDataSource, CCmdTarget)
  507.     INTERFACE_PART(COleDataSource, IID_IDataObject, DataObject)
  508. END_INTERFACE_MAP()
  509.  
  510. STDMETHODIMP_(ULONG) COleDataSource::XDataObject::AddRef()
  511. {
  512.     METHOD_PROLOGUE_EX_(COleDataSource, DataObject)
  513.     return pThis->ExternalAddRef();
  514. }
  515.  
  516. STDMETHODIMP_(ULONG) COleDataSource::XDataObject::Release()
  517. {
  518.     METHOD_PROLOGUE_EX_(COleDataSource, DataObject)
  519.     return pThis->ExternalRelease();
  520. }
  521.  
  522. STDMETHODIMP COleDataSource::XDataObject::QueryInterface(
  523.     REFIID iid, LPVOID* ppvObj)
  524. {
  525.     METHOD_PROLOGUE_EX_(COleDataSource, DataObject)
  526.     return pThis->ExternalQueryInterface(&iid, ppvObj);
  527. }
  528.  
  529. STDMETHODIMP COleDataSource::XDataObject::GetData(
  530.     LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium)
  531. {
  532.     METHOD_PROLOGUE_EX(COleDataSource, DataObject)
  533.     ASSERT_VALID(pThis);
  534.  
  535.     // attempt to find match in the cache
  536.     AFX_DATACACHE_ENTRY* pCache = pThis->Lookup(lpFormatEtc, DATADIR_GET);
  537.     if (pCache == NULL)
  538.         return DATA_E_FORMATETC;
  539.  
  540.     // use cache if entry is not delay render
  541.     memset(lpStgMedium, 0, sizeof(STGMEDIUM));
  542.     if (pCache->m_stgMedium.tymed != TYMED_NULL)
  543.     {
  544.         // Copy the cached medium into the lpStgMedium provided by caller.
  545.         if (!_AfxCopyStgMedium(lpFormatEtc->cfFormat, lpStgMedium,
  546.           &pCache->m_stgMedium))
  547.             return DATA_E_FORMATETC;
  548.  
  549.         // format was supported for copying
  550.         return S_OK;
  551.     }
  552.  
  553.     SCODE sc = DATA_E_FORMATETC;
  554.     TRY
  555.     {
  556.         // attempt LPSTGMEDIUM based delay render
  557.         if (pThis->OnRenderData(lpFormatEtc, lpStgMedium))
  558.             sc = S_OK;
  559.     }
  560.     CATCH_ALL(e)
  561.     {
  562.         sc = COleException::Process(e);
  563.         DELETE_EXCEPTION(e);
  564.     }
  565.     END_CATCH_ALL
  566.  
  567.     return sc;
  568. }
  569.  
  570. STDMETHODIMP COleDataSource::XDataObject::GetDataHere(
  571.     LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium)
  572. {
  573.     METHOD_PROLOGUE_EX(COleDataSource, DataObject)
  574.     ASSERT_VALID(pThis);
  575.  
  576.     // these two must be the same
  577.     ASSERT(lpFormatEtc->tymed == lpStgMedium->tymed);
  578.     lpFormatEtc->tymed = lpStgMedium->tymed;    // but just in case...
  579.  
  580.     // attempt to find match in the cache
  581.     AFX_DATACACHE_ENTRY* pCache = pThis->Lookup(lpFormatEtc, DATADIR_GET);
  582.     if (pCache == NULL)
  583.         return DATA_E_FORMATETC;
  584.  
  585.     // handle cached medium and copy
  586.     if (pCache->m_stgMedium.tymed != TYMED_NULL)
  587.     {
  588.         // found a cached format -- copy it to dest medium
  589.         ASSERT(pCache->m_stgMedium.tymed == lpStgMedium->tymed);
  590.         if (!_AfxCopyStgMedium(lpFormatEtc->cfFormat, lpStgMedium,
  591.           &pCache->m_stgMedium))
  592.             return DATA_E_FORMATETC;
  593.  
  594.         // format was supported for copying
  595.         return S_OK;
  596.     }
  597.  
  598.     SCODE sc = DATA_E_FORMATETC;
  599.     TRY
  600.     {
  601.         // attempt LPSTGMEDIUM based delay render
  602.         if (pThis->OnRenderData(lpFormatEtc, lpStgMedium))
  603.             sc = S_OK;
  604.     }
  605.     CATCH_ALL(e)
  606.     {
  607.         sc = COleException::Process(e);
  608.         DELETE_EXCEPTION(e);
  609.     }
  610.     END_CATCH_ALL
  611.  
  612.     return sc;
  613. }
  614.  
  615. STDMETHODIMP COleDataSource::XDataObject::QueryGetData(LPFORMATETC lpFormatEtc)
  616. {
  617.     METHOD_PROLOGUE_EX_(COleDataSource, DataObject)
  618.  
  619.     // attempt to find match in the cache
  620.     AFX_DATACACHE_ENTRY* pCache = pThis->Lookup(lpFormatEtc, DATADIR_GET);
  621.     if (pCache == NULL)
  622.         return DATA_E_FORMATETC;
  623.  
  624.     // it was found in the cache or can be rendered -- success
  625.     return S_OK;
  626. }
  627.  
  628. STDMETHODIMP COleDataSource::XDataObject::GetCanonicalFormatEtc(
  629.     LPFORMATETC /*lpFormatEtcIn*/, LPFORMATETC /*lpFormatEtcOut*/)
  630. {
  631.     // because we support the target-device (ptd) for server metafile format,
  632.     //  all members of the FORMATETC are significant.
  633.  
  634.     return DATA_S_SAMEFORMATETC;
  635. }
  636.  
  637. STDMETHODIMP COleDataSource::XDataObject::SetData(
  638.     LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium, BOOL bRelease)
  639. {
  640.     METHOD_PROLOGUE_EX(COleDataSource, DataObject)
  641.     ASSERT_VALID(pThis);
  642.  
  643.     ASSERT(lpFormatEtc->tymed == lpStgMedium->tymed);
  644.  
  645.     // attempt to find match in the cache
  646.     AFX_DATACACHE_ENTRY* pCache = pThis->Lookup(lpFormatEtc, DATADIR_SET);
  647.     if (pCache == NULL)
  648.         return DATA_E_FORMATETC;
  649.  
  650.     ASSERT(pCache->m_stgMedium.tymed == TYMED_NULL);
  651.  
  652.     SCODE sc = E_UNEXPECTED;
  653.     TRY
  654.     {
  655.         // attempt LPSTGMEDIUM based SetData
  656.         if (pThis->OnSetData(lpFormatEtc, lpStgMedium, bRelease))
  657.             sc = S_OK;
  658.     }
  659.     CATCH_ALL(e)
  660.     {
  661.         sc = COleException::Process(e);
  662.         DELETE_EXCEPTION(e);
  663.     }
  664.     END_CATCH_ALL
  665.  
  666.     return sc;
  667. }
  668.  
  669. STDMETHODIMP COleDataSource::XDataObject::EnumFormatEtc(
  670.     DWORD dwDirection, LPENUMFORMATETC* ppenumFormatEtc)
  671. {
  672.     METHOD_PROLOGUE_EX_(COleDataSource, DataObject)
  673.  
  674.     *ppenumFormatEtc = NULL;
  675.  
  676.     CEnumFormatEtc* pFormatList = NULL;
  677.     SCODE sc = E_OUTOFMEMORY;
  678.     TRY
  679.     {
  680.         // generate a format list from the cache
  681.         pFormatList = new CEnumFormatEtc;
  682.         for (UINT nIndex = 0; nIndex < pThis->m_nSize; nIndex++)
  683.         {
  684.             AFX_DATACACHE_ENTRY* pCache = &pThis->m_pDataCache[nIndex];
  685.             if ((DWORD)pCache->m_nDataDir & dwDirection)
  686.             {
  687.                 // entry should be enumerated -- add it to the list
  688.                 FORMATETC formatEtc;
  689.                 _AfxOleCopyFormatEtc(&formatEtc, &pCache->m_formatEtc);
  690.                 pFormatList->AddFormat(&formatEtc);
  691.             }
  692.         }
  693.         // give it away to OLE (ref count is already 1)
  694.         *ppenumFormatEtc = (LPENUMFORMATETC)&pFormatList->m_xEnumVOID;
  695.         sc = S_OK;
  696.     }
  697.     END_TRY
  698.  
  699.     return sc;
  700. }
  701.  
  702. STDMETHODIMP COleDataSource::XDataObject::DAdvise(
  703.     FORMATETC* /*pFormatetc*/, DWORD /*advf*/,
  704.     LPADVISESINK /*pAdvSink*/, DWORD* pdwConnection)
  705. {
  706.     *pdwConnection = 0;
  707.     return OLE_E_ADVISENOTSUPPORTED;
  708. }
  709.  
  710. STDMETHODIMP COleDataSource::XDataObject::DUnadvise(DWORD /*dwConnection*/)
  711. {
  712.     return OLE_E_ADVISENOTSUPPORTED;
  713. }
  714.  
  715. STDMETHODIMP COleDataSource::XDataObject::EnumDAdvise(
  716.     LPENUMSTATDATA* ppenumAdvise)
  717. {
  718.     *ppenumAdvise = NULL;
  719.     return OLE_E_ADVISENOTSUPPORTED;
  720. }
  721.  
  722. /////////////////////////////////////////////////////////////////////////////
  723. // COleDataSource diagnostics
  724.  
  725. #ifdef _DEBUG
  726. void COleDataSource::AssertValid() const
  727. {
  728.     CCmdTarget::AssertValid();
  729.     ASSERT(m_nSize <= m_nMaxSize);
  730.     ASSERT(m_nMaxSize != 0 || m_pDataCache == NULL);
  731. }
  732.  
  733. void COleDataSource::Dump(CDumpContext& dc) const
  734. {
  735.     CCmdTarget::Dump(dc);
  736.  
  737.     dc << "m_nMaxSize = " << m_nMaxSize;
  738.     dc << "\nm_nSize = " << m_nSize;
  739.     dc << "\nm_pDataCache = " << m_pDataCache;
  740.  
  741.     for (UINT n = 0; n < m_nSize; n++)
  742.     {
  743.         dc << "\n\tentry [" << n << "] = {";
  744.         AFX_DATACACHE_ENTRY& rEntry = m_pDataCache[n];
  745.         dc << "\n\t m_formatEtc.cfFormat = " << rEntry.m_formatEtc.cfFormat;
  746.         dc << "\n\t m_formatEtc.pdt = " << rEntry.m_formatEtc.ptd;
  747.         dc << "\n\t m_formatEtc.dwAspect = " << rEntry.m_formatEtc.dwAspect;
  748.         dc << "\n\t m_formatEtc.lindex = " << rEntry.m_formatEtc.lindex;
  749.         dc << "\n\t m_formatEtc.tymed = " << rEntry.m_formatEtc.tymed;
  750.         dc << "\n\t m_stgMedium.tymed = " << rEntry.m_stgMedium.tymed;
  751.         dc << "\n\t m_nDataDir = " << (UINT)rEntry.m_nDataDir;
  752.         dc << "\n\t}";
  753.     }
  754.  
  755.     dc << "\n";
  756. }
  757. #endif //_DEBUG
  758.  
  759. /////////////////////////////////////////////////////////////////////////////
  760.