ole: ITypeInfo::Invoke rewrite.

Re-implement ITypeInfo::Invoke on top of DispCallFunc and
VariantChangeType instead of _invoke and _copy_arg.
This commit is contained in:
Robert Shearman 2006-01-06 21:15:48 +01:00 committed by Alexandre Julliard
parent 95312fcb63
commit 8cf5373f60
1 changed files with 107 additions and 101 deletions

View File

@ -5358,153 +5358,159 @@ static HRESULT WINAPI ITypeInfo_fnInvoke(
switch (func_desc->funckind) {
case FUNC_PUREVIRTUAL:
case FUNC_VIRTUAL: {
int numargs, numargs2, argspos, args2pos;
DWORD *args , *args2;
VARIANT *rgvarg = HeapAlloc(GetProcessHeap(), 0, sizeof(VARIANT) * func_desc->cParams);
VARIANTARG *rgvarg = NULL;
VARIANTARG **prgpvarg = HeapAlloc(GetProcessHeap(), 0, sizeof(*prgpvarg) * func_desc->cParams);
VARTYPE *rgvt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*rgvt) * func_desc->cParams);
VARIANT varresult;
memcpy(rgvarg,pDispParams->rgvarg,sizeof(VARIANT)*pDispParams->cArgs);
SHORT missing_param_offset = func_desc->cParams;
SHORT missing_params = 0;
void *retval; /* pointer for storing byref retvals in */
hres = S_OK;
numargs = 1; /* sizeof(thisptr) */
numargs2 = 0;
for (i = 0; i < func_desc->cParams; i++)
{
TYPEDESC *tdesc = &func_desc->lprgelemdescParam[i].tdesc;
numargs += _argsize(tdesc->vt);
if (i>=pDispParams->cArgs) { /* arguments to return */
if (tdesc->vt == VT_PTR) {
numargs2 += _argsize(tdesc->u.lptdesc->vt);
} else {
FIXME("The variant type here should have been VT_PTR, not vt %d\n", tdesc->vt);
numargs2 += _argsize(tdesc->vt);
}
}
USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
hres = typedescvt_to_variantvt((ITypeInfo *)iface, tdesc, &rgvt[i]);
if (FAILED(hres))
goto func_fail;
if ((i >= pDispParams->cArgs) &&
(wParamFlags & PARAMFLAG_FOPT) &&
!(wParamFlags & PARAMFLAG_FHASDEFAULT))
missing_params++;
}
args = HeapAlloc(GetProcessHeap(),0,sizeof(DWORD)*numargs);
args2 = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DWORD)*numargs2);
rgvarg = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*rgvarg) * (func_desc->cParams + missing_params));
args[0] = (DWORD)pIUnk;
argspos = 1; args2pos = 0;
TRACE("changing args\n");
for (i = 0; i < func_desc->cParams; i++)
{
ELEMDESC *elemdesc = &(func_desc->lprgelemdescParam[i]);
TYPEDESC *tdesc = &(elemdesc->tdesc);
USHORT paramFlags = elemdesc->u.paramdesc.wParamFlags;
int arglen = _argsize(tdesc->vt);
if (i<pDispParams->cArgs)
USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
if (wParamFlags & PARAMFLAG_FRETVAL)
{
VARIANT *arg = &rgvarg[pDispParams->cArgs-i-1];
if (paramFlags & PARAMFLAG_FOPT) {
if(i < func_desc->cParams - func_desc->cParamsOpt)
ERR("Parameter has PARAMFLAG_FOPT flag but is not one of last cParamOpt parameters\n");
if(V_VT(arg) == VT_EMPTY
|| ((V_ISBYREF(arg)) && !V_BYREF(arg))) {
/* FIXME: Documentation says that we do this when parameter is left unspecified.
How to determine it? */
if(paramFlags & PARAMFLAG_FHASDEFAULT)
FIXME("PARAMFLAG_FHASDEFAULT flag not supported\n");
V_VT(arg) = VT_ERROR;
V_ERROR(arg) = DISP_E_PARAMNOTFOUND;
arglen = _argsize(VT_ERROR);
}
}
hres = _copy_arg(iface, tdesc, &args[argspos], arg, tdesc->vt);
if (FAILED(hres)) goto func_fail;
argspos += arglen;
}
else if (paramFlags & PARAMFLAG_FOPT)
/* note: this check is placed so that if the caller passes
* in a VARIANTARG for the retval we just ignore it, like
* native does */
if (i == func_desc->cParams - 1)
{
VARIANT *arg = &rgvarg[i];
if (i < func_desc->cParams - func_desc->cParamsOpt)
ERR("Parameter has PARAMFLAG_FOPT flag but is not one of last cParamOpt parameters\n");
if (paramFlags & PARAMFLAG_FHASDEFAULT)
FIXME("PARAMFLAG_FHASDEFAULT flag not supported\n");
V_VT(arg) = VT_ERROR;
V_ERROR(arg) = DISP_E_PARAMNOTFOUND;
arglen = _argsize(VT_ERROR);
hres = _copy_arg(iface, tdesc, &args[argspos], arg, tdesc->vt);
if (FAILED(hres)) goto func_fail;
argspos += arglen;
VARIANTARG *arg;
arg = prgpvarg[i] = &rgvarg[i];
memset(arg, 0, sizeof(*arg));
V_VT(arg) = rgvt[i];
retval = NULL;
V_BYREF(arg) = &retval;
}
else
{
if (tdesc->vt == VT_PTR)
arglen = _argsize(tdesc->u.lptdesc->vt);
ERR("[retval] parameter must be the last parameter of the method (%d/%d)\n", i, func_desc->cParams);
hres = E_UNEXPECTED;
break;
}
}
else if (i < pDispParams->cArgs)
{
V_VT(&rgvarg[i]) = V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1 - i]);
dump_Variant(&pDispParams->rgvarg[pDispParams->cArgs - 1 - i]);
/* FIXME: this doesn't work for VT_BYREF arguments if
* they are not the same type as in the paramdesc */
hres = VariantChangeType(&rgvarg[i], &pDispParams->rgvarg[pDispParams->cArgs - 1 - i], 0, rgvt[i]);
if (FAILED(hres))
{
ERR("failed to convert param %d to vt %d\n", i, rgvt[i]);
break;
}
V_VT(&rgvarg[i]) = rgvt[i];
prgpvarg[i] = &rgvarg[i];
}
else if (wParamFlags & PARAMFLAG_FOPT)
{
VARIANTARG *arg;
arg = prgpvarg[i] = &rgvarg[i];
if (wParamFlags & PARAMFLAG_FHASDEFAULT)
{
hres = VariantCopy(arg, &func_desc->lprgelemdescParam[i].u.paramdesc.pparamdescex->varDefaultValue);
if (FAILED(hres))
break;
}
else
FIXME("set %d to pointer for get (type is %d)\n",i,tdesc->vt);
/* Supply pointers for the rest, so propertyget works*/
args[argspos] = (DWORD)&args2[args2pos];
/* If pointer to variant, pass reference it. */
if ((tdesc->vt == VT_PTR) &&
(tdesc->u.lptdesc->vt == VT_VARIANT) &&
pVarResult
)
args[argspos]= (DWORD)pVarResult;
argspos += 1;
args2pos += arglen;
{
V_VT(arg) = VT_VARIANT | VT_BYREF;
V_VARIANTREF(arg) = &rgvarg[missing_param_offset];
missing_param_offset++;
V_VT(V_VARIANTREF(arg)) = VT_ERROR;
V_ERROR(V_VARIANTREF(arg)) = DISP_E_PARAMNOTFOUND;
}
}
else
{
hres = DISP_E_BADPARAMCOUNT;
break;
}
}
if (func_desc->cParamsOpt < 0)
FIXME("Does not support optional parameters (%d)\n", func_desc->cParamsOpt);
{
FIXME("Does not support safearray optional parameters\n");
hres = DISP_E_BADPARAMCOUNT;
goto func_fail; /* FIXME: we don't free changed types here */
}
V_VT(&varresult) = 0;
hres = typedescvt_to_variantvt((ITypeInfo *)iface, &func_desc->elemdescFunc.tdesc, &V_VT(&varresult));
if (FAILED(hres)) goto func_fail; /* FIXME: we don't free changed types here */
V_ERROR(&varresult) = _invoke((*(FARPROC**)pIUnk)[func_desc->oVft/4],
func_desc->callconv,
numargs,
args
);
hres = DispCallFunc(pIUnk, func_desc->oVft, func_desc->callconv,
V_VT(&varresult), func_desc->cParams, rgvt,
prgpvarg, &varresult);
for (i = 0; i < func_desc->cParams; i++)
{
USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
if (wParamFlags & PARAMFLAG_FRETVAL)
{
ELEMDESC *elemdesc = &func_desc->lprgelemdescParam[i];
TYPEDESC *tdesc = &elemdesc->tdesc;
VARIANTARG varresult;
V_VT(&varresult) = 0;
hres = typedescvt_to_variantvt((ITypeInfo *)iface, tdesc, &V_VT(&varresult));
if (hres)
break;
/* FIXME: this is really messy - we should keep the
* args in VARIANTARGs rather than a DWORD array */
memcpy(&V_UI4(&varresult), &args[i+1], sizeof(DWORD));
if (TRACE_ON(ole))
{
TRACE("varresult: ");
dump_Variant(&varresult);
dump_Variant(prgpvarg[i]);
}
if (pVarResult)
/* deref return value */
hres = VariantCopyInd(pVarResult, &varresult);
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(&varresult) == (VT_UNKNOWN | VT_BYREF)) ||
(V_VT(&varresult) == (VT_DISPATCH | VT_BYREF)))
if ((V_VT(prgpvarg[i]) == (VT_UNKNOWN | VT_BYREF)) ||
(V_VT(prgpvarg[i]) == (VT_DISPATCH | VT_BYREF)))
{
if(*V_UNKNOWNREF(&varresult))
IUnknown_Release(*V_UNKNOWNREF(&varresult));
if(*V_UNKNOWNREF(prgpvarg[i]))
IUnknown_Release(*V_UNKNOWNREF(prgpvarg[i]));
}
break;
}
else if (i < pDispParams->cArgs)
{
if (wParamFlags & PARAMFLAG_FOUT)
{
hres = VariantChangeType(&pDispParams->rgvarg[pDispParams->cArgs - 1 - i],
&rgvarg[i], 0,
V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1 - i]));
if (FAILED(hres))
{
ERR("failed to convert param %d to vt %d\n", i,
V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1 - i]));
break;
}
}
VariantClear(&rgvarg[i]);
}
else if (wParamFlags & PARAMFLAG_FOPT)
{
if (wParamFlags & PARAMFLAG_FHASDEFAULT)
VariantClear(&rgvarg[i]);
}
}
if ((V_VT(&varresult) == VT_ERROR) && FAILED(V_ERROR(&varresult)))
@ -5515,9 +5521,9 @@ static HRESULT WINAPI ITypeInfo_fnInvoke(
}
func_fail:
HeapFree(GetProcessHeap(), 0, prgpvarg);
HeapFree(GetProcessHeap(), 0, rgvarg);
HeapFree(GetProcessHeap(),0,args2);
HeapFree(GetProcessHeap(),0,args);
HeapFree(GetProcessHeap(), 0, rgvt);
break;
}
case FUNC_DISPATCH: {