From: Francis De Brabandere <francisdb@gmail.com> 0xFF on VT_UI1 is not VARIANT_TRUE (unsigned), so drop its all-ones check and let bitwise Imp run. VT_CY stores values ×10000, so compare the scaled int64 against -10000 rather than -1 for the "True" case. --- dlls/oleaut32/tests/vartest.c | 20 ++++++++++++++++++++ dlls/oleaut32/variant.c | 7 +++++-- dlls/vbscript/tests/lang.vbs | 10 ++++++++++ 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/dlls/oleaut32/tests/vartest.c b/dlls/oleaut32/tests/vartest.c index c362f9854fe..53ed11f4e88 100644 --- a/dlls/oleaut32/tests/vartest.c +++ b/dlls/oleaut32/tests/vartest.c @@ -9759,6 +9759,26 @@ static void test_VarImp(void) V_I8(&result), -3); } + /* All-ones left Imp Null. For every signed type whose -1 bit pattern is + * VARIANT_TRUE the three-valued "True Imp unknown = unknown" rule applies + * and the result is Null. VT_UI1 is unsigned so 0xFF is just a byte value + * and Imp computes the bitwise result (~0xFF = 0) in VT_UI1. */ + VARIMP(I2,-1,NULL,0,NULL,0); + VARIMP(I4,-1,NULL,0,NULL,0); + VARIMP(R8,-1.0,NULL,0,NULL,0); + VARIMP(UI1,255,NULL,0,UI1,0); + + /* VT_CY stores values scaled by 10000 in .int64, so CY -1 has .int64 of + * -10000 (not -1). Previously Wine's all-ones check compared against -1 + * and never fired, producing a bitwise result instead of Null. */ + V_VT(&left) = VT_CY; + V_CY(&left).int64 = -10000; + V_VT(&right) = VT_NULL; + V_I4(&right) = 0; + V_VT(&exp) = VT_NULL; + V_I4(&exp) = 0; + test_var_call2(__LINE__, pVarImp, &left, &right, &exp); + SysFreeString(false_str); SysFreeString(true_str); } diff --git a/dlls/oleaut32/variant.c b/dlls/oleaut32/variant.c index 4695ca66bb0..c7213e9f7c3 100644 --- a/dlls/oleaut32/variant.c +++ b/dlls/oleaut32/variant.c @@ -5948,7 +5948,9 @@ HRESULT WINAPI VarImp(LPVARIANT left, LPVARIANT right, LPVARIANT result) switch(leftvt) { case VT_I1: if (V_I1(left) == -1) resvt = VT_NULL; break; - case VT_UI1: if (V_UI1(left) == 0xff) resvt = VT_NULL; break; + /* UI1 is unsigned — 0xFF is the max value, not VARIANT_TRUE, so the + * three-valued `True Imp Null = Null` rule does not apply. Let the + * main computation produce the bitwise Imp result instead. */ case VT_I2: if (V_I2(left) == -1) resvt = VT_NULL; break; case VT_UI2: if (V_UI2(left) == 0xffff) resvt = VT_NULL; break; case VT_INT: if (V_INT(left) == -1) resvt = VT_NULL; break; @@ -5960,7 +5962,8 @@ HRESULT WINAPI VarImp(LPVARIANT left, LPVARIANT right, LPVARIANT result) case VT_BOOL: if (V_BOOL(left) == VARIANT_TRUE) resvt = VT_NULL; break; case VT_R4: if (V_R4(left) == -1.0) resvt = VT_NULL; break; case VT_R8: if (V_R8(left) == -1.0) resvt = VT_NULL; break; - case VT_CY: if (V_CY(left).int64 == -1) resvt = VT_NULL; break; + /* VT_CY stores values scaled by 10000, so -1 is -10000 in .int64. */ + case VT_CY: if (V_CY(left).int64 == -10000) resvt = VT_NULL; break; case VT_DECIMAL: if (V_DECIMAL(left).Hi32 == 0xffffffff) resvt = VT_NULL; diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs index 7bc3aaaa4a1..a6ddf86fb29 100644 --- a/dlls/vbscript/tests/lang.vbs +++ b/dlls/vbscript/tests/lang.vbs @@ -206,6 +206,16 @@ Call ok((CInt(0) And Null) = 0, "CInt(0) And Null is not 0") Call ok(getVT(CInt(0) And Null) = "VT_I2", "getVT(CInt(0) And Null) = " & getVT(CInt(0) And Null)) Call ok(isNull(CInt(5) And Null), "CInt(5) And Null is not Null") +' Smoke checks that VBScript's sibling logical operators reach Var* +' correctly and propagate the result payload. The full conformance tables +' live in dlls/oleaut32/tests/vartest.c. +Call ok((True Or Null) = True, "True Or Null is not True") +Call ok(isNull(False Or Null), "False Or Null is not Null") +Call ok(isNull(CInt(5) Xor Null), "CInt(5) Xor Null is not Null") +Call ok(isNull(CInt(5) Eqv Null), "CInt(5) Eqv Null is not Null") +Call ok((CByte(255) Imp Null) = 0, "CByte(255) Imp Null is not 0") +Call ok((Not CLng(0)) = -1, "Not CLng(0) is not -1") + Call ok(2 >= 1, "! 2 >= 1") Call ok(2 >= 2, "! 2 >= 2") Call ok(2 => 1, "! 2 => 1") -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10673