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:
parent
95312fcb63
commit
8cf5373f60
|
@ -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: {
|
||||||
|
|
Loading…
Reference in New Issue