diff --git a/dlls/oleaut32/typelib.c b/dlls/oleaut32/typelib.c index 07447f2c5a2..bc92f5d23d1 100644 --- a/dlls/oleaut32/typelib.c +++ b/dlls/oleaut32/typelib.c @@ -6146,7 +6146,8 @@ static HRESULT WINAPI ITypeInfo_fnInvoke( else { VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams); - hres = VariantCopy(&missing_arg[i], src_arg); + if (wParamFlags & PARAMFLAG_FIN) + hres = VariantCopy(&missing_arg[i], src_arg); V_VARIANTREF(&rgvarg[i]) = &missing_arg[i]; } V_VT(&rgvarg[i]) = rgvt[i]; @@ -6184,8 +6185,10 @@ static HRESULT WINAPI ITypeInfo_fnInvoke( else if ((rgvt[i] & VT_BYREF) && !V_ISBYREF(src_arg)) { VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams); - V_VT(&missing_arg[i]) = V_VT(src_arg); - hres = VariantChangeType(&missing_arg[i], src_arg, 0, rgvt[i] & ~VT_BYREF); + if (wParamFlags & PARAMFLAG_FIN) + hres = VariantChangeType(&missing_arg[i], src_arg, 0, rgvt[i] & ~VT_BYREF); + else + V_VT(&missing_arg[i]) = rgvt[i] & ~VT_BYREF; V_BYREF(&rgvarg[i]) = &V_NONE(&missing_arg[i]); V_VT(&rgvarg[i]) = rgvt[i]; } @@ -6268,6 +6271,7 @@ static HRESULT WINAPI ITypeInfo_fnInvoke( for (i = 0; i < func_desc->cParams; i++) { USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags; + VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams); if (wParamFlags & PARAMFLAG_FLCID) continue; @@ -6286,33 +6290,23 @@ static HRESULT WINAPI ITypeInfo_fnInvoke( hres = VariantCopyInd(pVarResult, prgpvarg[i]); } - /* free data stored in varresult. Note that - * VariantClear doesn't do what we want because we are - * working with byref types. */ - /* FIXME: clear safearrays, bstrs, records and - * variants here too */ - if ((V_VT(prgpvarg[i]) == (VT_UNKNOWN | VT_BYREF)) || - (V_VT(prgpvarg[i]) == (VT_DISPATCH | VT_BYREF))) - { - if(*V_UNKNOWNREF(prgpvarg[i])) - IUnknown_Release(*V_UNKNOWNREF(prgpvarg[i])); - } - break; + VARIANT_ClearInd(prgpvarg[i]); } else if (vargs_converted < pDispParams->cArgs) { + VARIANTARG *arg = &pDispParams->rgvarg[pDispParams->cArgs - 1 - vargs_converted]; if (wParamFlags & PARAMFLAG_FOUT) { - VARIANTARG *arg = &pDispParams->rgvarg[pDispParams->cArgs - 1 - vargs_converted]; - - if ((rgvt[i] == VT_BYREF) && (V_VT(arg) != VT_BYREF)) + if ((rgvt[i] & VT_BYREF) && !(V_VT(arg) & VT_BYREF)) + { hres = VariantChangeType(arg, &rgvarg[i], 0, V_VT(arg)); - if (FAILED(hres)) - { - ERR("failed to convert param %d to vt %d\n", i, - V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1 - vargs_converted])); - break; + if (FAILED(hres)) + { + ERR("failed to convert param %d to vt %d\n", i, + V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1 - vargs_converted])); + break; + } } } else if (V_VT(prgpvarg[i]) == (VT_VARIANT | VT_ARRAY) && @@ -6351,6 +6345,8 @@ static HRESULT WINAPI ITypeInfo_fnInvoke( if (wParamFlags & PARAMFLAG_FHASDEFAULT) VariantClear(&rgvarg[i]); } + + VariantClear(&missing_arg[i]); } if ((V_VT(&varresult) == VT_ERROR) && FAILED(V_ERROR(&varresult))) diff --git a/dlls/oleaut32/variant.c b/dlls/oleaut32/variant.c index e92a63dcdd7..cd99814d8e9 100644 --- a/dlls/oleaut32/variant.c +++ b/dlls/oleaut32/variant.c @@ -578,6 +578,66 @@ void WINAPI VariantInit(VARIANTARG* pVarg) V_VT(pVarg) = VT_EMPTY; /* Native doesn't set any other fields */ } +HRESULT VARIANT_ClearInd(VARIANTARG *pVarg) +{ + HRESULT hres; + + TRACE("(%p->(%s%s))\n", pVarg, debugstr_VT(pVarg), debugstr_VF(pVarg)); + + hres = VARIANT_ValidateType(V_VT(pVarg)); + if (FAILED(hres)) + return hres; + + switch (V_VT(pVarg)) + { + case VT_DISPATCH: + case VT_UNKNOWN: + if (V_UNKNOWN(pVarg)) + IUnknown_Release(V_UNKNOWN(pVarg)); + break; + case VT_UNKNOWN | VT_BYREF: + case VT_DISPATCH | VT_BYREF: + if(*V_UNKNOWNREF(pVarg)) + IUnknown_Release(*V_UNKNOWNREF(pVarg)); + break; + case VT_BSTR: + SysFreeString(V_BSTR(pVarg)); + break; + case VT_BSTR | VT_BYREF: + SysFreeString(*V_BSTRREF(pVarg)); + break; + case VT_VARIANT | VT_BYREF: + VariantClear(V_VARIANTREF(pVarg)); + break; + case VT_RECORD: + case VT_RECORD | VT_BYREF: + { + struct __tagBRECORD* pBr = &V_UNION(pVarg,brecVal); + if (pBr->pRecInfo) + { + IRecordInfo_RecordClear(pBr->pRecInfo, pBr->pvRecord); + IRecordInfo_Release(pBr->pRecInfo); + } + break; + } + default: + if (V_ISARRAY(pVarg) || (V_VT(pVarg) & ~VT_BYREF) == VT_SAFEARRAY) + { + if (V_ISBYREF(pVarg)) + { + if (*V_ARRAYREF(pVarg)) + hres = SafeArrayDestroy(*V_ARRAYREF(pVarg)); + } + else if (V_ARRAY(pVarg)) + hres = SafeArrayDestroy(V_ARRAY(pVarg)); + } + break; + } + + V_VT(pVarg) = VT_EMPTY; + return hres; +} + /****************************************************************************** * VariantClear [OLEAUT32.9] * diff --git a/dlls/oleaut32/variant.h b/dlls/oleaut32/variant.h index c881b24d60f..265fcc8041e 100644 --- a/dlls/oleaut32/variant.h +++ b/dlls/oleaut32/variant.h @@ -126,3 +126,4 @@ typedef struct tagVARIANT_NUMBER_CHARS BOOL VARIANT_GetLocalisedText(LANGID, DWORD, WCHAR *); +HRESULT VARIANT_ClearInd(VARIANTARG *);