IDATAOBJ.CPP
/* 
 * IDATAOBJ.CPP 
 * Data Transfer Object Chapter 12 
 * 
 * Implementation of the IDataObject interface for CDataObject. 
 * 
 * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved 
 * 
 * Kraig Brockschmidt, Microsoft 
 * Internet  :  kraigb@microsoft.com 
 * Compuserve:  >INTERNET:kraigb@microsoft.com 
 */ 
 
 
#include "dataobj.h" 
 
 
/* 
 * CImpIDataObject::CImpIDataObject 
 * CImpIDataObject::~CImpIDataObject 
 * 
 * Parameters (Constructor): 
 *  pObj            PCDataObject of the object we're in. 
 *  pUnkOuter       LPUNKNOWN to which we delegate. 
 */ 
 
CImpIDataObject::CImpIDataObject(PCDataObject pObj 
    , LPUNKNOWN pUnkOuter) 
    { 
    m_cRef=0; 
    m_pObj=pObj; 
    m_pUnkOuter=pUnkOuter; 
    return; 
    } 
 
CImpIDataObject::~CImpIDataObject(void) 
    { 
    return; 
    } 
 
 
 
/* 
 * CImpIDataObject::QueryInterface 
 * CImpIDataObject::AddRef 
 * CImpIDataObject::Release 
 * 
 * Purpose: 
 *  IUnknown members for CImpIDataObject object. 
 */ 
 
STDMETHODIMP CImpIDataObject::QueryInterface(REFIID riid, PPVOID ppv) 
    { 
    return m_pUnkOuter->QueryInterface(riid, ppv); 
    } 
 
 
STDMETHODIMP_(ULONG) CImpIDataObject::AddRef(void) 
    { 
    ++m_cRef; 
    return m_pUnkOuter->AddRef(); 
    } 
 
STDMETHODIMP_(ULONG) CImpIDataObject::Release(void) 
    { 
    --m_cRef; 
    return m_pUnkOuter->Release(); 
    } 
 
 
 
 
 
/* 
 * CImpIDataObject::GetData 
 * 
 * Purpose: 
 *  Retrieves data described by a specific FormatEtc into a StgMedium 
 *  allocated by this function.  Used like GetClipboardData. 
 * 
 * Parameters: 
 *  pFE             LPFORMATETC describing the desired data. 
 *  pSTM            LPSTGMEDIUM in which to return the data. 
 * 
 * Return Value: 
 *  HRESULT         NOERROR or a general error value. 
 */ 
 
STDMETHODIMP CImpIDataObject::GetData(LPFORMATETC pFE 
    , LPSTGMEDIUM pSTM) 
    { 
    UINT        i, cItems; 
    PRENDERING  pRen; 
    DWORD       cb; 
    HWND        hList; 
 
    if (NULL==m_pObj->m_hList || NULL==pFE || NULL==pSTM) 
        return ResultFromScode(DATA_E_FORMATETC); 
 
    hList=m_pObj->m_hList; 
    cItems=(UINT)SendMessage(hList, LB_GETCOUNT, 0, 0L); 
 
    for (i=0; i < cItems; i++) 
        { 
        cb=SendMessage(hList, LB_GETTEXT, i, (LPARAM)&pRen); 
 
        if (LB_ERR!=cb) 
            { 
            /* 
             * Check if the requested FORMATETC is the same as one 
             * that we already have. If so, then copy that STGMEDIUM 
             * to pSTM and AddRef ourselves for pUnkForRelease. 
             */ 
            if (pFE->cfFormat==pRen->fe.cfFormat 
                && (pFE->tymed & pRen->fe.tymed) 
                && pFE->dwAspect==pRen->fe.dwAspect) 
                { 
                /* 
                 * ReleaseStgMedium will Release both storage 
                 * and stream elements regardless of the value 
                 * of pUnkForRelease, so we have to AddRef the 
                 * element and bump our own ref count here. 
                 */ 
                if (TYMED_ISTORAGE==pRen->fe.tymed) 
                      pRen->stm.pstg->AddRef(); 
 
                if (TYMED_ISTREAM==pRen->fe.tymed) 
                      pRen->stm.pstm->AddRef(); 
 
                *pSTM=pRen->stm; 
                AddRef(); 
                return NOERROR; 
                } 
            } 
        } 
 
    return ResultFromScode(DATA_E_FORMATETC); 
    } 
 
 
 
