/* * IEnumFORMATETC, IDataObject * * selecting and dropping objects within the shell and/or common dialogs * * Copyright 1998, 1999 <juergen.schmied@metronet.de> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include <string.h> #define COBJMACROS #define NONAMELESSUNION #include "windef.h" #include "wingdi.h" #include "pidl.h" #include "winerror.h" #include "shell32_main.h" #include "wine/debug.h" #include "undocshell.h" WINE_DEFAULT_DEBUG_CHANNEL(shell); /*********************************************************************** * IEnumFORMATETC implementation */ typedef struct { /* IUnknown fields */ IEnumFORMATETC IEnumFORMATETC_iface; LONG ref; /* IEnumFORMATETC fields */ UINT posFmt; UINT countFmt; LPFORMATETC pFmt; } IEnumFORMATETCImpl; static inline IEnumFORMATETCImpl *impl_from_IEnumFORMATETC(IEnumFORMATETC *iface) { return CONTAINING_RECORD(iface, IEnumFORMATETCImpl, IEnumFORMATETC_iface); } static HRESULT WINAPI IEnumFORMATETC_fnQueryInterface( LPENUMFORMATETC iface, REFIID riid, LPVOID* ppvObj) { IEnumFORMATETCImpl *This = impl_from_IEnumFORMATETC(iface); TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj); *ppvObj = NULL; if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumFORMATETC)) { *ppvObj = &This->IEnumFORMATETC_iface; } if(*ppvObj) { IUnknown_AddRef((IUnknown*)(*ppvObj)); TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj); return S_OK; } TRACE("-- Interface: E_NOINTERFACE\n"); return E_NOINTERFACE; } static ULONG WINAPI IEnumFORMATETC_fnAddRef(LPENUMFORMATETC iface) { IEnumFORMATETCImpl *This = impl_from_IEnumFORMATETC(iface); ULONG refCount = InterlockedIncrement(&This->ref); TRACE("(%p)->(count=%u)\n", This, refCount - 1); return refCount; } static ULONG WINAPI IEnumFORMATETC_fnRelease(LPENUMFORMATETC iface) { IEnumFORMATETCImpl *This = impl_from_IEnumFORMATETC(iface); ULONG refCount = InterlockedDecrement(&This->ref); TRACE("(%p)->(%u)\n", This, refCount + 1); if (!refCount) { TRACE(" destroying IEnumFORMATETC(%p)\n",This); SHFree (This->pFmt); HeapFree(GetProcessHeap(),0,This); return 0; } return refCount; } static HRESULT WINAPI IEnumFORMATETC_fnNext(LPENUMFORMATETC iface, ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed) { IEnumFORMATETCImpl *This = impl_from_IEnumFORMATETC(iface); UINT i; TRACE("(%p)->(%u,%p)\n", This, celt, rgelt); if(!This->pFmt)return S_FALSE; if(!rgelt) return E_INVALIDARG; if (pceltFethed) *pceltFethed = 0; for(i = 0; This->posFmt < This->countFmt && celt > i; i++) { *rgelt++ = This->pFmt[This->posFmt++]; } if (pceltFethed) *pceltFethed = i; return ((i == celt) ? S_OK : S_FALSE); } static HRESULT WINAPI IEnumFORMATETC_fnSkip(LPENUMFORMATETC iface, ULONG celt) { IEnumFORMATETCImpl *This = impl_from_IEnumFORMATETC(iface); TRACE("(%p)->(num=%u)\n", This, celt); if((This->posFmt + celt) >= This->countFmt) return S_FALSE; This->posFmt += celt; return S_OK; } static HRESULT WINAPI IEnumFORMATETC_fnReset(LPENUMFORMATETC iface) { IEnumFORMATETCImpl *This = impl_from_IEnumFORMATETC(iface); TRACE("(%p)->()\n", This); This->posFmt = 0; return S_OK; } static HRESULT WINAPI IEnumFORMATETC_fnClone(LPENUMFORMATETC iface, LPENUMFORMATETC* ppenum) { IEnumFORMATETCImpl *This = impl_from_IEnumFORMATETC(iface); TRACE("(%p)->(ppenum=%p)\n", This, ppenum); if (!ppenum) return E_INVALIDARG; *ppenum = IEnumFORMATETC_Constructor(This->countFmt, This->pFmt); if(*ppenum) IEnumFORMATETC_fnSkip(*ppenum, This->posFmt); return S_OK; } static const IEnumFORMATETCVtbl efvt = { IEnumFORMATETC_fnQueryInterface, IEnumFORMATETC_fnAddRef, IEnumFORMATETC_fnRelease, IEnumFORMATETC_fnNext, IEnumFORMATETC_fnSkip, IEnumFORMATETC_fnReset, IEnumFORMATETC_fnClone }; LPENUMFORMATETC IEnumFORMATETC_Constructor(UINT cfmt, const FORMATETC afmt[]) { IEnumFORMATETCImpl* ef; DWORD size=cfmt * sizeof(FORMATETC); ef = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IEnumFORMATETCImpl)); if(ef) { ef->ref=1; ef->IEnumFORMATETC_iface.lpVtbl = &efvt; ef->countFmt = cfmt; ef->pFmt = SHAlloc (size); if (ef->pFmt) memcpy(ef->pFmt, afmt, size); } TRACE("(%p)->(%u,%p)\n",ef, cfmt, afmt); return (LPENUMFORMATETC)ef; } /*********************************************************************** * IDataObject implementation */ /* number of supported formats */ #define MAX_FORMATS 4 typedef struct { /* IUnknown fields */ IDataObject IDataObject_iface; LONG ref; /* IDataObject fields */ LPITEMIDLIST pidl; LPITEMIDLIST * apidl; UINT cidl; FORMATETC pFormatEtc[MAX_FORMATS]; UINT cfShellIDList; UINT cfFileNameA; UINT cfFileNameW; } IDataObjectImpl; static inline IDataObjectImpl *impl_from_IDataObject(IDataObject *iface) { return CONTAINING_RECORD(iface, IDataObjectImpl, IDataObject_iface); } /*************************************************************************** * IDataObject_QueryInterface */ static HRESULT WINAPI IDataObject_fnQueryInterface(IDataObject *iface, REFIID riid, LPVOID * ppvObj) { IDataObjectImpl *This = impl_from_IDataObject(iface); TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj); *ppvObj = NULL; if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDataObject)) { *ppvObj = &This->IDataObject_iface; } if(*ppvObj) { IUnknown_AddRef((IUnknown*)*ppvObj); TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj); return S_OK; } TRACE("-- Interface: E_NOINTERFACE\n"); return E_NOINTERFACE; } /************************************************************************** * IDataObject_AddRef */ static ULONG WINAPI IDataObject_fnAddRef(IDataObject *iface) { IDataObjectImpl *This = impl_from_IDataObject(iface); ULONG refCount = InterlockedIncrement(&This->ref); TRACE("(%p)->(count=%u)\n", This, refCount - 1); return refCount; } /************************************************************************** * IDataObject_Release */ static ULONG WINAPI IDataObject_fnRelease(IDataObject *iface) { IDataObjectImpl *This = impl_from_IDataObject(iface); ULONG refCount = InterlockedDecrement(&This->ref); TRACE("(%p)->(%u)\n", This, refCount + 1); if (!refCount) { TRACE(" destroying IDataObject(%p)\n",This); _ILFreeaPidl(This->apidl, This->cidl); ILFree(This->pidl), HeapFree(GetProcessHeap(),0,This); } return refCount; } /************************************************************************** * IDataObject_fnGetData */ static HRESULT WINAPI IDataObject_fnGetData(IDataObject *iface, LPFORMATETC pformatetcIn, STGMEDIUM *pmedium) { IDataObjectImpl *This = impl_from_IDataObject(iface); char szTemp[256]; szTemp[0]=0; GetClipboardFormatNameA (pformatetcIn->cfFormat, szTemp, 256); TRACE("(%p)->(%p %p format=%s)\n", This, pformatetcIn, pmedium, szTemp); if (pformatetcIn->cfFormat == This->cfShellIDList) { if (This->cidl < 1) return(E_UNEXPECTED); pmedium->u.hGlobal = RenderSHELLIDLIST(This->pidl, This->apidl, This->cidl); } else if (pformatetcIn->cfFormat == CF_HDROP) { if (This->cidl < 1) return(E_UNEXPECTED); pmedium->u.hGlobal = RenderHDROP(This->pidl, This->apidl, This->cidl); } else if (pformatetcIn->cfFormat == This->cfFileNameA) { if (This->cidl < 1) return(E_UNEXPECTED); pmedium->u.hGlobal = RenderFILENAMEA(This->pidl, This->apidl, This->cidl); } else if (pformatetcIn->cfFormat == This->cfFileNameW) { if (This->cidl < 1) return(E_UNEXPECTED); pmedium->u.hGlobal = RenderFILENAMEW(This->pidl, This->apidl, This->cidl); } else { FIXME("-- expected clipformat not implemented\n"); return (E_INVALIDARG); } if (pmedium->u.hGlobal) { pmedium->tymed = TYMED_HGLOBAL; pmedium->pUnkForRelease = NULL; return S_OK; } return E_OUTOFMEMORY; } static HRESULT WINAPI IDataObject_fnGetDataHere(IDataObject *iface, LPFORMATETC pformatetc, STGMEDIUM *pmedium) { IDataObjectImpl *This = impl_from_IDataObject(iface); FIXME("(%p)->()\n", This); return E_NOTIMPL; } static HRESULT WINAPI IDataObject_fnQueryGetData(IDataObject *iface, LPFORMATETC pformatetc) { IDataObjectImpl *This = impl_from_IDataObject(iface); UINT i; TRACE("(%p)->(fmt=0x%08x tym=0x%08x)\n", This, pformatetc->cfFormat, pformatetc->tymed); if(!(DVASPECT_CONTENT & pformatetc->dwAspect)) return DV_E_DVASPECT; /* check our formats table what we have */ for (i=0; i<MAX_FORMATS; i++) { if ((This->pFormatEtc[i].cfFormat == pformatetc->cfFormat) && (This->pFormatEtc[i].tymed & pformatetc->tymed)) { return S_OK; } } return DV_E_TYMED; } static HRESULT WINAPI IDataObject_fnGetCanonicalFormatEtc(IDataObject *iface, LPFORMATETC pformatectIn, LPFORMATETC pformatetcOut) { IDataObjectImpl *This = impl_from_IDataObject(iface); FIXME("(%p)->()\n", This); return E_NOTIMPL; } static HRESULT WINAPI IDataObject_fnSetData(IDataObject *iface, LPFORMATETC pformatetc, STGMEDIUM *pmedium, BOOL fRelease) { IDataObjectImpl *This = impl_from_IDataObject(iface); FIXME("(%p)->()\n", This); return E_NOTIMPL; } static HRESULT WINAPI IDataObject_fnEnumFormatEtc(IDataObject *iface, DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc) { IDataObjectImpl *This = impl_from_IDataObject(iface); TRACE("(%p)->()\n", This); *ppenumFormatEtc=NULL; /* only get data */ if (DATADIR_GET == dwDirection) { *ppenumFormatEtc = IEnumFORMATETC_Constructor(MAX_FORMATS, This->pFormatEtc); return (*ppenumFormatEtc) ? S_OK : E_FAIL; } return E_NOTIMPL; } static HRESULT WINAPI IDataObject_fnDAdvise(IDataObject *iface, FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection) { IDataObjectImpl *This = impl_from_IDataObject(iface); FIXME("(%p)->()\n", This); return E_NOTIMPL; } static HRESULT WINAPI IDataObject_fnDUnadvise(IDataObject *iface, DWORD dwConnection) { IDataObjectImpl *This = impl_from_IDataObject(iface); FIXME("(%p)->()\n", This); return E_NOTIMPL; } static HRESULT WINAPI IDataObject_fnEnumDAdvise(IDataObject *iface, IEnumSTATDATA **ppenumAdvise) { IDataObjectImpl *This = impl_from_IDataObject(iface); FIXME("(%p)->()\n", This); return E_NOTIMPL; } static const IDataObjectVtbl dtovt = { IDataObject_fnQueryInterface, IDataObject_fnAddRef, IDataObject_fnRelease, IDataObject_fnGetData, IDataObject_fnGetDataHere, IDataObject_fnQueryGetData, IDataObject_fnGetCanonicalFormatEtc, IDataObject_fnSetData, IDataObject_fnEnumFormatEtc, IDataObject_fnDAdvise, IDataObject_fnDUnadvise, IDataObject_fnEnumDAdvise }; /************************************************************************** * IDataObject_Constructor */ IDataObject* IDataObject_Constructor(HWND hwndOwner, LPCITEMIDLIST pMyPidl, LPCITEMIDLIST * apidl, UINT cidl) { IDataObjectImpl* dto; dto = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDataObjectImpl)); if (dto) { dto->ref = 1; dto->IDataObject_iface.lpVtbl = &dtovt; dto->pidl = ILClone(pMyPidl); dto->apidl = _ILCopyaPidl(apidl, cidl); dto->cidl = cidl; dto->cfShellIDList = RegisterClipboardFormatW(CFSTR_SHELLIDLISTW); dto->cfFileNameA = RegisterClipboardFormatA(CFSTR_FILENAMEA); dto->cfFileNameW = RegisterClipboardFormatW(CFSTR_FILENAMEW); InitFormatEtc(dto->pFormatEtc[0], dto->cfShellIDList, TYMED_HGLOBAL); InitFormatEtc(dto->pFormatEtc[1], CF_HDROP, TYMED_HGLOBAL); InitFormatEtc(dto->pFormatEtc[2], dto->cfFileNameA, TYMED_HGLOBAL); InitFormatEtc(dto->pFormatEtc[3], dto->cfFileNameW, TYMED_HGLOBAL); } TRACE("(%p)->(apidl=%p cidl=%u)\n",dto, apidl, cidl); return &dto->IDataObject_iface; }