home *** CD-ROM | disk | FTP | other *** search
/ Supercompiler 1997 / SUPERCOMPILER97.iso / MS_VC.50 / VC / MFC / SRC / OLEDOBJ2.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1996-12-03  |  20.9 KB  |  754 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1997 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10.  
  11. #include "stdafx.h"
  12.  
  13. #ifdef AFX_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.     // look for suitable match to lpFormatEtc in cache
  289.     for (UINT nIndex = 0; nIndex < m_nSize; nIndex++)
  290.     {
  291.         // get entry from cache at nIndex
  292.         AFX_DATACACHE_ENTRY* pCache = &m_pDataCache[nIndex];
  293.         FORMATETC *pCacheFormat = &pCache->m_formatEtc;
  294.  
  295.         // check for match
  296.         if (pCacheFormat->cfFormat == lpFormatEtc->cfFormat &&
  297.             (pCacheFormat->tymed & lpFormatEtc->tymed) != 0 &&
  298.             pCacheFormat->lindex == lpFormatEtc->lindex &&
  299.             pCacheFormat->dwAspect == lpFormatEtc->dwAspect &&
  300.             pCache->m_nDataDir == nDataDir)
  301.         {
  302.             // for backward compatibility we match even if we never
  303.             // find an exact match for the DVTARGETDEVICE
  304.             DVTARGETDEVICE* ptd1 = pCacheFormat->ptd;
  305.             DVTARGETDEVICE* ptd2 = lpFormatEtc->ptd;
  306.             pLast = pCache;
  307.             if ( ((ptd1 == NULL) && (ptd2 == NULL)) ||
  308.                 ((ptd1 != NULL) && (ptd2 != NULL) &&
  309.                     (ptd1->tdSize == ptd2->tdSize) &&
  310.                     (memcmp(ptd1, ptd2, ptd1->tdSize)==0)
  311.                 ))
  312.             {
  313.                 // exact match, so break now and return it
  314.                 break;
  315.             }
  316.             // continue looking for better match
  317.         }
  318.     }
  319.  
  320.     return pLast;    // not found
  321. }
  322.  
  323. /////////////////////////////////////////////////////////////////////////////
  324. // COleDataSource overidable default implementation
  325.  
  326. BOOL COleDataSource::OnRenderGlobalData(
  327.     LPFORMATETC /*lpFormatEtc*/, HGLOBAL* /*phGlobal*/)
  328. {
  329.     return FALSE;   // default does nothing
  330. }
  331.  
  332. BOOL COleDataSource::OnRenderFileData(
  333.     LPFORMATETC /*lpFormatEtc*/, CFile* /*pFile*/)
  334. {
  335.     return FALSE;   // default does nothing
  336. }
  337.  
  338. BOOL COleDataSource::OnRenderData(
  339.     LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium)
  340. {
  341.     // attempt TYMED_HGLOBAL as prefered format
  342.     if (lpFormatEtc->tymed & TYMED_HGLOBAL)
  343.     {
  344.         // attempt HGLOBAL delay render hook
  345.         HGLOBAL hGlobal = lpStgMedium->hGlobal;
  346.         if (OnRenderGlobalData(lpFormatEtc, &hGlobal))
  347.         {
  348.             ASSERT(lpStgMedium->tymed != TYMED_HGLOBAL ||
  349.                 (lpStgMedium->hGlobal == hGlobal));
  350.             ASSERT(hGlobal != NULL);
  351.             lpStgMedium->tymed = TYMED_HGLOBAL;
  352.             lpStgMedium->hGlobal = hGlobal;
  353.             return TRUE;
  354.         }
  355.  
  356.         // attempt CFile* based delay render hook
  357.         CSharedFile file;
  358.         if (lpStgMedium->tymed == TYMED_HGLOBAL)
  359.         {
  360.             ASSERT(lpStgMedium->hGlobal != NULL);
  361.             file.SetHandle(lpStgMedium->hGlobal, FALSE);
  362.         }
  363.         if (OnRenderFileData(lpFormatEtc, &file))
  364.         {
  365.             lpStgMedium->tymed = TYMED_HGLOBAL;
  366.             lpStgMedium->hGlobal = file.Detach();
  367.             ASSERT(lpStgMedium->hGlobal != NULL);
  368.             return TRUE;
  369.         }
  370.         if (lpStgMedium->tymed == TYMED_HGLOBAL)
  371.             file.Detach();
  372.     }
  373.  
  374.     // attempt TYMED_ISTREAM format
  375.     if (lpFormatEtc->tymed & TYMED_ISTREAM)
  376.     {
  377.         COleStreamFile file;
  378.         if (lpStgMedium->tymed == TYMED_ISTREAM)
  379.         {
  380.             ASSERT(lpStgMedium->pstm != NULL);
  381.             file.Attach(lpStgMedium->pstm);
  382.         }
  383.         else
  384.         {
  385.             if (!file.CreateMemoryStream())
  386.                 AfxThrowMemoryException();
  387.         }
  388.         // get data into the stream
  389.         if (OnRenderFileData(lpFormatEtc, &file))
  390.         {
  391.             lpStgMedium->tymed = TYMED_ISTREAM;
  392.             lpStgMedium->pstm = file.Detach();
  393.             return TRUE;
  394.         }
  395.         if (lpStgMedium->tymed == TYMED_ISTREAM)
  396.             file.Detach();
  397.     }
  398.  
  399.     return FALSE;   // default does nothing
  400. }
  401.  
  402. BOOL COleDataSource::OnSetData(
  403.     LPFORMATETC /*lpFormatEtc*/, LPSTGMEDIUM /*lpStgMedium*/, BOOL /*bRelease*/)
  404. {
  405.     return FALSE;   // default does nothing
  406. }
  407.  
  408. /////////////////////////////////////////////////////////////////////////////
  409. // CEnumFormatEtc - enumerator for array for FORMATETC structures
  410.  
  411. class CEnumFormatEtc : public CEnumArray
  412. {
  413. // Constructors
  414. public:
  415.     CEnumFormatEtc();
  416.  
  417. // Operations
  418.     void AddFormat(const FORMATETC* lpFormatEtc);
  419.  
  420. // Implementation
  421. public:
  422.     virtual ~CEnumFormatEtc();
  423.  
  424. protected:
  425.     virtual BOOL OnNext(void* pv);
  426.  
  427.     UINT m_nMaxSize;    // number of items allocated (>= m_nSize)
  428.     DECLARE_INTERFACE_MAP()
  429. };
  430.  
  431. BEGIN_INTERFACE_MAP(CEnumFormatEtc, CEnumArray)
  432.     INTERFACE_PART(CEnumFormatEtc, IID_IEnumFORMATETC, EnumVOID)
  433. END_INTERFACE_MAP()
  434.  
  435. CEnumFormatEtc::CEnumFormatEtc()
  436.     : CEnumArray(sizeof(FORMATETC), NULL, 0, TRUE)
  437. {
  438.     m_nMaxSize = 0;
  439. }
  440.  
  441. CEnumFormatEtc::~CEnumFormatEtc()
  442. {
  443.     if (m_pClonedFrom == NULL)
  444.     {
  445.         // release all of the pointers to DVTARGETDEVICE
  446.         LPFORMATETC lpFormatEtc = (LPFORMATETC)m_pvEnum;
  447.         for (UINT nIndex = 0; nIndex < m_nSize; nIndex++)
  448.             CoTaskMemFree(lpFormatEtc[nIndex].ptd);
  449.     }
  450.     // destructor will free the actual array (if it was not a clone)
  451. }
  452.  
  453. BOOL CEnumFormatEtc::OnNext(void* pv)
  454. {
  455.     if (!CEnumArray::OnNext(pv))
  456.         return FALSE;
  457.  
  458.     // any outgoing formatEtc may require the DVTARGETDEVICE to
  459.     //  be copied (the caller has responsibility to free it)
  460.     LPFORMATETC lpFormatEtc = (LPFORMATETC)pv;
  461.     if (lpFormatEtc->ptd != NULL)
  462.     {
  463.         lpFormatEtc->ptd = _AfxOleCopyTargetDevice(lpFormatEtc->ptd);
  464.         if (lpFormatEtc->ptd == NULL)
  465.             AfxThrowMemoryException();
  466.     }
  467.     // otherwise, copying worked...
  468.     return TRUE;
  469. }
  470.  
  471. void CEnumFormatEtc::AddFormat(const FORMATETC* lpFormatEtc)
  472. {
  473.     ASSERT(m_nSize <= m_nMaxSize);
  474.  
  475.     if (m_nSize == m_nMaxSize)
  476.     {
  477.         // not enough space for new item -- allocate more
  478.         FORMATETC* pListNew = new FORMATETC[m_nSize+10];
  479.         m_nMaxSize += 10;
  480.         memcpy(pListNew, m_pvEnum, m_nSize*sizeof(FORMATETC));
  481.         delete m_pvEnum;
  482.         m_pvEnum = (BYTE*)pListNew;
  483.     }
  484.  
  485.     // add this item to the list
  486.     ASSERT(m_nSize < m_nMaxSize);
  487.     FORMATETC* pFormat = &((FORMATETC*)m_pvEnum)[m_nSize];
  488.     pFormat->cfFormat = lpFormatEtc->cfFormat;
  489.     pFormat->ptd = lpFormatEtc->ptd;
  490.         // Note: ownership of lpFormatEtc->ptd is transfered with this call.
  491.     pFormat->dwAspect = lpFormatEtc->dwAspect;
  492.     pFormat->lindex = lpFormatEtc->lindex;
  493.     pFormat->tymed = lpFormatEtc->tymed;
  494.     ++m_nSize;
  495. }
  496.  
  497. /////////////////////////////////////////////////////////////////////////////
  498. // COleDataSource::XDataObject
  499.  
  500. BEGIN_INTERFACE_MAP(COleDataSource, CCmdTarget)
  501.     INTERFACE_PART(COleDataSource, IID_IDataObject, DataObject)
  502. END_INTERFACE_MAP()
  503.  
  504. STDMETHODIMP_(ULONG) COleDataSource::XDataObject::AddRef()
  505. {
  506.     METHOD_PROLOGUE_EX_(COleDataSource, DataObject)
  507.     return pThis->ExternalAddRef();
  508. }
  509.  
  510. STDMETHODIMP_(ULONG) COleDataSource::XDataObject::Release()
  511. {
  512.     METHOD_PROLOGUE_EX_(COleDataSource, DataObject)
  513.     return pThis->ExternalRelease();
  514. }
  515.  
  516. STDMETHODIMP COleDataSource::XDataObject::QueryInterface(
  517.     REFIID iid, LPVOID* ppvObj)
  518. {
  519.     METHOD_PROLOGUE_EX_(COleDataSource, DataObject)
  520.     return pThis->ExternalQueryInterface(&iid, ppvObj);
  521. }
  522.  
  523. STDMETHODIMP COleDataSource::XDataObject::GetData(
  524.     LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium)
  525. {
  526.     METHOD_PROLOGUE_EX(COleDataSource, DataObject)
  527.     ASSERT_VALID(pThis);
  528.  
  529.     // attempt to find match in the cache
  530.     AFX_DATACACHE_ENTRY* pCache = pThis->Lookup(lpFormatEtc, DATADIR_GET);
  531.     if (pCache == NULL)
  532.         return DATA_E_FORMATETC;
  533.  
  534.     // use cache if entry is not delay render
  535.     memset(lpStgMedium, 0, sizeof(STGMEDIUM));
  536.     if (pCache->m_stgMedium.tymed != TYMED_NULL)
  537.     {
  538.         // Copy the cached medium into the lpStgMedium provided by caller.
  539.         if (!_AfxCopyStgMedium(lpFormatEtc->cfFormat, lpStgMedium,
  540.           &pCache->m_stgMedium))
  541.             return DATA_E_FORMATETC;
  542.  
  543.         // format was supported for copying
  544.         return S_OK;
  545.     }
  546.  
  547.     SCODE sc = DATA_E_FORMATETC;
  548.     TRY
  549.     {
  550.         // attempt LPSTGMEDIUM based delay render
  551.         if (pThis->OnRenderData(lpFormatEtc, lpStgMedium))
  552.             sc = S_OK;
  553.     }
  554.     CATCH_ALL(e)
  555.     {
  556.         sc = COleException::Process(e);
  557.         DELETE_EXCEPTION(e);
  558.     }
  559.     END_CATCH_ALL
  560.  
  561.     return sc;
  562. }
  563.  
  564. STDMETHODIMP COleDataSource::XDataObject::GetDataHere(
  565.     LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium)
  566. {
  567.     METHOD_PROLOGUE_EX(COleDataSource, DataObject)
  568.     ASSERT_VALID(pThis);
  569.  
  570.     // these two must be the same
  571.     ASSERT(lpFormatEtc->tymed == lpStgMedium->tymed);
  572.     lpFormatEtc->tymed = lpStgMedium->tymed;    // but just in case...
  573.  
  574.     // attempt to find match in the cache
  575.     AFX_DATACACHE_ENTRY* pCache = pThis->Lookup(lpFormatEtc, DATADIR_GET);
  576.     if (pCache == NULL)
  577.         return DATA_E_FORMATETC;
  578.  
  579.     // handle cached medium and copy
  580.     if (pCache->m_stgMedium.tymed != TYMED_NULL)
  581.     {
  582.         // found a cached format -- copy it to dest medium
  583.         ASSERT(pCache->m_stgMedium.tymed == lpStgMedium->tymed);
  584.         if (!_AfxCopyStgMedium(lpFormatEtc->cfFormat, lpStgMedium,
  585.           &pCache->m_stgMedium))
  586.             return DATA_E_FORMATETC;
  587.  
  588.         // format was supported for copying
  589.         return S_OK;
  590.     }
  591.  
  592.     SCODE sc = DATA_E_FORMATETC;
  593.     TRY
  594.     {
  595.         // attempt LPSTGMEDIUM based delay render
  596.         if (pThis->OnRenderData(lpFormatEtc, lpStgMedium))
  597.             sc = S_OK;
  598.     }
  599.     CATCH_ALL(e)
  600.     {
  601.         sc = COleException::Process(e);
  602.         DELETE_EXCEPTION(e);
  603.     }
  604.     END_CATCH_ALL
  605.  
  606.     return sc;
  607. }
  608.  
  609. STDMETHODIMP COleDataSource::XDataObject::QueryGetData(LPFORMATETC lpFormatEtc)
  610. {
  611.     METHOD_PROLOGUE_EX_(COleDataSource, DataObject)
  612.  
  613.     // attempt to find match in the cache
  614.     AFX_DATACACHE_ENTRY* pCache = pThis->Lookup(lpFormatEtc, DATADIR_GET);
  615.     if (pCache == NULL)
  616.         return DATA_E_FORMATETC;
  617.  
  618.     // it was found in the cache or can be rendered -- success
  619.     return S_OK;
  620. }
  621.  
  622. STDMETHODIMP COleDataSource::XDataObject::GetCanonicalFormatEtc(
  623.     LPFORMATETC /*lpFormatEtcIn*/, LPFORMATETC /*lpFormatEtcOut*/)
  624. {
  625.     // because we support the target-device (ptd) for server metafile format,
  626.     //  all members of the FORMATETC are significant.
  627.  
  628.     return DATA_S_SAMEFORMATETC;
  629. }
  630.  
  631. STDMETHODIMP COleDataSource::XDataObject::SetData(
  632.     LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium, BOOL bRelease)
  633. {
  634.     METHOD_PROLOGUE_EX(COleDataSource, DataObject)
  635.     ASSERT_VALID(pThis);
  636.  
  637.     ASSERT(lpFormatEtc->tymed == lpStgMedium->tymed);
  638.  
  639.     // attempt to find match in the cache
  640.     AFX_DATACACHE_ENTRY* pCache = pThis->Lookup(lpFormatEtc, DATADIR_SET);
  641.     if (pCache == NULL)
  642.         return DATA_E_FORMATETC;
  643.  
  644.     ASSERT(pCache->m_stgMedium.tymed == TYMED_NULL);
  645.  
  646.     SCODE sc = E_UNEXPECTED;
  647.     TRY
  648.     {
  649.         // attempt LPSTGMEDIUM based SetData
  650.         if (pThis->OnSetData(lpFormatEtc, lpStgMedium, bRelease))
  651.             sc = S_OK;
  652.     }
  653.     CATCH_ALL(e)
  654.     {
  655.         sc = COleException::Process(e);
  656.         DELETE_EXCEPTION(e);
  657.     }
  658.     END_CATCH_ALL
  659.  
  660.     return sc;
  661. }
  662.  
  663. STDMETHODIMP COleDataSource::XDataObject::EnumFormatEtc(
  664.     DWORD dwDirection, LPENUMFORMATETC* ppenumFormatEtc)
  665. {
  666.     METHOD_PROLOGUE_EX_(COleDataSource, DataObject)
  667.  
  668.     *ppenumFormatEtc = NULL;
  669.  
  670.     CEnumFormatEtc* pFormatList = NULL;
  671.     SCODE sc = E_OUTOFMEMORY;
  672.     TRY
  673.     {
  674.         // generate a format list from the cache
  675.         pFormatList = new CEnumFormatEtc;
  676.         for (UINT nIndex = 0; nIndex < pThis->m_nSize; nIndex++)
  677.         {
  678.             AFX_DATACACHE_ENTRY* pCache = &pThis->m_pDataCache[nIndex];
  679.             if ((DWORD)pCache->m_nDataDir & dwDirection)
  680.             {
  681.                 // entry should be enumerated -- add it to the list
  682.                 FORMATETC formatEtc;
  683.                 _AfxOleCopyFormatEtc(&formatEtc, &pCache->m_formatEtc);
  684.                 pFormatList->AddFormat(&formatEtc);
  685.             }
  686.         }
  687.         // give it away to OLE (ref count is already 1)
  688.         *ppenumFormatEtc = (LPENUMFORMATETC)&pFormatList->m_xEnumVOID;
  689.         sc = S_OK;
  690.     }
  691.     END_TRY
  692.  
  693.     return sc;
  694. }
  695.  
  696. STDMETHODIMP COleDataSource::XDataObject::DAdvise(
  697.     FORMATETC* /*pFormatetc*/, DWORD /*advf*/,
  698.     LPADVISESINK /*pAdvSink*/, DWORD* pdwConnection)
  699. {
  700.     *pdwConnection = 0;
  701.     return OLE_E_ADVISENOTSUPPORTED;
  702. }
  703.  
  704. STDMETHODIMP COleDataSource::XDataObject::DUnadvise(DWORD /*dwConnection*/)
  705. {
  706.     return OLE_E_ADVISENOTSUPPORTED;
  707. }
  708.  
  709. STDMETHODIMP COleDataSource::XDataObject::EnumDAdvise(
  710.     LPENUMSTATDATA* ppenumAdvise)
  711. {
  712.     *ppenumAdvise = NULL;
  713.     return OLE_E_ADVISENOTSUPPORTED;
  714. }
  715.  
  716. /////////////////////////////////////////////////////////////////////////////
  717. // COleDataSource diagnostics
  718.  
  719. #ifdef _DEBUG
  720. void COleDataSource::AssertValid() const
  721. {
  722.     CCmdTarget::AssertValid();
  723.     ASSERT(m_nSize <= m_nMaxSize);
  724.     ASSERT(m_nMaxSize != 0 || m_pDataCache == NULL);
  725. }
  726.  
  727. void COleDataSource::Dump(CDumpContext& dc) const
  728. {
  729.     CCmdTarget::Dump(dc);
  730.  
  731.     dc << "m_nMaxSize = " << m_nMaxSize;
  732.     dc << "\nm_nSize = " << m_nSize;
  733.     dc << "\nm_pDataCache = " << m_pDataCache;
  734.  
  735.     for (UINT n = 0; n < m_nSize; n++)
  736.     {
  737.         dc << "\n\tentry [" << n << "] = {";
  738.         AFX_DATACACHE_ENTRY& rEntry = m_pDataCache[n];
  739.         dc << "\n\t m_formatEtc.cfFormat = " << rEntry.m_formatEtc.cfFormat;
  740.         dc << "\n\t m_formatEtc.pdt = " << rEntry.m_formatEtc.ptd;
  741.         dc << "\n\t m_formatEtc.dwAspect = " << rEntry.m_formatEtc.dwAspect;
  742.         dc << "\n\t m_formatEtc.lindex = " << rEntry.m_formatEtc.lindex;
  743.         dc << "\n\t m_formatEtc.tymed = " << rEntry.m_formatEtc.tymed;
  744.         dc << "\n\t m_stgMedium.tymed = " << rEntry.m_stgMedium.tymed;
  745.         dc << "\n\t m_nDataDir = " << (UINT)rEntry.m_nDataDir;
  746.         dc << "\n\t}";
  747.     }
  748.  
  749.     dc << "\n";
  750. }
  751. #endif //_DEBUG
  752.  
  753. /////////////////////////////////////////////////////////////////////////////
  754.