[PATCH v13 0/2] MR8635: oleaut32: Convert VT_BSTR numeric strings to VT_I4 in VarAnd
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=56280 -- v13: oleaut32: Convert VT_BSTR numeric strings to VT_I4 in VarAnd. oleaut32/tests: Add more test cases for VarAnd https://gitlab.winehq.org/wine/wine/-/merge_requests/8635
From: Maotong Zhang <zmtong1988@gmail.com> --- dlls/oleaut32/tests/vartest.c | 43 ++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/dlls/oleaut32/tests/vartest.c b/dlls/oleaut32/tests/vartest.c index e5bbecbdd3f..7c3b6b12938 100644 --- a/dlls/oleaut32/tests/vartest.c +++ b/dlls/oleaut32/tests/vartest.c @@ -6814,7 +6814,8 @@ static void test_VarAnd(void) static const WCHAR szFalse[] = { '#','F','A','L','S','E','#','\0' }; static const WCHAR szTrue[] = { '#','T','R','U','E','#','\0' }; VARIANT left, right, exp, result; - BSTR false_str, true_str; + BSTR false_str, true_str, bstrmaxi4, bstrmini4, bstr9999999998, bstr3; + BSTR bstrfloat1p49, bstrfloatm1p49, bstrfloat1p59, bstrfloatm1p59; VARTYPE i; HRESULT hres; @@ -6822,6 +6823,14 @@ static void test_VarAnd(void) true_str = SysAllocString(szTrue); false_str = SysAllocString(szFalse); + bstrmaxi4 = SysAllocString(L"2147483647"); + bstrmini4 = SysAllocString(L"-2147483648"); + bstr9999999998 = SysAllocString(L"9999999998"); + bstr3 = SysAllocString(L"3"); + bstrfloat1p49 = SysAllocString(L"1.49"); + bstrfloatm1p49 = SysAllocString(L"-1.49"); + bstrfloat1p59 = SysAllocString(L"1.59"); + bstrfloatm1p59 = SysAllocString(L"-1.59"); /* Test all possible flag/vt combinations & the resulting vt type */ for (i = 0; i < ARRAY_SIZE(ExtraFlags); i++) @@ -7154,6 +7163,8 @@ static void test_VarAnd(void) VARAND(UI1,255,BSTR,false_str,I2,0); VARAND(UI1,0,BSTR,true_str,I2,0); VARAND(UI1,255,BSTR,true_str,I2,255); + VARAND(UI1, 1, BSTR, bstrmaxi4, I4, 1); + VARAND(UI1, 1, BSTR, bstrmini4, I4, 0); VARANDCY(UI1,255,10000,I4,1); VARANDCY(UI1,255,0,I4,0); VARANDCY(UI1,0,0,I4,0); @@ -7197,6 +7208,8 @@ static void test_VarAnd(void) VARAND(I2,-1,BSTR,false_str,I2,0); VARAND(I2,0,BSTR,true_str,I2,0); VARAND(I2,-1,BSTR,true_str,I2,-1); + VARAND(I2,1,BSTR,bstrmaxi4,I4,1); + VARAND(I2,1,BSTR,bstrmini4,I4,0); VARANDCY(I2,-1,10000,I4,1); VARANDCY(I2,-1,0,I4,0); VARANDCY(I2,0,0,I4,0); @@ -7458,11 +7471,39 @@ static void test_VarAnd(void) VARAND(BSTR,false_str,BSTR,false_str,BOOL,0); VARAND(BSTR,true_str,BSTR,false_str,BOOL,VARIANT_FALSE); VARAND(BSTR,true_str,BSTR,true_str,BOOL,VARIANT_TRUE); + VARAND(BSTR, bstrfloat1p49, I2, 1, I4, 1); + VARAND(BSTR, bstrfloatm1p49, I2, 1, I4, 1); + VARAND(BSTR, bstrfloat1p59, I2, 1, I4, 0); + VARAND(BSTR, bstrfloatm1p59, I2, 1, I4, 0); VARANDCY(BSTR,true_str,10000,I4,1); VARANDCY(BSTR,false_str,10000,I4,0); + VariantInit(&left); + VariantInit(&right); + VariantInit(&result); + + V_VT(&left) = VT_BSTR; + V_BSTR(&left) = bstr9999999998; + V_VT(&right) = VT_BSTR; + V_BSTR(&right) = bstr3; + hres = pVarAnd(&left, &right, &result); + ok(hres == DISP_E_OVERFLOW,"got 0x%08lx\n", hres); + + VariantClear(&left); + VariantClear(&right); + VariantClear(&result); + + SysFreeString(true_str); SysFreeString(false_str); + SysFreeString(bstrmaxi4); + SysFreeString(bstrmini4); + SysFreeString(bstr9999999998); + SysFreeString(bstr3); + SysFreeString(bstrfloat1p49); + SysFreeString(bstrfloatm1p49); + SysFreeString(bstrfloat1p59); + SysFreeString(bstrfloatm1p59); } static void test_cmp( int line, LCID lcid, UINT flags, VARIANT *left, VARIANT *right, HRESULT result ) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/8635
From: Maotong Zhang <zmtong1988@gmail.com> --- dlls/oleaut32/variant.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/dlls/oleaut32/variant.c b/dlls/oleaut32/variant.c index 8b5e41ec66d..8f053ca4248 100644 --- a/dlls/oleaut32/variant.c +++ b/dlls/oleaut32/variant.c @@ -3132,7 +3132,18 @@ HRESULT WINAPI VarAnd(LPVARIANT left, LPVARIANT right, LPVARIANT result) hres = VariantChangeType(&varLeft,&varLeft, VARIANT_LOCALBOOL, VT_BOOL); if (SUCCEEDED(hres) && V_VT(&varLeft) != resvt) + { + if (V_VT(&varLeft) == VT_BSTR) + { + if (d > I4_MAX || d < I4_MIN) + { + hres = DISP_E_OVERFLOW; + goto VarAnd_Exit; + } + if (d >= I4_MIN && d <= I4_MAX) resvt = VT_I4; + } hres = VariantChangeType(&varLeft,&varLeft,0,resvt); + } if (FAILED(hres)) goto VarAnd_Exit; } @@ -3148,10 +3159,33 @@ HRESULT WINAPI VarAnd(LPVARIANT left, LPVARIANT right, LPVARIANT result) hres = VariantChangeType(&varRight, &varRight, VARIANT_LOCALBOOL, VT_BOOL); if (SUCCEEDED(hres) && V_VT(&varRight) != resvt) + { + if (V_VT(&varRight) == VT_BSTR) + { + if (d > I4_MAX || d < I4_MIN) + { + hres = DISP_E_OVERFLOW; + goto VarAnd_Exit; + } + if (d >= I4_MIN && d <= I4_MAX) resvt = VT_I4; + } hres = VariantChangeType(&varRight, &varRight, 0, resvt); + } if (FAILED(hres)) goto VarAnd_Exit; } + if (V_VT(&varLeft) != resvt) + { + hres = VariantChangeType(&varLeft, &varLeft, 0, resvt); + if (FAILED(hres)) goto VarAnd_Exit; + } + + if (V_VT(&varRight) != resvt) + { + hres = VariantChangeType(&varRight, &varRight, 0, resvt); + if (FAILED(hres)) goto VarAnd_Exit; + } + V_VT(result) = resvt; switch(resvt) { -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/8635
`(BSTR_numeric_over_I4, BSTR_anything_numeric)` — native errors with `DISP_E_OVERFLOW`, current patch silently returns wrong results because the BOOL fallback fires when the BSTR is too big to widen and the other side later bumps `resvt` to `I4`. E.g. `"9999999998" AND "3"` returns 3 here, native overflows.
Added implementation.
Fractional BSTRs use truncation toward zero on native, not banker's rounding: `"1.99" AND 1 = 1` and `"-1.99" AND 1 = 1` natively. Could compute the I4 directly from the parsed `d` (e.g. `(LONG)d` after the `VarR8FromStr` succeeds, when `d` fits I4) instead of round-tripping through `VariantChangeType(BSTR -> I4)`.
I added test cases: 1.49 and 1.59. No changes for now, (LONG)d is used for I4 cases.
Hex BSTRs with the sign bit set: native treats `"&HFFFFFFFF"` as signed `I4(-1)` and computes `-1 & 1 = 1`. Currently `VarR8FromStr` returns the unsigned value `4294967295`, the fits-in-I4 check fails, and the conversion overflows. Maybe special-case `"&H..."` via `VarI4FromStr`.
The Var**FromStr functions all rely on VARIANT_NumberFromBstr. Special handling may be needed for cases such as "&HFFFFFFFF". -- https://gitlab.winehq.org/wine/wine/-/merge_requests/8635#note_139349
participants (2)
-
Maotong Zhang -
Maotong Zhang (@xiaotong)