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