/************************************************************************** THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. Copyright 1998 Microsoft Corporation. All Rights Reserved. **************************************************************************/ /************************************************************************** File: DataObj.cpp Description: CDataObject implementation. **************************************************************************/ /************************************************************************** #include statements **************************************************************************/ #include "DataObj.h" /************************************************************************** global variables **************************************************************************/ /************************************************************************** CDataObject::CDataObject() **************************************************************************/ CDataObject::CDataObject(CShellFolder *psfParent, LPCITEMIDLIST *aPidls, UINT uItemCount) { g_DllRefCount++; m_uItemCount = 0; m_psfParent = psfParent; if(m_psfParent) m_psfParent->AddRef(); m_ObjRefCount = 1; m_aPidls = NULL; SHGetMalloc(&m_pMalloc); if(!m_pMalloc) { delete this; return; } m_pPidlMgr = new CPidlMgr(); m_uItemCount = uItemCount; AllocPidlTable(uItemCount); if(m_aPidls) { FillPidlTable(aPidls, uItemCount); } m_cfPrivateData = RegisterClipboardFormat(CFSTR_SAMPVIEWDATA); m_cfShellIDList = RegisterClipboardFormat(CFSTR_SHELLIDLIST); m_cFormatEtc = 2; m_pFormatEtc = new FORMATETC[m_cFormatEtc]; SETDefFormatEtc(m_pFormatEtc[0], m_cfPrivateData, TYMED_HGLOBAL); SETDefFormatEtc(m_pFormatEtc[1], m_cfShellIDList, TYMED_HGLOBAL); m_iCurrent = 0; } /************************************************************************** CDataObject::~CDataObject() **************************************************************************/ CDataObject::~CDataObject() { if(m_psfParent) m_psfParent->Release(); g_DllRefCount--; //make sure the pidls are freed if(m_aPidls && m_pMalloc) { FreePidlTable(); } if(m_pPidlMgr) delete m_pPidlMgr; if(m_pMalloc) m_pMalloc->Release(); //delete [] m_pFormatEtc; delete m_pFormatEtc; } /////////////////////////////////////////////////////////////////////////// // // IUnknown Implementation // /************************************************************************** CDataObject::QueryInterface **************************************************************************/ STDMETHODIMP CDataObject::QueryInterface( REFIID riid, LPVOID *ppReturn) { *ppReturn = NULL; if(IsEqualIID(riid, IID_IUnknown)) { *ppReturn = (LPUNKNOWN)(LPCONTEXTMENU)this; } else if(IsEqualIID(riid, IID_IDataObject)) { *ppReturn = (LPDATAOBJECT)this; } else if(IsEqualIID(riid, IID_IEnumFORMATETC)) { *ppReturn = (LPENUMFORMATETC)this; } if(*ppReturn) { (*(LPUNKNOWN*)ppReturn)->AddRef(); return S_OK; } return E_NOINTERFACE; } /************************************************************************** CDataObject::AddRef **************************************************************************/ STDMETHODIMP_(DWORD) CDataObject::AddRef() { return ++m_ObjRefCount; } /************************************************************************** CDataObject::Release **************************************************************************/ STDMETHODIMP_(DWORD) CDataObject::Release() { if(--m_ObjRefCount == 0) delete this; return m_ObjRefCount; } /////////////////////////////////////////////////////////////////////////// // // IDataObject Implementation // /************************************************************************** CDataObject::GetData() **************************************************************************/ STDMETHODIMP CDataObject::GetData(LPFORMATETC pFE, LPSTGMEDIUM pStgMedium) { if(pFE->cfFormat == m_cfPrivateData) { LPITEMIDLIST pidlParent; pidlParent = m_psfParent->CreateFQPidl(NULL); if(pidlParent) { pStgMedium->hGlobal = CreatePrivateClipboardData(pidlParent, m_aPidls, m_uItemCount, FALSE); m_pPidlMgr->Delete(pidlParent); if(pStgMedium->hGlobal) { pStgMedium->tymed = TYMED_HGLOBAL; return S_OK; } } return E_OUTOFMEMORY; } else if(pFE->cfFormat == m_cfShellIDList) { LPITEMIDLIST pidlParent; pidlParent = m_psfParent->CreateFQPidl(NULL); if(pidlParent) { pStgMedium->hGlobal = CreateShellIDList(pidlParent, m_aPidls, m_uItemCount); m_pPidlMgr->Delete(pidlParent); if(pStgMedium->hGlobal) { pStgMedium->tymed = TYMED_HGLOBAL; return S_OK; } } return E_OUTOFMEMORY; } return E_INVALIDARG; } /************************************************************************** CDataObject::GetDataHere() **************************************************************************/ STDMETHODIMP CDataObject::GetDataHere (LPFORMATETC pFE, LPSTGMEDIUM pStgMedium) { return E_NOTIMPL; } /************************************************************************** CDataObject::QueryGetData() **************************************************************************/ STDMETHODIMP CDataObject::QueryGetData(LPFORMATETC pFE) { BOOL fReturn = FALSE; /* Check the aspects we support. Implementations of this object will only support DVASPECT_CONTENT. */ if(!(DVASPECT_CONTENT & pFE->dwAspect)) return DV_E_DVASPECT; if(pFE->cfFormat == m_cfPrivateData) { // // Now check for an appropriate TYMED. // for(UINT i = 0; i < m_cFormatEtc; i++) { fReturn |= m_pFormatEtc[i].tymed & pFE->tymed; } } if(pFE->cfFormat == m_cfShellIDList) { // // Now check for an appropriate TYMED. // for(UINT i = 0; i < m_cFormatEtc; i++) { fReturn |= m_pFormatEtc[i].tymed & pFE->tymed; } } return (fReturn ? S_OK : DV_E_TYMED); } /************************************************************************** CDataObject::GetCanonicalFormatEtc() **************************************************************************/ STDMETHODIMP CDataObject::GetCanonicalFormatEtc(LPFORMATETC pFEIn, LPFORMATETC pFEOut) { if(NULL == pFEOut) return E_INVALIDARG; pFEOut->ptd = NULL; return DATA_S_SAMEFORMATETC; } /************************************************************************** CDataObject::EnumFormatEtc() **************************************************************************/ STDMETHODIMP CDataObject::EnumFormatEtc( DWORD dwDirection, IEnumFORMATETC** ppEFE) { *ppEFE = NULL; if(DATADIR_GET == dwDirection) { return this->QueryInterface(IID_IEnumFORMATETC, (LPVOID*)ppEFE); } return E_NOTIMPL; } /************************************************************************** CDataObject::SetData() **************************************************************************/ STDMETHODIMP CDataObject::SetData( LPFORMATETC pFE, LPSTGMEDIUM pStgMedium, BOOL fRelease) { return E_NOTIMPL; } /************************************************************************** CDataObject::DAdvise() **************************************************************************/ STDMETHODIMP CDataObject::DAdvise( LPFORMATETC pFE, DWORD advf, IAdviseSink *ppAdviseSink, LPDWORD pdwConnection) { return E_NOTIMPL; } /************************************************************************** CDataObject::DUnadvise() **************************************************************************/ STDMETHODIMP CDataObject::DUnadvise(DWORD dwConnection) { return E_NOTIMPL; } /************************************************************************** CDataObject::EnumDAdvise() **************************************************************************/ STDMETHODIMP CDataObject::EnumDAdvise(IEnumSTATDATA** ppEnumAdvise) { return E_NOTIMPL; } /////////////////////////////////////////////////////////////////////////// // // IEnumFORMATETC Implementation // STDMETHODIMP CDataObject::Next(ULONG uRequested, LPFORMATETC pFormatEtc, ULONG* pulFetched) { if(NULL == m_pFormatEtc) return S_FALSE; if(NULL != pulFetched) *pulFetched = 0L; if(NULL == pFormatEtc) return E_INVALIDARG; ULONG uFetched; for(uFetched = 0; m_iCurrent < m_cFormatEtc && uRequested > uFetched; uFetched++) { *pFormatEtc++ = m_pFormatEtc[m_iCurrent++]; } if(NULL != pulFetched) *pulFetched = uFetched; return ((uFetched == uRequested) ? S_OK : S_FALSE); } /************************************************************************** CDataObject::Skip() **************************************************************************/ STDMETHODIMP CDataObject::Skip(ULONG cSkip) { if((m_iCurrent + cSkip) >= m_cFormatEtc) return S_FALSE; m_iCurrent += cSkip; return S_OK; } /************************************************************************** CDataObject::Reset() **************************************************************************/ STDMETHODIMP CDataObject::Reset(void) { m_iCurrent = 0; return S_OK; } /************************************************************************** CDataObject::Clone() **************************************************************************/ STDMETHODIMP CDataObject::Clone(LPENUMFORMATETC* ppEnum) { CDataObject* pNew; *ppEnum = NULL; // Create the clone. pNew = new CDataObject(m_psfParent, (LPCITEMIDLIST*)m_aPidls, m_uItemCount); if (NULL == pNew) return E_OUTOFMEMORY; pNew->m_iCurrent = m_iCurrent; *ppEnum = pNew; return S_OK; } /////////////////////////////////////////////////////////////////////////// // // private and utility methods // /************************************************************************** CDataObject::AllocPidlTable() **************************************************************************/ BOOL CDataObject::AllocPidlTable(DWORD dwEntries) { m_aPidls = (LPITEMIDLIST*)m_pMalloc->Alloc(dwEntries * sizeof(LPITEMIDLIST)); if(m_aPidls) { //set all of the entries to NULL ZeroMemory(m_aPidls, dwEntries * sizeof(LPITEMIDLIST)); } return (m_aPidls != NULL); } /************************************************************************** CDataObject::FreePidlTable() **************************************************************************/ VOID CDataObject::FreePidlTable(VOID) { if(m_aPidls && m_pPidlMgr) { UINT i; for(i = 0; i < m_uItemCount; i++) m_pPidlMgr->Delete(m_aPidls[i]); m_pMalloc->Free(m_aPidls); m_aPidls = NULL; } } /************************************************************************** CDataObject::FillPidlTable() **************************************************************************/ BOOL CDataObject::FillPidlTable(LPCITEMIDLIST *aPidls, UINT uItemCount) { if(m_aPidls) { if(m_pPidlMgr) { UINT i; for(i = 0; i < uItemCount; i++) { m_aPidls[i] = m_pPidlMgr->Copy(aPidls[i]); } return TRUE; } } return FALSE; }