/* * Copyright 2005 Jacek Caban * * 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 "urlmon_main.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(urlmon); static WCHAR wszEnumFORMATETC[] = {'_','E','n','u','m','F','O','R','M','A','T','E','T','C','_',0}; typedef struct { IEnumFORMATETC IEnumFORMATETC_iface; FORMATETC *fetc; UINT fetc_cnt; UINT it; LONG ref; } EnumFORMATETC; static inline EnumFORMATETC *impl_from_IEnumFORMATETC(IEnumFORMATETC *iface) { return CONTAINING_RECORD(iface, EnumFORMATETC, IEnumFORMATETC_iface); } static IEnumFORMATETC *EnumFORMATETC_Create(UINT cfmtetc, const FORMATETC *rgfmtetc, UINT it); static HRESULT WINAPI EnumFORMATETC_QueryInterface(IEnumFORMATETC *iface, REFIID riid, void **ppv) { EnumFORMATETC *This = impl_from_IEnumFORMATETC(iface); TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); *ppv = NULL; if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IEnumFORMATETC, riid)) { IEnumFORMATETC_AddRef(iface); *ppv = iface; return S_OK; } WARN("not supported interface %s\n", debugstr_guid(riid)); return E_NOINTERFACE; } static ULONG WINAPI EnumFORMATETC_AddRef(IEnumFORMATETC *iface) { EnumFORMATETC *This = impl_from_IEnumFORMATETC(iface); LONG ref = InterlockedIncrement(&This->ref); TRACE("(%p) ref=%d\n", This, ref); return ref; } static ULONG WINAPI EnumFORMATETC_Release(IEnumFORMATETC *iface) { EnumFORMATETC *This = impl_from_IEnumFORMATETC(iface); LONG ref = InterlockedDecrement(&This->ref); TRACE("(%p) ref=%d\n", This, ref); if(!ref) { heap_free(This->fetc); heap_free(This); URLMON_UnlockModule(); } return ref; } static HRESULT WINAPI EnumFORMATETC_Next(IEnumFORMATETC *iface, ULONG celt, FORMATETC *rgelt, ULONG *pceltFetched) { EnumFORMATETC *This = impl_from_IEnumFORMATETC(iface); ULONG cnt; TRACE("(%p)->(%d %p %p)\n", This, celt, rgelt, pceltFetched); if(!rgelt) return E_INVALIDARG; if(This->it >= This->fetc_cnt || !celt) { if(pceltFetched) *pceltFetched = 0; return celt ? S_FALSE : S_OK; } cnt = This->fetc_cnt-This->it > celt ? celt : This->fetc_cnt-This->it; memcpy(rgelt, This->fetc+This->it, cnt*sizeof(FORMATETC)); This->it += cnt; if(pceltFetched) *pceltFetched = cnt; return cnt == celt ? S_OK : S_FALSE; } static HRESULT WINAPI EnumFORMATETC_Skip(IEnumFORMATETC *iface, ULONG celt) { EnumFORMATETC *This = impl_from_IEnumFORMATETC(iface); TRACE("(%p)->(%d)\n", This, celt); This->it += celt; return This->it > This->fetc_cnt ? S_FALSE : S_OK; } static HRESULT WINAPI EnumFORMATETC_Reset(IEnumFORMATETC *iface) { EnumFORMATETC *This = impl_from_IEnumFORMATETC(iface); TRACE("(%p)\n", This); This->it = 0; return S_OK; } static HRESULT WINAPI EnumFORMATETC_Clone(IEnumFORMATETC *iface, IEnumFORMATETC **ppenum) { EnumFORMATETC *This = impl_from_IEnumFORMATETC(iface); TRACE("(%p)->(%p)\n", This, ppenum); if(!ppenum) return E_INVALIDARG; *ppenum = EnumFORMATETC_Create(This->fetc_cnt, This->fetc, This->it); return S_OK; } static const IEnumFORMATETCVtbl EnumFORMATETCVtbl = { EnumFORMATETC_QueryInterface, EnumFORMATETC_AddRef, EnumFORMATETC_Release, EnumFORMATETC_Next, EnumFORMATETC_Skip, EnumFORMATETC_Reset, EnumFORMATETC_Clone }; static IEnumFORMATETC *EnumFORMATETC_Create(UINT cfmtetc, const FORMATETC *rgfmtetc, UINT it) { EnumFORMATETC *ret = heap_alloc(sizeof(EnumFORMATETC)); URLMON_LockModule(); ret->IEnumFORMATETC_iface.lpVtbl = &EnumFORMATETCVtbl; ret->ref = 1; ret->it = it; ret->fetc_cnt = cfmtetc; ret->fetc = heap_alloc(cfmtetc*sizeof(FORMATETC)); memcpy(ret->fetc, rgfmtetc, cfmtetc*sizeof(FORMATETC)); return &ret->IEnumFORMATETC_iface; } /********************************************************** * CreateFormatEnumerator (urlmon.@) */ HRESULT WINAPI CreateFormatEnumerator(UINT cfmtetc, FORMATETC *rgfmtetc, IEnumFORMATETC** ppenumfmtetc) { TRACE("(%d %p %p)\n", cfmtetc, rgfmtetc, ppenumfmtetc); if(!ppenumfmtetc) return E_INVALIDARG; if(!cfmtetc) return E_FAIL; *ppenumfmtetc = EnumFORMATETC_Create(cfmtetc, rgfmtetc, 0); return S_OK; } /********************************************************** * RegisterFormatEnumerator (urlmon.@) */ HRESULT WINAPI RegisterFormatEnumerator(LPBC pBC, IEnumFORMATETC *pEFetc, DWORD reserved) { TRACE("(%p %p %d)\n", pBC, pEFetc, reserved); if(reserved) WARN("reserved != 0\n"); if(!pBC || !pEFetc) return E_INVALIDARG; return IBindCtx_RegisterObjectParam(pBC, wszEnumFORMATETC, (IUnknown*)pEFetc); } /********************************************************** * RevokeFormatEnumerator (urlmon.@) */ HRESULT WINAPI RevokeFormatEnumerator(LPBC pbc, IEnumFORMATETC *pEFetc) { TRACE("(%p %p)\n", pbc, pEFetc); if(!pbc) return E_INVALIDARG; return IBindCtx_RevokeObjectParam(pbc, wszEnumFORMATETC); }