[PATCH v5 0/2] MR10895: vbscript: Match native error codes for non-array arguments to UBound/LBound.
-- v5: vbscript: Match native error codes for non-array arguments to UBound/LBound. vbscript/tests: Add tests for UBound/LBound on non-array arguments. https://gitlab.winehq.org/wine/wine/-/merge_requests/10895
From: Francis De Brabandere <francisdb@gmail.com> --- dlls/vbscript/tests/api.vbs | 48 +++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/dlls/vbscript/tests/api.vbs b/dlls/vbscript/tests/api.vbs index 8cbd5824b39..b9d1ad8b8e0 100644 --- a/dlls/vbscript/tests/api.vbs +++ b/dlls/vbscript/tests/api.vbs @@ -332,6 +332,9 @@ Call ok(Lbound(arr2, 1) = 0, "Lbound(x) = " & Lbound(x)) Call ok(Lbound(arr2, 2) = 0, "Lbound(x) = " & Lbound(x)) sub testLBoundError() + Dim nothingObj : Set nothingObj = Nothing + Dim emptyObj : Set emptyObj = new EmptyClass + Dim dictObj : Set dictObj = CreateObject("Scripting.Dictionary") on error resume next call Err.clear() call LBound() @@ -343,6 +346,27 @@ sub testLBoundError() call LBound(Null) call ok(Err.number = 13, "Err.number = " & Err.number) call Err.clear() + call LBound(42) + todo_wine_ok Err.number = 13, "LBound(int) Err.number = " & Err.number + call Err.clear() + call LBound("str") + todo_wine_ok Err.number = 13, "LBound(string) Err.number = " & Err.number + call Err.clear() + call LBound(True) + todo_wine_ok Err.number = 13, "LBound(bool) Err.number = " & Err.number + call Err.clear() + call LBound(3.14) + todo_wine_ok Err.number = 13, "LBound(double) Err.number = " & Err.number + call Err.clear() + call LBound(nothingObj) + todo_wine_ok Err.number = 91, "LBound(Nothing) Err.number = " & Err.number + call Err.clear() + call LBound(emptyObj) + todo_wine_ok Err.number = 438, "LBound(no-default-object) Err.number = " & Err.number + call Err.clear() + call LBound(dictObj) + todo_wine_ok Err.number = 450, "LBound(default-needs-arg) Err.number = " & Err.number + call Err.clear() call LBound(arr, 1, 2) call ok(Err.number = 450, "Err.number = " & Err.number) if isEnglishLang then call ok(Err.description = "Wrong number of arguments or invalid property assignment", _ @@ -350,6 +374,9 @@ sub testLBoundError() end sub sub testUBoundError() + Dim nothingObj : Set nothingObj = Nothing + Dim emptyObj : Set emptyObj = new EmptyClass + Dim dictObj : Set dictObj = CreateObject("Scripting.Dictionary") on error resume next call Err.clear() call UBound() @@ -361,6 +388,27 @@ sub testUBoundError() call UBound(Null) call ok(Err.number = 13, "Err.number = " & Err.number) call Err.clear() + call UBound(42) + todo_wine_ok Err.number = 13, "UBound(int) Err.number = " & Err.number + call Err.clear() + call UBound("str") + todo_wine_ok Err.number = 13, "UBound(string) Err.number = " & Err.number + call Err.clear() + call UBound(True) + todo_wine_ok Err.number = 13, "UBound(bool) Err.number = " & Err.number + call Err.clear() + call UBound(3.14) + todo_wine_ok Err.number = 13, "UBound(double) Err.number = " & Err.number + call Err.clear() + call UBound(nothingObj) + todo_wine_ok Err.number = 91, "UBound(Nothing) Err.number = " & Err.number + call Err.clear() + call UBound(emptyObj) + todo_wine_ok Err.number = 438, "UBound(no-default-object) Err.number = " & Err.number + call Err.clear() + call UBound(dictObj) + todo_wine_ok Err.number = 450, "UBound(default-needs-arg) Err.number = " & Err.number + call Err.clear() call UBound(arr, 1, 2) call ok(Err.number = 450, "Err.number = " & Err.number) if isEnglishLang then call ok(Err.description = "Wrong number of arguments or invalid property assignment", _ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10895
From: Francis De Brabandere <francisdb@gmail.com> For VT_DISPATCH arguments, try to resolve the default value via DISPID_VALUE and map the failure mode to the same VBScript error code native cscript raises: err 91 for a NULL dispatch (Nothing), err 438 when the object has no default member, err 450 when the default member exists but needs arguments. If the default resolves to an array, use it; if it resolves to a scalar, that is a type mismatch. All other non-array variant types (scalars) collapse into a plain type-mismatch via the default arm. --- dlls/vbscript/global.c | 94 ++++++++++++++++++++++++++++--------- dlls/vbscript/tests/api.vbs | 58 +++++++++++++++++------ 2 files changed, 116 insertions(+), 36 deletions(-) diff --git a/dlls/vbscript/global.c b/dlls/vbscript/global.c index bd949f7b370..214fc27b5d3 100644 --- a/dlls/vbscript/global.c +++ b/dlls/vbscript/global.c @@ -1166,8 +1166,27 @@ static HRESULT Global_Timer(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, } +static HRESULT bound_arg_resolve_dispatch(script_ctx_t *ctx, IDispatch *disp, + VARIANT *out) +{ + DISPPARAMS dp = {0}; + HRESULT hres; + + if(!disp) + return MAKE_VBSERROR(VBSE_OBJECT_VARIABLE_NOT_SET); + + VariantInit(out); + hres = disp_call(ctx, disp, DISPID_VALUE, TRUE, &dp, out); + if(hres == DISP_E_MEMBERNOTFOUND) + return MAKE_VBSERROR(VBSE_OLE_NO_PROP_OR_METHOD); + if(hres == DISP_E_BADPARAMCOUNT || hres == DISP_E_PARAMNOTOPTIONAL) + return MAKE_VBSERROR(VBSE_FUNC_ARITY_MISMATCH); + return hres; +} + static HRESULT Global_LBound(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) { + VARIANT default_value; SAFEARRAY *sa; HRESULT hres; LONG lbound; @@ -1177,6 +1196,8 @@ static HRESULT Global_LBound(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, TRACE("%s %s\n", debugstr_variant(arg), args_cnt == 2 ? debugstr_variant(arg + 1) : "1"); + V_VT(&default_value) = VT_EMPTY; + switch(V_VT(arg)) { case VT_VARIANT|VT_ARRAY: sa = V_ARRAY(arg); @@ -1184,34 +1205,48 @@ static HRESULT Global_LBound(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, case VT_VARIANT|VT_ARRAY|VT_BYREF: sa = *V_ARRAYREF(arg); break; - case VT_EMPTY: - case VT_NULL: - return MAKE_VBSERROR(VBSE_TYPE_MISMATCH); + case VT_DISPATCH: + hres = bound_arg_resolve_dispatch(This->ctx, V_DISPATCH(arg), &default_value); + if(FAILED(hres)) + return hres; + if(V_VT(&default_value) == (VT_VARIANT|VT_ARRAY)) + sa = V_ARRAY(&default_value); + else if(V_VT(&default_value) == (VT_VARIANT|VT_ARRAY|VT_BYREF)) + sa = *V_ARRAYREF(&default_value); + else { + VariantClear(&default_value); + return MAKE_VBSERROR(VBSE_TYPE_MISMATCH); + } + break; default: - FIXME("arg %s not supported\n", debugstr_variant(arg)); - return E_NOTIMPL; + return MAKE_VBSERROR(VBSE_TYPE_MISMATCH); } - if(!sa) - return MAKE_VBSERROR(VBSE_OUT_OF_BOUNDS); + if(!sa) { + hres = MAKE_VBSERROR(VBSE_OUT_OF_BOUNDS); + goto done; + } if(args_cnt == 2) { hres = to_int(arg + 1, &dim); if(FAILED(hres)) - return hres; + goto done; }else { dim = 1; } hres = SafeArrayGetLBound(sa, dim, &lbound); - if(FAILED(hres)) - return hres; + if(SUCCEEDED(hres)) + hres = return_int(res, lbound); - return return_int(res, lbound); +done: + VariantClear(&default_value); + return hres; } static HRESULT Global_UBound(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) { + VARIANT default_value; SAFEARRAY *sa; HRESULT hres; LONG ubound; @@ -1221,6 +1256,8 @@ static HRESULT Global_UBound(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, TRACE("%s %s\n", debugstr_variant(arg), args_cnt == 2 ? debugstr_variant(arg + 1) : "1"); + V_VT(&default_value) = VT_EMPTY; + switch(V_VT(arg)) { case VT_VARIANT|VT_ARRAY: sa = V_ARRAY(arg); @@ -1228,30 +1265,43 @@ static HRESULT Global_UBound(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, case VT_VARIANT|VT_ARRAY|VT_BYREF: sa = *V_ARRAYREF(arg); break; - case VT_EMPTY: - case VT_NULL: - return MAKE_VBSERROR(VBSE_TYPE_MISMATCH); + case VT_DISPATCH: + hres = bound_arg_resolve_dispatch(This->ctx, V_DISPATCH(arg), &default_value); + if(FAILED(hres)) + return hres; + if(V_VT(&default_value) == (VT_VARIANT|VT_ARRAY)) + sa = V_ARRAY(&default_value); + else if(V_VT(&default_value) == (VT_VARIANT|VT_ARRAY|VT_BYREF)) + sa = *V_ARRAYREF(&default_value); + else { + VariantClear(&default_value); + return MAKE_VBSERROR(VBSE_TYPE_MISMATCH); + } + break; default: - FIXME("arg %s not supported\n", debugstr_variant(arg)); - return E_NOTIMPL; + return MAKE_VBSERROR(VBSE_TYPE_MISMATCH); } - if(!sa) - return MAKE_VBSERROR(VBSE_OUT_OF_BOUNDS); + if(!sa) { + hres = MAKE_VBSERROR(VBSE_OUT_OF_BOUNDS); + goto done; + } if(args_cnt == 2) { hres = to_int(arg + 1, &dim); if(FAILED(hres)) - return hres; + goto done; }else { dim = 1; } hres = SafeArrayGetUBound(sa, dim, &ubound); - if(FAILED(hres)) - return hres; + if(SUCCEEDED(hres)) + hres = return_int(res, ubound); - return return_int(res, ubound); +done: + VariantClear(&default_value); + return hres; } static HRESULT Global_RGB(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) diff --git a/dlls/vbscript/tests/api.vbs b/dlls/vbscript/tests/api.vbs index b9d1ad8b8e0..fc09be7a8a6 100644 --- a/dlls/vbscript/tests/api.vbs +++ b/dlls/vbscript/tests/api.vbs @@ -347,25 +347,25 @@ sub testLBoundError() call ok(Err.number = 13, "Err.number = " & Err.number) call Err.clear() call LBound(42) - todo_wine_ok Err.number = 13, "LBound(int) Err.number = " & Err.number + call ok(Err.number = 13, "LBound(int) Err.number = " & Err.number) call Err.clear() call LBound("str") - todo_wine_ok Err.number = 13, "LBound(string) Err.number = " & Err.number + call ok(Err.number = 13, "LBound(string) Err.number = " & Err.number) call Err.clear() call LBound(True) - todo_wine_ok Err.number = 13, "LBound(bool) Err.number = " & Err.number + call ok(Err.number = 13, "LBound(bool) Err.number = " & Err.number) call Err.clear() call LBound(3.14) - todo_wine_ok Err.number = 13, "LBound(double) Err.number = " & Err.number + call ok(Err.number = 13, "LBound(double) Err.number = " & Err.number) call Err.clear() call LBound(nothingObj) - todo_wine_ok Err.number = 91, "LBound(Nothing) Err.number = " & Err.number + call ok(Err.number = 91, "LBound(Nothing) Err.number = " & Err.number) call Err.clear() call LBound(emptyObj) - todo_wine_ok Err.number = 438, "LBound(no-default-object) Err.number = " & Err.number + call ok(Err.number = 438, "LBound(no-default-object) Err.number = " & Err.number) call Err.clear() call LBound(dictObj) - todo_wine_ok Err.number = 450, "LBound(default-needs-arg) Err.number = " & Err.number + call ok(Err.number = 450, "LBound(default-needs-arg) Err.number = " & Err.number) call Err.clear() call LBound(arr, 1, 2) call ok(Err.number = 450, "Err.number = " & Err.number) @@ -389,25 +389,25 @@ sub testUBoundError() call ok(Err.number = 13, "Err.number = " & Err.number) call Err.clear() call UBound(42) - todo_wine_ok Err.number = 13, "UBound(int) Err.number = " & Err.number + call ok(Err.number = 13, "UBound(int) Err.number = " & Err.number) call Err.clear() call UBound("str") - todo_wine_ok Err.number = 13, "UBound(string) Err.number = " & Err.number + call ok(Err.number = 13, "UBound(string) Err.number = " & Err.number) call Err.clear() call UBound(True) - todo_wine_ok Err.number = 13, "UBound(bool) Err.number = " & Err.number + call ok(Err.number = 13, "UBound(bool) Err.number = " & Err.number) call Err.clear() call UBound(3.14) - todo_wine_ok Err.number = 13, "UBound(double) Err.number = " & Err.number + call ok(Err.number = 13, "UBound(double) Err.number = " & Err.number) call Err.clear() call UBound(nothingObj) - todo_wine_ok Err.number = 91, "UBound(Nothing) Err.number = " & Err.number + call ok(Err.number = 91, "UBound(Nothing) Err.number = " & Err.number) call Err.clear() call UBound(emptyObj) - todo_wine_ok Err.number = 438, "UBound(no-default-object) Err.number = " & Err.number + call ok(Err.number = 438, "UBound(no-default-object) Err.number = " & Err.number) call Err.clear() call UBound(dictObj) - todo_wine_ok Err.number = 450, "UBound(default-needs-arg) Err.number = " & Err.number + call ok(Err.number = 450, "UBound(default-needs-arg) Err.number = " & Err.number) call Err.clear() call UBound(arr, 1, 2) call ok(Err.number = 450, "Err.number = " & Err.number) @@ -418,6 +418,36 @@ end sub call testLBoundError() call testUBoundError() +Class ArrayDefaultClass + Public Default Function GetArr + GetArr = Array(10, 20, 30) + End Function +End Class + +Class ScalarDefaultClass + Public Default Function GetIt + GetIt = 42 + End Function +End Class + +sub testBoundDispatchDefault() + Dim arrObj : Set arrObj = new ArrayDefaultClass + Dim scalarObj : Set scalarObj = new ScalarDefaultClass + + call ok(LBound(arrObj) = 0, "LBound(array-default) = " & LBound(arrObj)) + call ok(UBound(arrObj) = 2, "UBound(array-default) = " & UBound(arrObj)) + + on error resume next + Err.Clear() + call LBound(scalarObj) + call ok(Err.number = 13, "LBound(scalar-default) Err.number = " & Err.number) + Err.Clear() + call UBound(scalarObj) + call ok(Err.number = 13, "UBound(scalar-default) Err.number = " & Err.number) +end sub + +call testBoundDispatchDefault() + sub testBoundUninitArray() Dim u() on error resume next -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10895
participants (2)
-
Francis De Brabandere -
Francis De Brabandere (@francisdb)