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);
}