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