DATAOBJ.CPP
//******************************************************************************************* 
// 
// Filename : DataObj.cpp 
// 
//Implementation file for CObjFormats and CCabObj 
// 
// Copyright 1994 - 1998 Microsoft Corporation. All rights reserved 
// 
//******************************************************************************************* 
 
#include "pch.h" 
 
#include "thisdll.h" 
 
#include "folder.h" 
#include "dataobj.h" 
 
#include "cabitms.h" 
 
UINT CCabObj::s_uFileGroupDesc = 0; 
UINT CCabObj::s_uFileContents = 0; 
 
 
class CObjFormats : public IEnumFORMATETC 
{ 
public: 
CObjFormats(UINT cfmt, const FORMATETC afmt[]); 
~CObjFormats(); 
 
    // *** IUnknown methods *** 
    STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj); 
    STDMETHODIMP_(ULONG) AddRef(); 
    STDMETHODIMP_(ULONG) Release(); 
 
    // *** IEnumFORMATETC methods *** 
    STDMETHODIMP Next(ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed); 
    STDMETHODIMP Skip(ULONG celt); 
    STDMETHODIMP Reset(); 
    STDMETHODIMP Clone(IEnumFORMATETC ** ppenum); 
 
private: 
CRefCount m_cRef; 
 
CRefDll m_cRefDll; 
 
UINT m_iFmt; 
UINT m_cFmt; 
FORMATETC *m_aFmt; 
} ; 
 
 
CObjFormats::CObjFormats(UINT cfmt, const FORMATETC afmt[]) 
{ 
m_iFmt = 0; 
m_cFmt = cfmt; 
m_aFmt = new FORMATETC[cfmt]; 
 
if (m_aFmt) 
{ 
CopyMemory(m_aFmt, afmt, cfmt*sizeof(afmt[0])); 
} 
} 
 
 
CObjFormats::~CObjFormats() 
{ 
if (m_aFmt) 
{ 
delete m_aFmt; 
} 
} 
 
 
// *** IUnknown methods *** 
STDMETHODIMP CObjFormats::QueryInterface( 
   REFIID riid,  
   LPVOID FAR* ppvObj) 
{ 
*ppvObj = NULL; 
 
if (!m_aFmt) 
{ 
return(E_OUTOFMEMORY); 
} 
 
LPUNKNOWN pObj; 
  
if (riid == IID_IUnknown) 
{ 
pObj = (IUnknown*)((IEnumFORMATETC*)this);  
} 
else if (riid == IID_IEnumFORMATETC) 
{ 
pObj = (IUnknown*)((IEnumFORMATETC*)this);  
} 
else 
{ 
   return(E_NOINTERFACE); 
} 
 
pObj->AddRef(); 
*ppvObj = pObj; 
 
return(NOERROR); 
} 
 
 
STDMETHODIMP_(ULONG) CObjFormats::AddRef(void) 
{ 
return(m_cRef.AddRef()); 
} 
 
 
STDMETHODIMP_(ULONG) CObjFormats::Release(void) 
{ 
if (!m_cRef.Release()) 
{ 
   delete this; 
return(0); 
} 
 
return(m_cRef.GetRef()); 
} 
 
 
STDMETHODIMP CObjFormats::Next(ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed) 
{ 
UINT cfetch; 
HRESULT hres = S_FALSE;// assume less numbers 
 
if (m_iFmt < m_cFmt) 
{ 
cfetch = m_cFmt - m_iFmt; 
if (cfetch >= celt) 
{ 
cfetch = celt; 
hres = S_OK; 
} 
 
CopyMemory(rgelt, &m_aFmt[m_iFmt], cfetch * sizeof(FORMATETC)); 
m_iFmt += cfetch; 
} 
else 
{ 
cfetch = 0; 
} 
 
if (pceltFethed) 
{ 
*pceltFethed = cfetch; 
} 
 
return hres; 
} 
 
STDMETHODIMP CObjFormats::Skip(ULONG celt) 
{ 
m_iFmt += celt; 
if (m_iFmt > m_cFmt) 
{ 
m_iFmt = m_cFmt; 
return S_FALSE; 
} 
return S_OK; 
} 
 
STDMETHODIMP CObjFormats::Reset() 
{ 
m_iFmt = 0; 
return S_OK; 
} 
 
STDMETHODIMP CObjFormats::Clone(IEnumFORMATETC ** ppenum) 
{ 
return(E_NOTIMPL); 
} 
 
