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