From: Francis De Brabandere <francisdb@gmail.com> VarCmp falls into its "BSTR always greater" branch for BSTR vs VT_BOOL, so every "True" = True / "False" = False returned False on Wine. VBScript coerces the boolean to its CStr form ("True"/"False") and string-compares; comparison is binary, not locale-aware (matches "abc" > True returning True on Windows). VarBstrFromBool / VariantChangeType yield "-1"/"0" (OLE numeric convention) and don't match what VBScript uses, so the strings are hardcoded. --- dlls/vbscript/interp.c | 20 ++++++++++++++++++++ dlls/vbscript/tests/lang.vbs | 24 +++++++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c index 58afe4c6b41..ce4cdd8cf87 100644 --- a/dlls/vbscript/interp.c +++ b/dlls/vbscript/interp.c @@ -2136,6 +2136,26 @@ static HRESULT var_cmp(exec_ctx_t *ctx, VARIANT *l, VARIANT *r) return VARCMP_EQ; } + /* VarCmp returns "BSTR always greater" for BSTR vs VT_BOOL; VBScript instead + * coerces the boolean to its CStr form ("True"/"False") and string-compares. + * (VarBstrFromBool yields "-1"/"0" — OLE numeric convention, not what VBScript + * uses.) */ + if((V_VT(l) == VT_BSTR && V_VT(r) == VT_BOOL) || + (V_VT(r) == VT_BSTR && V_VT(l) == VT_BOOL)) { + VARIANT_BOOL b = V_VT(l) == VT_BOOL ? V_BOOL(l) : V_BOOL(r); + VARIANT bool_str; + HRESULT hres; + + V_VT(&bool_str) = VT_BSTR; + V_BSTR(&bool_str) = SysAllocString(b ? L"True" : L"False"); + if(!V_BSTR(&bool_str)) + return E_OUTOFMEMORY; + hres = V_VT(l) == VT_BOOL ? VarCmp(&bool_str, r, 0, 0) + : VarCmp(l, &bool_str, 0, 0); + VariantClear(&bool_str); + return hres; + } + return VarCmp(l, r, ctx->script->lcid, 0); } diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs index e0de413be93..ad9018f143e 100644 --- a/dlls/vbscript/tests/lang.vbs +++ b/dlls/vbscript/tests/lang.vbs @@ -136,10 +136,32 @@ Call ok(30 > "0", "30 > ""0"" should be true") Call ok(9 < "10", "9 < ""10"" should be true") Call ok(42 = "42", "42 = ""42"" should be true") Call ok(not ("10" > "9"), """10"" > ""9"" should be false (string comparison)") -' String vs Boolean uses string comparison, not numeric conversion +' BSTR vs Boolean: string-compare against CStr(bool) ("True"/"False"), +' case-sensitive, no whitespace trimming, no numeric coercion, no type-mismatch. +Call ok("True" = True, """True"" = True should be true") +Call ok("False" = False, """False"" = False should be true") +Call ok(not ("True" = False), """True"" = False should be false") +Call ok(not ("False" = True), """False"" = True should be false") +Call ok(not ("true" = True), """true"" = True should be false (case-sensitive)") +Call ok(not ("TRUE" = True), """TRUE"" = True should be false (case-sensitive)") +Call ok(not ("True " = True), """True "" = True should be false (no trim)") +Call ok(not (" True" = True), """ True"" = True should be false (no trim)") Call ok(not ("1" = True), """1"" = True should be false") Call ok(not ("-1" = True), """-1"" = True should be false") Call ok(not ("0" = False), """0"" = False should be false") +Call ok(not ("-1" = False), """-1"" = False should be false") +Call ok(not ("True" <> True), """True"" <> True should be false") +Call ok("False" <> True, """False"" <> True should be true") +Call ok(not ("abc" = True), """abc"" = True should be false (no error)") +Call ok(not ("" = True), """"" = True should be false (no error)") +Call ok(not ("" = False), """"" = False should be false (no error)") +Call ok(True = "True", "True = ""True"" should be true") +Call ok(False = "False", "False = ""False"" should be true") +' Relational: lexicographic string comparison after coercing bool to BSTR +Call ok("True" > False, """True"" > False should be true (lex)") +Call ok(not ("True" < False), """True"" < False should be false (lex)") +Call ok(not ("False" > True), """False"" > True should be false (lex)") +Call ok("abc" > True, """abc"" > True should be true (lex)") ' Non-numeric string compared to number should raise type mismatch on error resume next err.clear -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10764