CCabObj::CCabObj(HWND hwndOwner, CCabFolder *pcf, LPCABITEM *apit, UINT cpit) 
: m_lSel(8), m_lContents(NULL) 
{ 
m_pcfHere = pcf; 
pcf->AddRef(); 
 
m_hwndOwner = hwndOwner; 
m_lSel.AddItems(apit, cpit); 
} 
 
 
CCabObj::~CCabObj() 
{ 
m_pcfHere->Release(); 
} 
 
 
// *** IUnknown methods *** 
STDMETHODIMP CCabObj::QueryInterface( 
   REFIID riid,  
   LPVOID FAR* ppvObj) 
{ 
*ppvObj = NULL; 
 
if (m_lSel.GetState() == CCabItemList::State_OutOfMem) 
{ 
return(E_OUTOFMEMORY); 
} 
 
LPUNKNOWN pObj; 
  
if (riid == IID_IUnknown) 
{ 
pObj = (IUnknown*)((IDataObject*)this);  
} 
else if (riid == IID_IDataObject) 
{ 
pObj = (IUnknown*)((IDataObject*)this);  
} 
else 
{ 
   return(E_NOINTERFACE); 
} 
 
pObj->AddRef(); 
*ppvObj = pObj; 
 
return(NOERROR); 
} 
 
 
STDMETHODIMP_(ULONG) CCabObj::AddRef(void) 
{ 
return(m_cRef.AddRef()); 
} 
 
 
STDMETHODIMP_(ULONG) CCabObj::Release(void) 
{ 
if (!m_cRef.Release()) 
{ 
   delete this; 
return(0); 
} 
 
return(m_cRef.GetRef()); 
} 
 
 
STDMETHODIMP CCabObj::GetData(FORMATETC *pfmt, STGMEDIUM *pmedium) 
{ 
if (!InitFileGroupDesc()) 
{ 
return(E_UNEXPECTED); 
} 
 
if (pfmt->cfFormat == s_uFileGroupDesc) 
{ 
if (pfmt->ptd==NULL && (pfmt->dwAspect&DVASPECT_CONTENT) && pfmt->lindex==-1 
&& (pfmt->tymed&TYMED_HGLOBAL)) 
{ 
int cItems = m_lSel.GetCount(); 
if (cItems < 1) 
{ 
return(E_UNEXPECTED); 
} 
 
FILEGROUPDESCRIPTOR *pfgd = (FILEGROUPDESCRIPTOR *)GlobalAlloc(GMEM_FIXED, 
sizeof(FILEGROUPDESCRIPTOR) + (cItems-1)*sizeof(FILEDESCRIPTOR)); 
if (!pfgd) 
{ 
return(E_OUTOFMEMORY); 
} 
 
pfgd->cItems = cItems; 
for (--cItems; cItems>=0; --cItems) 
{ 
LPCABITEM pItem = m_lSel[cItems]; 
 
pfgd->fgd[cItems].dwFlags = FD_ATTRIBUTES|FD_WRITESTIME|FD_FILESIZE; 
pfgd->fgd[cItems].dwFileAttributes = pItem->uFileAttribs; 
DosDateTimeToFileTime(pItem->uFileDate, pItem->uFileTime, 
&pfgd->fgd[cItems].ftLastWriteTime); 
pfgd->fgd[cItems].nFileSizeHigh = 0; 
pfgd->fgd[cItems].nFileSizeLow  = pItem->dwFileSize; 
lstrcpyn(pfgd->fgd[cItems].cFileName, pItem->szName, 
sizeof(pfgd->fgd[cItems].cFileName)); 
} 
 
pmedium->tymed = TYMED_HGLOBAL; 
pmedium->hGlobal = (HGLOBAL)pfgd; 
pmedium->pUnkForRelease = NULL; 
 
return(NOERROR); 
} 
 
return(E_INVALIDARG); 
} 
 
if (!InitFileContents()) 
{ 
return(E_UNEXPECTED); 
} 
 
if (pfmt->cfFormat == s_uFileContents) 
{ 
if (pfmt->ptd==NULL && (pfmt->dwAspect&DVASPECT_CONTENT) 
&& (pfmt->tymed&TYMED_HGLOBAL)) 
{ 
int cItems = m_lSel.GetCount(); 
if (pfmt->lindex >= cItems) 
{ 
return(E_INVALIDARG); 
} 
 
HRESULT hRes = InitContents(); 
if (FAILED(hRes)) 
{ 
return(hRes); 
} 
 
if (!m_lContents[pfmt->lindex]) 
{ 
return(E_OUTOFMEMORY); 
} 
 
// TODO: Maybe if we run out of memory I will just return an IStream for each 
// file and take the time hit to extract each one separately 
pmedium->tymed = TYMED_HGLOBAL; 
pmedium->hGlobal = m_lContents[pfmt->lindex]; 
// We will delete these globals when we go away 
pmedium->pUnkForRelease = (IDataObject*)this; 
AddRef(); 
 
return(NOERROR); 
} 
 
return(E_INVALIDARG); 
} 
 
return(E_NOTIMPL); 
} 
 
 
STDMETHODIMP CCabObj::GetDataHere(FORMATETC *pformatetc, STGMEDIUM *pmedium) 
{ 
return(E_NOTIMPL); 
} 
 
 
STDMETHODIMP CCabObj::QueryGetData(FORMATETC *pfmt) 
{ 
if (!InitFileGroupDesc()) 
{ 
return(E_UNEXPECTED); 
} 
 
if (pfmt->cfFormat == s_uFileGroupDesc) 
{ 
if (pfmt->ptd==NULL && (pfmt->dwAspect&DVASPECT_CONTENT) && pfmt->lindex==-1 
&& (pfmt->tymed&TYMED_HGLOBAL)) 
{ 
return(S_OK); 
} 
 
return(E_INVALIDARG); 
} 
 
if (!InitFileContents()) 
{ 
return(E_UNEXPECTED); 
} 
 
if (pfmt->cfFormat == s_uFileContents) 
{ 
if (pfmt->ptd==NULL && (pfmt->dwAspect&DVASPECT_CONTENT) 
&& (pfmt->tymed&TYMED_HGLOBAL)) 
{ 
return(S_OK); 
} 
 
return(E_INVALIDARG); 
} 
 
return(E_NOTIMPL); 
} 
 
 
STDMETHODIMP CCabObj::GetCanonicalFormatEtc(FORMATETC *pformatectIn, FORMATETC *pformatetcOut) 
{ 
return(E_NOTIMPL); 
} 
 
 
STDMETHODIMP CCabObj::SetData(FORMATETC *pformatetc, STGMEDIUM *pmedium, BOOL fRelease) 
{ 
return(E_NOTIMPL); 
} 
 
 
STDMETHODIMP CCabObj::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc) 
{ 
if (!InitFileGroupDesc() || !InitFileContents()) 
{ 
return(E_UNEXPECTED); 
} 
 
    FORMATETC fmte[] = { 
        {(USHORT)s_uFileContents,  NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }, 
        {(USHORT)s_uFileGroupDesc, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }, 
    }; 
 
CObjFormats *pFmts = new CObjFormats(2, fmte); 
if (!pFmts) 
{ 
return(E_OUTOFMEMORY); 
} 
 
pFmts->AddRef(); 
HRESULT hRes = pFmts->QueryInterface(IID_IEnumFORMATETC, (LPVOID *)ppenumFormatEtc); 
pFmts->Release(); 
 
return(hRes); 
} 
 
 
STDMETHODIMP CCabObj::DAdvise(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, 
DWORD *pdwConnection) 
{ 
return(E_NOTIMPL); 
} 
 
 
STDMETHODIMP CCabObj::DUnadvise(DWORD dwConnection) 
{ 
return(E_NOTIMPL); 
} 
 
 
STDMETHODIMP CCabObj::EnumDAdvise(IEnumSTATDATA **ppenumAdvise) 
{ 
return(E_NOTIMPL); 
} 
 
 
BOOL CCabObj::InitFileGroupDesc() 
{ 
if (s_uFileGroupDesc) 
{ 
return(TRUE); 
} 
 
s_uFileGroupDesc = RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR); 
return(s_uFileGroupDesc != 0); 
} 
 
 
BOOL CCabObj::InitFileContents() 
{ 
if (s_uFileContents) 
{ 
return(TRUE); 
} 
 
s_uFileContents = RegisterClipboardFormat(CFSTR_FILECONTENTS); 
return(s_uFileContents != 0); 
} 
 
 
HGLOBAL * CALLBACK CCabObj::ShouldExtract(LPCSTR pszFile, DWORD dwSize, UINT date, 
UINT time, UINT attribs, LPARAM lParam) 
{ 
CCabObj *pThis = (CCabObj*)lParam; 
 
int iItem = pThis->m_lSel.FindInList(pszFile, dwSize, date, time, attribs); 
if (iItem < 0) 
{ 
return(EXTRACT_FALSE); 
} 
 
// Copy nothing for now 
return(&(pThis->m_lContents[iItem])); 
} 
 
 
HRESULT CCabObj::InitContents() 
{ 
if (m_lContents) 
{ 
return(NOERROR); 
} 
 
int iCount = m_lSel.GetCount(); 
if (iCount < 1) 
{ 
return(E_UNEXPECTED); 
} 
 
m_lContents = (HGLOBAL *)GlobalAlloc(GMEM_FIXED|GMEM_ZEROINIT, 
sizeof(HGLOBAL)*m_lSel.GetCount()); 
if (!m_lContents) 
{ 
return(E_OUTOFMEMORY); 
} 
 
char szHere[MAX_PATH]; 
if (!m_pcfHere->GetPath(szHere)) 
{ 
return(E_UNEXPECTED); 
} 
 
CCabExtract ceHere(szHere); 
 
ceHere.ExtractItems(m_hwndOwner, DIR_MEM, ShouldExtract, (LPARAM)this); 
 
return(TRUE); 
}