Don't trash the dst variant if we can't do the type conversion. Add a test for this.
diff --git a/dlls/oleaut32/tests/vartype.c b/dlls/oleaut32/tests/vartype.c index 3f48c90..f9224c7 100644 --- a/dlls/oleaut32/tests/vartype.c +++ b/dlls/oleaut32/tests/vartype.c
@@ -5304,6 +5304,30 @@ ok(hRes == DISP_E_BADVARTYPE, "VariantChangeTypeEx should return DISP_E_BADVARTYPE\n"); } +/* Dst Variant should remain unchanged if VariantChangeType cannot convert */ +static void test_ChangeType_keep_dst() +{ + VARIANT v1, v2; + BSTR bstr; + WCHAR testW[] = {'t','e','s','t',0}; + HRESULT hres; + + bstr = SysAllocString(testW); + VariantClear(&v1); + VariantClear(&v2); + V_VT(&v1) = VT_BSTR; + V_BSTR(&v1) = bstr; + hres = VariantChangeTypeEx(&v1, &v1, 0, 0, VT_INT); + ok(hres == DISP_E_TYPEMISMATCH, "VariantChangeTypeEx returns %08lx\n", hres); + ok(V_VT(&v1) == VT_BSTR && V_BSTR(&v1) == bstr, "VariantChangeTypeEx changed dst variant\n"); + V_VT(&v2) = VT_INT; + V_INT(&v2) = 4; + hres = VariantChangeTypeEx(&v2, &v1, 0, 0, VT_INT); + ok(hres == DISP_E_TYPEMISMATCH, "VariantChangeTypeEx returns %08lx\n", hres); + ok(V_VT(&v2) == VT_INT && V_INT(&v2) == 4, "VariantChangeTypeEx changed dst variant\n"); + SysFreeString(bstr); +} + START_TEST(vartype) { hOleaut32 = LoadLibraryA("oleaut32.dll"); @@ -5594,4 +5618,5 @@ test_ClearCustData(); test_NullByRef(); + test_ChangeType_keep_dst(); }
diff --git a/dlls/oleaut32/variant.c b/dlls/oleaut32/variant.c index 61e8e76..da16f98 100644 --- a/dlls/oleaut32/variant.c +++ b/dlls/oleaut32/variant.c
@@ -982,31 +982,35 @@ if (SUCCEEDED(res)) { - VARIANTARG vTmp; + VARIANTARG vTmp, vSrcDeref; if(V_VT(pvargSrc)&VT_BYREF && !V_BYREF(pvargSrc)) res = DISP_E_TYPEMISMATCH; else { V_VT(&vTmp) = VT_EMPTY; - res = VariantCopyInd(&vTmp, pvargSrc); + V_VT(&vSrcDeref) = VT_EMPTY; + VariantClear(&vTmp); + VariantClear(&vSrcDeref); } if (SUCCEEDED(res)) { - res = VariantClear(pvargDest); - + res = VariantCopyInd(&vSrcDeref, pvargSrc); if (SUCCEEDED(res)) { - if (V_ISARRAY(&vTmp) || (vt & VT_ARRAY)) - res = VARIANT_CoerceArray(pvargDest, &vTmp, vt); + if (V_ISARRAY(&vSrcDeref) || (vt & VT_ARRAY)) + res = VARIANT_CoerceArray(&vTmp, &vSrcDeref, vt); else - res = VARIANT_Coerce(pvargDest, lcid, wFlags, &vTmp, vt); + res = VARIANT_Coerce(&vTmp, lcid, wFlags, &vSrcDeref, vt); - if (SUCCEEDED(res)) - V_VT(pvargDest) = vt; + if (SUCCEEDED(res)) { + V_VT(&vTmp) = vt; + VariantCopy(pvargDest, &vTmp); + } + VariantClear(&vTmp); + VariantClear(&vSrcDeref); } - VariantClear(&vTmp); } } }