From: Francis De Brabandere <francisdb@gmail.com> Native VarXor already converts a BSTR operand to VT_I4 when it parses as a number, falling back to VT_BOOL otherwise; VarAnd, VarOr and VarImp do not. That left expressions like ""1"" And ""2"" producing Boolean[True] in Wine instead of native's Long[0]. Apply the same coercion in interp_and / interp_or / interp_imp before calling oleaut32 so the bitwise result type matches. --- dlls/vbscript/interp.c | 43 +++++++++++++++++++++++++++++++++--- dlls/vbscript/tests/lang.vbs | 18 +++++++-------- 2 files changed, 49 insertions(+), 12 deletions(-) diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c index 219b4fdefda..b0dda54a584 100644 --- a/dlls/vbscript/interp.c +++ b/dlls/vbscript/interp.c @@ -2078,6 +2078,31 @@ static inline void coerce_empty_to_i2(variant_val_t *val) val->owned = TRUE; } +/* Native And/Or/Imp coerce a BSTR operand to a number when it parses as one, + * falling back to a Boolean conversion otherwise. VarXor already does this + * internally; VarAnd/VarOr/VarImp do not, so VBScript needs to coerce first. */ +static HRESULT coerce_str_to_num_or_bool(variant_val_t *val) +{ + DOUBLE d; + HRESULT hres; + VARTYPE target; + + if(V_VT(val->v) != VT_BSTR) + return S_OK; + + target = SUCCEEDED(VarR8FromStr(V_BSTR(val->v), LOCALE_USER_DEFAULT, 0, &d)) ? VT_I4 : VT_BOOL; + VariantInit(&val->store); + hres = VariantChangeType(&val->store, val->v, VARIANT_LOCALBOOL, target); + if(FAILED(hres)) + return hres; + + if(val->owned) + VariantClear(val->v); + val->v = &val->store; + val->owned = TRUE; + return S_OK; +} + static HRESULT interp_not(exec_ctx_t *ctx) { variant_val_t val; @@ -2115,7 +2140,11 @@ static HRESULT interp_and(exec_ctx_t *ctx) if(SUCCEEDED(hres)) { coerce_empty_to_i4(&l); coerce_empty_to_i4(&r); - hres = VarAnd(l.v, r.v, &v); + hres = coerce_str_to_num_or_bool(&l); + if(SUCCEEDED(hres)) + hres = coerce_str_to_num_or_bool(&r); + if(SUCCEEDED(hres)) + hres = VarAnd(l.v, r.v, &v); release_val(&l); } release_val(&r); @@ -2141,7 +2170,11 @@ static HRESULT interp_or(exec_ctx_t *ctx) if(SUCCEEDED(hres)) { coerce_empty_to_i4(&l); coerce_empty_to_i4(&r); - hres = VarOr(l.v, r.v, &v); + hres = coerce_str_to_num_or_bool(&l); + if(SUCCEEDED(hres)) + hres = coerce_str_to_num_or_bool(&r); + if(SUCCEEDED(hres)) + hres = VarOr(l.v, r.v, &v); release_val(&l); } release_val(&r); @@ -2229,7 +2262,11 @@ static HRESULT interp_imp(exec_ctx_t *ctx) } else { coerce_empty_to_i4(&l); coerce_empty_to_i4(&r); - hres = VarImp(l.v, r.v, &v); + hres = coerce_str_to_num_or_bool(&l); + if(SUCCEEDED(hres)) + hres = coerce_str_to_num_or_bool(&r); + if(SUCCEEDED(hres)) + hres = VarImp(l.v, r.v, &v); } release_val(&l); } diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs index 5ffa8546c00..1f7bd5491c7 100644 --- a/dlls/vbscript/tests/lang.vbs +++ b/dlls/vbscript/tests/lang.vbs @@ -539,19 +539,19 @@ Call ok(getVT(Not Empty) = "VT_I4", "getVT(Not Empty) = " & getVT(Not E ' string as a Boolean. Sub testLogicalBstr Dim r - r = "1" And "2" : todo_wine_ok r = 0, """1"" And ""2"" is not 0" - r = "5" And "3" : todo_wine_ok r = 1, """5"" And ""3"" is not 1" - r = "1" And "2" : todo_wine_ok getVT(r) = "VT_I4*", "getVT(""1"" And ""2"") = " & getVT(r) - r = "1" Or "2" : todo_wine_ok r = 3, """1"" Or ""2"" is not 3" - r = "5" Or "3" : todo_wine_ok r = 7, """5"" Or ""3"" is not 7" - r = "1" Or "2" : todo_wine_ok getVT(r) = "VT_I4*", "getVT(""1"" Or ""2"") = " & getVT(r) - r = "1" Imp "2" : todo_wine_ok r = -2, """1"" Imp ""2"" is not -2" - r = "1" Imp "2" : todo_wine_ok getVT(r) = "VT_I4*", "getVT(""1"" Imp ""2"") = " & getVT(r) + r = "1" And "2" : call ok(r = 0, """1"" And ""2"" is not 0") + r = "5" And "3" : call ok(r = 1, """5"" And ""3"" is not 1") + r = "1" And "2" : call ok(getVT(r) = "VT_I4*", "getVT(""1"" And ""2"") = " & getVT(r)) + r = "1" Or "2" : call ok(r = 3, """1"" Or ""2"" is not 3") + r = "5" Or "3" : call ok(r = 7, """5"" Or ""3"" is not 7") + r = "1" Or "2" : call ok(getVT(r) = "VT_I4*", "getVT(""1"" Or ""2"") = " & getVT(r)) + r = "1" Imp "2" : call ok(r = -2, """1"" Imp ""2"" is not -2") + r = "1" Imp "2" : call ok(getVT(r) = "VT_I4*", "getVT(""1"" Imp ""2"") = " & getVT(r)) ' Mixed BSTR + numeric stays Long. r = 5 And "3" : call ok(r = 1, "5 And ""3"" is not 1") r = "5" And 3 : call ok(r = 1, """5"" And 3 is not 1") - r = 5 And "3" : todo_wine_ok getVT(r) = "VT_I4*", "getVT(5 And ""3"") = " & getVT(r) + r = 5 And "3" : call ok(getVT(r) = "VT_I4*", "getVT(5 And ""3"") = " & getVT(r)) End Sub Call testLogicalBstr -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10901