/* 
 * CImpIDataObject::GetDataHere 
 * 
 * Purpose: 
 *  Copies a piece of data in this data object to another 
 *  STGMEDIUM.  This is only supported for TYMED_ISTORAGE 
 *  and TYMED_ISTREAM. 
 * 
 * Parameters: 
 *  pFE             LPFORMATETC describing the desired data. 
 *  pSTM            LPSTGMEDIUM pointing to the medium into which 
 *                  we copy. 
 * 
 * Return Value: 
 *  HRESULT         NOERROR or a general error value. 
 */ 
 
STDMETHODIMP CImpIDataObject::GetDataHere(LPFORMATETC pFE 
    , LPSTGMEDIUM pSTM) 
    { 
    UINT        i, cItems; 
    PRENDERING  pRen; 
    DWORD       cb; 
    HWND        hList; 
 
    if (NULL==m_pObj->m_hList || NULL==pFE || NULL==pSTM) 
        return ResultFromScode(DATA_E_FORMATETC); 
 
    //We only support IStorage and IStream 
    if (!(TYMED_ISTORAGE & pFE->tymed) 
        && !(TYMED_ISTREAM & pFE->tymed)) 
        return ResultFromScode(DATA_E_FORMATETC); 
 
    hList=m_pObj->m_hList; 
    cItems=(UINT)SendMessage(hList, LB_GETCOUNT, 0, 0L); 
 
    for (i=0; i < cItems; i++) 
        { 
        cb=SendMessage(hList, LB_GETTEXT, i, (LPARAM)&pRen); 
 
        if (LB_ERR!=cb) 
            { 
            /* 
             * When we find a matching FORMATETC, we know we're 
             * only looking for IStorage or IStream (we checked 
             * above), so use IStorage::CopyTo or IStream::CopyTo 
             * to make the copy. 
             */ 
            if (pFE->cfFormat==pRen->fe.cfFormat 
                && (pFE->tymed & pRen->fe.tymed) 
                && pFE->dwAspect==pRen->fe.dwAspect) 
                { 
                if (TYMED_ISTORAGE==pFE->tymed) 
                    { 
                    pSTM->tymed=TYMED_ISTORAGE; 
                    return pRen->stm.pstg->CopyTo(NULL, NULL 
                        , NULL, pSTM->pstg); 
                    } 
                else 
                    { 
                    STATSTG     st; 
 
                    pRen->stm.pstm->Stat(&st, STATFLAG_NONAME); 
                    pSTM->tymed=TYMED_ISTREAM; 
 
                    return pRen->stm.pstm->CopyTo(pSTM->pstm 
                        , st.cbSize, NULL, NULL); 
                    } 
                } 
            } 
        } 
 
    return ResultFromScode(DATA_E_FORMATETC); 
    } 
 
 
 
 
 
 
 
/* 
 * CImpIDataObject::QueryGetData 
 * 
 * Purpose: 
 *  Tests if a call to GetData with this FormatEtc will provide 
 *  any rendering; used like IsClipboardFormatAvailable. 
 * 
 * Parameters: 
 *  pFE             LPFORMATETC describing the desired data. 
 * 
 * Return Value: 
 *  HRESULT         NOERROR or a general error value. 
 */ 
 
STDMETHODIMP CImpIDataObject::QueryGetData(LPFORMATETC pFE) 
    { 
    UINT        i, cItems; 
    PRENDERING  pRen; 
    DWORD       cb; 
    HWND        hList; 
 
    if (NULL==m_pObj->m_hList || NULL==pFE) 
        return ResultFromScode(S_FALSE); 
 
    hList=m_pObj->m_hList; 
    cItems=(UINT)SendMessage(hList, LB_GETCOUNT, 0, 0L); 
 
    for (i=0; i < cItems; i++) 
        { 
        cb=SendMessage(hList, LB_GETTEXT, i, (LPARAM)&pRen); 
 
        if (LB_ERR!=cb) 
            { 
            /* 
             * Check if the requested FORMATETC is the same as one 
             * that we already have. 
             */ 
            if (pFE->cfFormat==pRen->fe.cfFormat 
                && (pFE->tymed & pRen->fe.tymed) 
                && pFE->dwAspect==pRen->fe.dwAspect) 
                { 
                return NOERROR; 
                } 
            } 
        } 
 
    return ResultFromScode(S_FALSE); 
    } 
 
 
 
 
/* 
 * CImpIDataObject::SetData 
 * 
 * Purpose: 
 *  Places data described by a FormatEtc and living in a StgMedium 
 *  into the object.  The object may be responsible to clean up the 
 *  StgMedium before exiting. 
 * 
 * Parameters: 
 *  pFE             LPFORMATETC describing the data to set. 
 *  pSTM            LPSTGMEDIUM containing the data. 
 *  fRelease        BOOL indicating if this function is responsible 
 *                  for freeing the data. 
 * 
 * Return Value: 
 *  HRESULT         NOERROR or a general error value. 
 */ 
 
