home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / com / inole2 / chap12 / datatran / idataobj.cpp < prev    next >
C/C++ Source or Header  |  1995-05-03  |  11KB  |  431 lines

  1. /*
  2.  * IDATAOBJ.CPP
  3.  * Data Transfer Object Chapter 12
  4.  *
  5.  * Implementation of the IDataObject interface for CDataObject.
  6.  *
  7.  * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  8.  *
  9.  * Kraig Brockschmidt, Microsoft
  10.  * Internet  :  kraigb@microsoft.com
  11.  * Compuserve:  >INTERNET:kraigb@microsoft.com
  12.  */
  13.  
  14.  
  15. #include "dataobj.h"
  16.  
  17.  
  18. /*
  19.  * CImpIDataObject::CImpIDataObject
  20.  * CImpIDataObject::~CImpIDataObject
  21.  *
  22.  * Parameters (Constructor):
  23.  *  pObj            PCDataObject of the object we're in.
  24.  *  pUnkOuter       LPUNKNOWN to which we delegate.
  25.  */
  26.  
  27. CImpIDataObject::CImpIDataObject(PCDataObject pObj
  28.     , LPUNKNOWN pUnkOuter)
  29.     {
  30.     m_cRef=0;
  31.     m_pObj=pObj;
  32.     m_pUnkOuter=pUnkOuter;
  33.     return;
  34.     }
  35.  
  36. CImpIDataObject::~CImpIDataObject(void)
  37.     {
  38.     return;
  39.     }
  40.  
  41.  
  42.  
  43. /*
  44.  * CImpIDataObject::QueryInterface
  45.  * CImpIDataObject::AddRef
  46.  * CImpIDataObject::Release
  47.  *
  48.  * Purpose:
  49.  *  IUnknown members for CImpIDataObject object.
  50.  */
  51.  
  52. STDMETHODIMP CImpIDataObject::QueryInterface(REFIID riid, PPVOID ppv)
  53.     {
  54.     return m_pUnkOuter->QueryInterface(riid, ppv);
  55.     }
  56.  
  57.  
  58. STDMETHODIMP_(ULONG) CImpIDataObject::AddRef(void)
  59.     {
  60.     ++m_cRef;
  61.     return m_pUnkOuter->AddRef();
  62.     }
  63.  
  64. STDMETHODIMP_(ULONG) CImpIDataObject::Release(void)
  65.     {
  66.     --m_cRef;
  67.     return m_pUnkOuter->Release();
  68.     }
  69.  
  70.  
  71.  
  72.  
  73.  
  74. /*
  75.  * CImpIDataObject::GetData
  76.  *
  77.  * Purpose:
  78.  *  Retrieves data described by a specific FormatEtc into a StgMedium
  79.  *  allocated by this function.  Used like GetClipboardData.
  80.  *
  81.  * Parameters:
  82.  *  pFE             LPFORMATETC describing the desired data.
  83.  *  pSTM            LPSTGMEDIUM in which to return the data.
  84.  *
  85.  * Return Value:
  86.  *  HRESULT         NOERROR or a general error value.
  87.  */
  88.  
  89. STDMETHODIMP CImpIDataObject::GetData(LPFORMATETC pFE
  90.     , LPSTGMEDIUM pSTM)
  91.     {
  92.     UINT        i, cItems;
  93.     PRENDERING  pRen;
  94.     DWORD       cb;
  95.     HWND        hList;
  96.  
  97.     if (NULL==m_pObj->m_hList || NULL==pFE || NULL==pSTM)
  98.         return ResultFromScode(DATA_E_FORMATETC);
  99.  
  100.     hList=m_pObj->m_hList;
  101.     cItems=(UINT)SendMessage(hList, LB_GETCOUNT, 0, 0L);
  102.  
  103.     for (i=0; i < cItems; i++)
  104.         {
  105.         cb=SendMessage(hList, LB_GETTEXT, i, (LPARAM)&pRen);
  106.  
  107.         if (LB_ERR!=cb)
  108.             {
  109.             /*
  110.              * Check if the requested FORMATETC is the same as one
  111.              * that we already have. If so, then copy that STGMEDIUM
  112.              * to pSTM and AddRef ourselves for pUnkForRelease.
  113.              */
  114.             if (pFE->cfFormat==pRen->fe.cfFormat
  115.                 && (pFE->tymed & pRen->fe.tymed)
  116.                 && pFE->dwAspect==pRen->fe.dwAspect)
  117.                 {
  118.                 /*
  119.                  * ReleaseStgMedium will Release both storage
  120.                  * and stream elements regardless of the value
  121.                  * of pUnkForRelease, so we have to AddRef the
  122.                  * element and bump our own ref count here.
  123.                  */
  124.                 if (TYMED_ISTORAGE==pRen->fe.tymed)
  125.                       pRen->stm.pstg->AddRef();
  126.  
  127.                 if (TYMED_ISTREAM==pRen->fe.tymed)
  128.                       pRen->stm.pstm->AddRef();
  129.  
  130.                 *pSTM=pRen->stm;
  131.                 AddRef();
  132.                 return NOERROR;
  133.                 }
  134.             }
  135.         }
  136.  
  137.     return ResultFromScode(DATA_E_FORMATETC);
  138.     }
  139.  
  140.  
  141.  
  142. /*
  143.  * CImpIDataObject::GetDataHere
  144.  *
  145.  * Purpose:
  146.  *  Copies a piece of data in this data object to another
  147.  *  STGMEDIUM.  This is only supported for TYMED_ISTORAGE
  148.  *  and TYMED_ISTREAM.
  149.  *
  150.  * Parameters:
  151.  *  pFE             LPFORMATETC describing the desired data.
  152.  *  pSTM            LPSTGMEDIUM pointing to the medium into which
  153.  *                  we copy.
  154.  *
  155.  * Return Value:
  156.  *  HRESULT         NOERROR or a general error value.
  157.  */
  158.  
  159. STDMETHODIMP CImpIDataObject::GetDataHere(LPFORMATETC pFE
  160.     , LPSTGMEDIUM pSTM)
  161.     {
  162.     UINT        i, cItems;
  163.     PRENDERING  pRen;
  164.     DWORD       cb;
  165.     HWND        hList;
  166.  
  167.     if (NULL==m_pObj->m_hList || NULL==pFE || NULL==pSTM)
  168.         return ResultFromScode(DATA_E_FORMATETC);
  169.  
  170.     //We only support IStorage and IStream
  171.     if (!(TYMED_ISTORAGE & pFE->tymed)
  172.         && !(TYMED_ISTREAM & pFE->tymed))
  173.         return ResultFromScode(DATA_E_FORMATETC);
  174.  
  175.     hList=m_pObj->m_hList;
  176.     cItems=(UINT)SendMessage(hList, LB_GETCOUNT, 0, 0L);
  177.  
  178.     for (i=0; i < cItems; i++)
  179.         {
  180.         cb=SendMessage(hList, LB_GETTEXT, i, (LPARAM)&pRen);
  181.  
  182.         if (LB_ERR!=cb)
  183.             {
  184.             /*
  185.              * When we find a matching FORMATETC, we know we're
  186.              * only looking for IStorage or IStream (we checked
  187.              * above), so use IStorage::CopyTo or IStream::CopyTo
  188.              * to make the copy.
  189.              */
  190.             if (pFE->cfFormat==pRen->fe.cfFormat
  191.                 && (pFE->tymed & pRen->fe.tymed)
  192.                 && pFE->dwAspect==pRen->fe.dwAspect)
  193.                 {
  194.                 if (TYMED_ISTORAGE==pFE->tymed)
  195.                     {
  196.                     pSTM->tymed=TYMED_ISTORAGE;
  197.                     return pRen->stm.pstg->CopyTo(NULL, NULL
  198.                         , NULL, pSTM->pstg);
  199.                     }
  200.                 else
  201.                     {
  202.                     STATSTG     st;
  203.  
  204.                     pRen->stm.pstm->Stat(&st, STATFLAG_NONAME);
  205.                     pSTM->tymed=TYMED_ISTREAM;
  206.  
  207.                     return pRen->stm.pstm->CopyTo(pSTM->pstm
  208.                         , st.cbSize, NULL, NULL);
  209.                     }
  210.                 }
  211.             }
  212.         }
  213.  
  214.     return ResultFromScode(DATA_E_FORMATETC);
  215.     }
  216.  
  217.  
  218.  
  219.  
  220.  
  221.  
  222.  
  223. /*
  224.  * CImpIDataObject::QueryGetData
  225.  *
  226.  * Purpose:
  227.  *  Tests if a call to GetData with this FormatEtc will provide
  228.  *  any rendering; used like IsClipboardFormatAvailable.
  229.  *
  230.  * Parameters:
  231.  *  pFE             LPFORMATETC describing the desired data.
  232.  *
  233.  * Return Value:
  234.  *  HRESULT         NOERROR or a general error value.
  235.  */
  236.  
  237. STDMETHODIMP CImpIDataObject::QueryGetData(LPFORMATETC pFE)
  238.     {
  239.     UINT        i, cItems;
  240.     PRENDERING  pRen;
  241.     DWORD       cb;
  242.     HWND        hList;
  243.  
  244.     if (NULL==m_pObj->m_hList || NULL==pFE)
  245.         return ResultFromScode(S_FALSE);
  246.  
  247.     hList=m_pObj->m_hList;
  248.     cItems=(UINT)SendMessage(hList, LB_GETCOUNT, 0, 0L);
  249.  
  250.     for (i=0; i < cItems; i++)
  251.         {
  252.         cb=SendMessage(hList, LB_GETTEXT, i, (LPARAM)&pRen);
  253.  
  254.         if (LB_ERR!=cb)
  255.             {
  256.             /*
  257.              * Check if the requested FORMATETC is the same as one
  258.              * that we already have.
  259.              */
  260.             if (pFE->cfFormat==pRen->fe.cfFormat
  261.                 && (pFE->tymed & pRen->fe.tymed)
  262.                 && pFE->dwAspect==pRen->fe.dwAspect)
  263.                 {
  264.                 return NOERROR;
  265.                 }
  266.             }
  267.         }
  268.  
  269.     return ResultFromScode(S_FALSE);
  270.     }
  271.  
  272.  
  273.  
  274.  
  275. /*
  276.  * CImpIDataObject::SetData
  277.  *
  278.  * Purpose:
  279.  *  Places data described by a FormatEtc and living in a StgMedium
  280.  *  into the object.  The object may be responsible to clean up the
  281.  *  StgMedium before exiting.
  282.  *
  283.  * Parameters:
  284.  *  pFE             LPFORMATETC describing the data to set.
  285.  *  pSTM            LPSTGMEDIUM containing the data.
  286.  *  fRelease        BOOL indicating if this function is responsible
  287.  *                  for freeing the data.
  288.  *
  289.  * Return Value:
  290.  *  HRESULT         NOERROR or a general error value.
  291.  */
  292.  
  293. STDMETHODIMP CImpIDataObject::SetData(LPFORMATETC pFE
  294.     , LPSTGMEDIUM pSTM, BOOL fRelease)
  295.     {
  296.     PRENDERING      prn;
  297.  
  298.     //We have to remain responsible for the data.
  299.     if (!fRelease)
  300.         return ResultFromScode(E_FAIL);
  301.  
  302.     //If we're handed NULLs, that means clean out the list.
  303.     if (NULL==pFE || NULL==pSTM)
  304.         {
  305.         m_pObj->Purge();
  306.         return NOERROR;
  307.         }
  308.  
  309.     /*
  310.      * Here we take the rendering we're given and attach it to the
  311.      * end of the list.  We save the original pSTM->pUnkForRelease
  312.      * and replace it with our own such that each 'copy' of this
  313.      * data is actually just a reference count.
  314.      */
  315.  
  316.     prn=new RENDERING;
  317.  
  318.     if (NULL==prn)
  319.         return ResultFromScode(E_OUTOFMEMORY);
  320.  
  321.     prn->fe=*pFE;
  322.     prn->stm=*pSTM;
  323.     prn->pUnkOrg=pSTM->pUnkForRelease;
  324.     prn->stm.pUnkForRelease=this;
  325.  
  326.     SendMessage(m_pObj->m_hList, LB_ADDSTRING, 0, (LONG)prn);
  327.     return NOERROR;
  328.     }
  329.  
  330.  
  331.  
  332.  
  333.  
  334.  
  335. /*
  336.  * CImpIDataObject::EnumFormatEtc
  337.  *
  338.  * Purpose:
  339.  *  Returns an IEnumFORMATETC object through which the caller can
  340.  *  iterate to learn about all the data formats this object can
  341.  *  provide through either GetData[Here] or SetData.
  342.  *
  343.  * Parameters:
  344.  *  dwDir           DWORD describing a data direction, either
  345.  *                  DATADIR_SET or DATADIR_GET.
  346.  *  ppEnum          LPENUMFORMATETC * in which to return the
  347.  *                  pointer to the enumerator.
  348.  *
  349.  * Return Value:
  350.  *  HRESULT         NOERROR or a general error value.
  351.  */
  352.  
  353. STDMETHODIMP CImpIDataObject::EnumFormatEtc(DWORD dwDir
  354.     , LPENUMFORMATETC *ppEnum)
  355.     {
  356.     PCEnumFormatEtc     pEnum;
  357.  
  358.     *ppEnum=NULL;
  359.  
  360.     /*
  361.      * From an external point of view there are no SET formats,
  362.      * because we want to allow the user of this component object
  363.      * to be able to stuff ANY format in via Set.  Only external
  364.      * users will call EnumFormatEtc and they can only Get.
  365.      */
  366.  
  367.     switch (dwDir)
  368.         {
  369.         case DATADIR_GET:
  370.              pEnum=new CEnumFormatEtc(m_pUnkOuter);
  371.              break;
  372.  
  373.         case DATADIR_SET:
  374.         default:
  375.             pEnum=NULL;
  376.             break;
  377.         }
  378.  
  379.     if (NULL==pEnum)
  380.         return ResultFromScode(E_FAIL);
  381.     else
  382.         {
  383.         //Let the enumerator copy our format list.
  384.         if (!pEnum->Init(m_pObj->m_hList))
  385.             {
  386.             delete pEnum;
  387.             return ResultFromScode(E_FAIL);
  388.             }
  389.  
  390.         pEnum->AddRef();
  391.         }
  392.  
  393.     *ppEnum=pEnum;
  394.     return NOERROR;
  395.     }
  396.  
  397.  
  398.  
  399.  
  400.  
  401. /*
  402.  * CImpIDataObject::GetCanonicalFormatEtc
  403.  * CImpIDataObject::DAdvise
  404.  * CImpIDataObject::DUnadvise
  405.  * CImpIDataObject::EnumDAdvise
  406.  *
  407.  * Trivial member functions.
  408.  */
  409.  
  410. STDMETHODIMP CImpIDataObject::GetCanonicalFormatEtc
  411.     (LPFORMATETC pFEIn, LPFORMATETC pFEOut)
  412.     {
  413.     return ResultFromScode(DATA_S_SAMEFORMATETC);
  414.     }
  415.  
  416. STDMETHODIMP CImpIDataObject::DAdvise(LPFORMATETC pFE
  417.     , DWORD dwFlags, LPADVISESINK pIAdviseSink, LPDWORD pdwConn)
  418.     {
  419.     return ResultFromScode(E_FAIL);
  420.     }
  421.  
  422. STDMETHODIMP CImpIDataObject::DUnadvise(DWORD dwConn)
  423.     {
  424.     return ResultFromScode(E_FAIL);
  425.     }
  426.  
  427. STDMETHODIMP CImpIDataObject::EnumDAdvise(LPENUMSTATDATA *ppEnum)
  428.     {
  429.     return ResultFromScode(E_FAIL);
  430.     }
  431.