From: Francis De Brabandere <francisdb@gmail.com> On Windows, public array properties declared in a class (e.g. "Public arr(3)") can be accessed element-wise from outside the class using obj.arr(i) for both reading and writing. Wine failed to handle this because invoke_variant_prop() used V_ARRAY() which does not work for VT_ARRAY|VT_BYREF|VT_VARIANT arrays, and the property put path did not support indexed arguments at all. Fix both by adding a helper to extract the SAFEARRAY from either BYREF or direct array variants, and implementing indexed array element writes in the property put path. --- dlls/vbscript/tests/lang.vbs | 9 +++--- dlls/vbscript/vbdisp.c | 55 ++++++++++++++++++++++++++++++++---- 2 files changed, 54 insertions(+), 10 deletions(-) diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs index c364f12c00b..305c3dd0db7 100644 --- a/dlls/vbscript/tests/lang.vbs +++ b/dlls/vbscript/tests/lang.vbs @@ -1840,7 +1840,7 @@ End Class Set obj = new ArrClass Call ok(getVT(obj.classarr) = "VT_ARRAY|VT_VARIANT", "getVT(obj.classarr) = " & getVT(obj.classarr)) -'todo_wine Call ok(obj.classarr(1) = 2, "obj.classarr(1) = " & obj.classarr(1)) +Call ok(obj.classarr(1) = 2, "obj.classarr(1) = " & obj.classarr(1)) obj.var = arr Call ok(getVT(obj.var) = "VT_ARRAY|VT_VARIANT", "getVT(obj.var) = " & getVT(obj.var)) @@ -2184,8 +2184,7 @@ call ok(x.pub2 = 2, "x.pub2 = " & x.pub2) call ok(ubound(x.pubArray) = 3, "ubound(x.pubArray) = " & ubound(x.pubArray)) call ok(ubound(x.pubArray2, 1) = 5, "ubound(x.pubArray2, 1) = " & ubound(x.pubArray2, 1)) call ok(ubound(x.pubArray2, 2) = 10, "ubound(x.pubArray2, 2) = " & ubound(x.pubArray2, 2)) -' TODO: this does not parse: accessing class variable of array type element directly -' call ok(x.pubArray(0) = 3, "x.pubArray(0) = " & x.pubArray(0)) +call ok(x.pubArray(0) = 3, "x.pubArray(0) = " & x.pubArray(0)) call ok(x.dim1 = 7, "x.dim1 = " & x.dim1) call ok(x.dim2 = 8, "x.dim2 = " & x.dim2) @@ -2196,9 +2195,9 @@ err.clear x.priv2 = 2 call ok(err.number = 438, "err.number = " & err.number) err.clear -' TODO: set class variable of array type element directly x.pubArray(0) = 1 -call todo_wine_ok(err.number = 0, "set x.pubArray(0) err.number = " & err.number) +call ok(err.number = 0, "set x.pubArray(0) err.number = " & err.number) +call ok(x.pubArray(0) = 1, "x.pubArray(0) = " & x.pubArray(0)) on error goto 0 funcCalled = "" diff --git a/dlls/vbscript/vbdisp.c b/dlls/vbscript/vbdisp.c index 0ede0cfd6ba..a0d0f56c7f6 100644 --- a/dlls/vbscript/vbdisp.c +++ b/dlls/vbscript/vbdisp.c @@ -114,6 +114,21 @@ static HRESULT get_propput_arg(script_ctx_t *ctx, const DISPPARAMS *dp, WORD fla return S_OK; } +static HRESULT get_array_from_variant(VARIANT *v, SAFEARRAY **array) +{ + switch(V_VT(v)) { + case VT_ARRAY|VT_BYREF|VT_VARIANT: + *array = *V_ARRAYREF(v); + break; + case VT_ARRAY|VT_VARIANT: + *array = V_ARRAY(v); + break; + default: + return E_FAIL; + } + return S_OK; +} + static HRESULT invoke_variant_prop(script_ctx_t *ctx, VARIANT *v, WORD flags, DISPPARAMS *dp, VARIANT *res) { HRESULT hres; @@ -122,13 +137,21 @@ static HRESULT invoke_variant_prop(script_ctx_t *ctx, VARIANT *v, WORD flags, DI case DISPATCH_PROPERTYGET|DISPATCH_METHOD: case DISPATCH_PROPERTYGET: if(dp->cArgs) { + SAFEARRAY *array; + if (!V_ISARRAY(v)) { WARN("called with arguments for non-array property\n"); return DISP_E_MEMBERNOTFOUND; /* That's what tests show */ } - if (FAILED(hres = array_access(V_ARRAY(v), dp, &v))) + if(FAILED(hres = get_array_from_variant(v, &array))) + { + FIXME("Unsupported array type %x\n", V_VT(v)); + return hres; + } + + if (FAILED(hres = array_access(array, dp, &v))) { WARN("failed to access array element\n"); return hres; @@ -149,17 +172,39 @@ static HRESULT invoke_variant_prop(script_ctx_t *ctx, VARIANT *v, WORD flags, DI return hres; if(arg_cnt(dp)) { - FIXME("Arguments not supported\n"); - return E_NOTIMPL; + SAFEARRAY *array; + + if(!V_ISARRAY(v)) { + FIXME("Arguments not supported for type %x\n", V_VT(v)); + if(own_val) + VariantClear(&put_val); + return E_NOTIMPL; + } + + if(FAILED(hres = get_array_from_variant(v, &array))) { + FIXME("Unsupported array type %x\n", V_VT(v)); + if(own_val) + VariantClear(&put_val); + return hres; + } + + hres = array_access(array, dp, &v); + if(FAILED(hres)) { + if(own_val) + VariantClear(&put_val); + return hres; + } } if(res) V_VT(res) = VT_EMPTY; - if(own_val) + if(own_val) { + VariantClear(v); *v = put_val; - else + } else { hres = VariantCopyInd(v, &put_val); + } break; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10383