STDMETHODIMP CImpIDataObject::SetData(LPFORMATETC pFE 
    , LPSTGMEDIUM pSTM, BOOL fRelease) 
    { 
    PRENDERING      prn; 
 
    //We have to remain responsible for the data. 
    if (!fRelease) 
        return ResultFromScode(E_FAIL); 
 
    //If we're handed NULLs, that means clean out the list. 
    if (NULL==pFE || NULL==pSTM) 
        { 
        m_pObj->Purge(); 
        return NOERROR; 
        } 
 
    /* 
     * Here we take the rendering we're given and attach it to the 
     * end of the list.  We save the original pSTM->pUnkForRelease 
     * and replace it with our own such that each 'copy' of this 
     * data is actually just a reference count. 
     */ 
 
    prn=new RENDERING; 
 
    if (NULL==prn) 
        return ResultFromScode(E_OUTOFMEMORY); 
 
    prn->fe=*pFE; 
    prn->stm=*pSTM; 
    prn->pUnkOrg=pSTM->pUnkForRelease; 
    prn->stm.pUnkForRelease=this; 
 
    SendMessage(m_pObj->m_hList, LB_ADDSTRING, 0, (LONG)prn); 
    return NOERROR; 
    } 
 
 
 
 
 
 
/* 
 * CImpIDataObject::EnumFormatEtc 
 * 
 * Purpose: 
 *  Returns an IEnumFORMATETC object through which the caller can 
 *  iterate to learn about all the data formats this object can 
 *  provide through either GetData[Here] or SetData. 
 * 
 * Parameters: 
 *  dwDir           DWORD describing a data direction, either 
 *                  DATADIR_SET or DATADIR_GET. 
 *  ppEnum          LPENUMFORMATETC * in which to return the 
 *                  pointer to the enumerator. 
 * 
 * Return Value: 
 *  HRESULT         NOERROR or a general error value. 
 */ 
 
STDMETHODIMP CImpIDataObject::EnumFormatEtc(DWORD dwDir 
    , LPENUMFORMATETC *ppEnum) 
    { 
    PCEnumFormatEtc     pEnum; 
 
    *ppEnum=NULL; 
 
    /* 
     * From an external point of view there are no SET formats, 
     * because we want to allow the user of this component object 
     * to be able to stuff ANY format in via Set.  Only external 
     * users will call EnumFormatEtc and they can only Get. 
     */ 
 
    switch (dwDir) 
        { 
        case DATADIR_GET: 
             pEnum=new CEnumFormatEtc(m_pUnkOuter); 
             break; 
 
        case DATADIR_SET: 
        default: 
            pEnum=NULL; 
            break; 
        } 
 
    if (NULL==pEnum) 
        return ResultFromScode(E_FAIL); 
    else 
        { 
        //Let the enumerator copy our format list. 
        if (!pEnum->Init(m_pObj->m_hList)) 
            { 
            delete pEnum; 
            return ResultFromScode(E_FAIL); 
            } 
 
        pEnum->AddRef(); 
        } 
 
    *ppEnum=pEnum; 
    return NOERROR; 
    } 
 
 
 
 
 
/* 
 * CImpIDataObject::GetCanonicalFormatEtc 
 * CImpIDataObject::DAdvise 
 * CImpIDataObject::DUnadvise 
 * CImpIDataObject::EnumDAdvise 
 * 
 * Trivial member functions. 
 */ 
 
STDMETHODIMP CImpIDataObject::GetCanonicalFormatEtc 
    (LPFORMATETC pFEIn, LPFORMATETC pFEOut) 
    { 
    return ResultFromScode(DATA_S_SAMEFORMATETC); 
    } 
 
STDMETHODIMP CImpIDataObject::DAdvise(LPFORMATETC pFE 
    , DWORD dwFlags, LPADVISESINK pIAdviseSink, LPDWORD pdwConn) 
    { 
    return ResultFromScode(E_FAIL); 
    } 
 
STDMETHODIMP CImpIDataObject::DUnadvise(DWORD dwConn) 
    { 
    return ResultFromScode(E_FAIL); 
    } 
 
STDMETHODIMP CImpIDataObject::EnumDAdvise(LPENUMSTATDATA *ppEnum) 
    { 
    return ResultFromScode(E_FAIL); 
    }