From a85d12af447057d40882c58e2bb9b51f389abecb Mon Sep 17 00:00:00 2001 From: Piotr Caban Date: Wed, 8 Nov 2017 15:05:01 +0100 Subject: [PATCH] vbscript: Add support for "for each" on arrays. Signed-off-by: Piotr Caban Signed-off-by: Jacek Caban Signed-off-by: Alexandre Julliard --- dlls/vbscript/Makefile.in | 1 + dlls/vbscript/interp.c | 12 +++ dlls/vbscript/utils.c | 193 ++++++++++++++++++++++++++++++++++++++ dlls/vbscript/vbscript.h | 2 + 4 files changed, 208 insertions(+) create mode 100644 dlls/vbscript/utils.c diff --git a/dlls/vbscript/Makefile.in b/dlls/vbscript/Makefile.in index 5ad0600416e..5c613f0ee50 100644 --- a/dlls/vbscript/Makefile.in +++ b/dlls/vbscript/Makefile.in @@ -7,6 +7,7 @@ C_SRCS = \ interp.c \ lex.c \ regexp.c \ + utils.c \ vbdisp.c \ vbregexp.c \ vbscript.c \ diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c index feb8119086c..2f414be40ee 100644 --- a/dlls/vbscript/interp.c +++ b/dlls/vbscript/interp.c @@ -1148,6 +1148,18 @@ static HRESULT interp_newenum(exec_ctx_t *ctx) V_UNKNOWN(r) = (IUnknown*)iter; break; } + case VT_VARIANT|VT_ARRAY: + case VT_VARIANT|VT_ARRAY|VT_BYREF: { + IEnumVARIANT *iter; + + hres = create_safearray_iter(V_ISBYREF(v.v) ? *V_ARRAYREF(v.v) : V_ARRAY(v.v), &iter); + if(FAILED(hres)) + return hres; + + V_VT(r) = VT_UNKNOWN; + V_UNKNOWN(r) = (IUnknown*)iter; + break; + } default: FIXME("Unsupported for %s\n", debugstr_variant(v.v)); release_val(&v); diff --git a/dlls/vbscript/utils.c b/dlls/vbscript/utils.c new file mode 100644 index 00000000000..d30842c52eb --- /dev/null +++ b/dlls/vbscript/utils.c @@ -0,0 +1,193 @@ +/* + * Copyright 2017 Piotr Caban for CodeWeavers + * + * 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 "vbscript.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(vbscript); + +typedef struct { + IEnumVARIANT IEnumVARIANT_iface; + + LONG ref; + + SAFEARRAY *sa; + ULONG i, size; +} safearray_iter; + +static inline safearray_iter *impl_from_IEnumVARIANT(IEnumVARIANT *iface) +{ + return CONTAINING_RECORD(iface, safearray_iter, IEnumVARIANT_iface); +} + +static HRESULT WINAPI safearray_iter_IEnumVARIANT_QueryInterface( + IEnumVARIANT *iface, REFIID riid, void **ppv) +{ + safearray_iter *This = impl_from_IEnumVARIANT(iface); + + if(IsEqualGUID(riid, &IID_IUnknown)) { + TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv); + *ppv = &This->IEnumVARIANT_iface; + }else if(IsEqualGUID(riid, &IID_IEnumVARIANT)) { + TRACE("(%p)->(IID_IEnumVARIANT %p)\n", This, ppv); + *ppv = &This->IEnumVARIANT_iface; + }else { + FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); + *ppv = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI safearray_iter_IEnumVARIANT_AddRef(IEnumVARIANT *iface) +{ + safearray_iter *This = impl_from_IEnumVARIANT(iface); + LONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) ref=%d\n", This, ref); + + return ref; +} + +static ULONG WINAPI safearray_iter_IEnumVARIANT_Release(IEnumVARIANT *iface) +{ + safearray_iter *This = impl_from_IEnumVARIANT(iface); + LONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) ref=%d\n", iface, ref); + + if(!ref) { + if(This->sa) + SafeArrayUnlock(This->sa); + heap_free(This); + } + + return ref; +} + +static HRESULT WINAPI safearray_iter_IEnumVARIANT_Next(IEnumVARIANT *iface, + ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched) +{ + safearray_iter *This = impl_from_IEnumVARIANT(iface); + HRESULT hres; + VARIANT *v; + + TRACE("(%p)->(%u %p %p)\n", This, celt, rgVar, pCeltFetched); + + if(celt != 1) { + FIXME("celt != 1\n"); + return E_NOTIMPL; + } + + if(This->i >= This->size) { + if(pCeltFetched) + *pCeltFetched = 0; + return S_FALSE; + } + + if(!This->sa->cLocks) + ERR("SAFEARRAY not locked\n"); + + v = (VARIANT*)(((BYTE*)This->sa->pvData) + This->i * This->sa->cbElements); + V_VT(rgVar) = VT_EMPTY; + hres = VariantCopy(rgVar, v); + if(FAILED(hres)) + return hres; + + This->i++; + if(pCeltFetched) + *pCeltFetched = 1; + return S_OK; +} + +static HRESULT WINAPI safearray_iter_IEnumVARIANT_Skip(IEnumVARIANT *iface, ULONG celt) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI safearray_iter_IEnumVARIANT_Reset(IEnumVARIANT *iface) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI safearray_iter_IEnumVARIANT_Clone( + IEnumVARIANT *iface, IEnumVARIANT **ppEnum) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static const IEnumVARIANTVtbl safearray_iter_EnumVARIANTVtbl = { + safearray_iter_IEnumVARIANT_QueryInterface, + safearray_iter_IEnumVARIANT_AddRef, + safearray_iter_IEnumVARIANT_Release, + safearray_iter_IEnumVARIANT_Next, + safearray_iter_IEnumVARIANT_Skip, + safearray_iter_IEnumVARIANT_Reset, + safearray_iter_IEnumVARIANT_Clone +}; + +static ULONG get_safearray_size(SAFEARRAY *sa) +{ + ULONG ret = 1; + USHORT i; + + if(!sa) + return 0; + + for(i=0; icDims && ret; i++) + ret *= sa->rgsabound[i].cElements; + return ret; +} + +HRESULT create_safearray_iter(SAFEARRAY *sa, IEnumVARIANT **ev) +{ + safearray_iter *iter; + HRESULT hres; + + if(sa && !(sa->fFeatures & FADF_VARIANT)) { + FIXME("enumeration not supported: %x\n", sa->fFeatures); + return E_NOTIMPL; + } + + iter = heap_alloc(sizeof(*iter)); + if(!iter) + return E_OUTOFMEMORY; + + if(sa) { + hres = SafeArrayLock(sa); + if(FAILED(hres)) { + heap_free(iter); + return hres; + } + } + + iter->IEnumVARIANT_iface.lpVtbl = &safearray_iter_EnumVARIANTVtbl; + iter->ref = 1; + iter->sa = sa; + iter->i = 0; + iter->size = get_safearray_size(sa); + + *ev = &iter->IEnumVARIANT_iface; + return S_OK; +} diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h index d3be4f09ac0..ec417370830 100644 --- a/dlls/vbscript/vbscript.h +++ b/dlls/vbscript/vbscript.h @@ -391,6 +391,8 @@ HRESULT create_regexp(IDispatch**) DECLSPEC_HIDDEN; HRESULT map_hres(HRESULT) DECLSPEC_HIDDEN; +HRESULT create_safearray_iter(SAFEARRAY *sa, IEnumVARIANT **ev) DECLSPEC_HIDDEN; + #define FACILITY_VBS 0xa #define MAKE_VBSERROR(code) MAKE_HRESULT(SEVERITY_ERROR, FACILITY_VBS, code)