oleaut32: Split DispCallFunc() into platform-specific functions.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
34e15e5a1d
commit
25d0c66238
|
@ -6345,6 +6345,114 @@ __ASM_GLOBAL_FUNC( call_method,
|
|||
__ASM_GLOBAL_FUNC( call_double_method,
|
||||
"jmp " __ASM_NAME("call_method") )
|
||||
|
||||
HRESULT WINAPI DispCallFunc( void* pvInstance, ULONG_PTR oVft, CALLCONV cc, VARTYPE vtReturn,
|
||||
UINT cActuals, VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult )
|
||||
{
|
||||
int argspos = 0, stack_offset;
|
||||
void *func;
|
||||
UINT i;
|
||||
DWORD *args;
|
||||
|
||||
TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n",
|
||||
pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg,
|
||||
pvargResult, V_VT(pvargResult));
|
||||
|
||||
if (cc != CC_STDCALL && cc != CC_CDECL)
|
||||
{
|
||||
FIXME("unsupported calling convention %d\n",cc);
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
/* maximum size for an argument is sizeof(VARIANT) */
|
||||
args = heap_alloc(sizeof(VARIANT) * cActuals + sizeof(DWORD) * 2 );
|
||||
|
||||
if (pvInstance)
|
||||
{
|
||||
const FARPROC *vtable = *(FARPROC **)pvInstance;
|
||||
func = vtable[oVft/sizeof(void *)];
|
||||
args[argspos++] = (DWORD)pvInstance; /* the This pointer is always the first parameter */
|
||||
}
|
||||
else func = (void *)oVft;
|
||||
|
||||
switch (vtReturn)
|
||||
{
|
||||
case VT_DECIMAL:
|
||||
case VT_VARIANT:
|
||||
args[argspos++] = (DWORD)pvargResult; /* arg 0 is a pointer to the result */
|
||||
break;
|
||||
case VT_HRESULT:
|
||||
WARN("invalid return type %u\n", vtReturn);
|
||||
heap_free( args );
|
||||
return E_INVALIDARG;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < cActuals; i++)
|
||||
{
|
||||
VARIANT *arg = prgpvarg[i];
|
||||
|
||||
switch (prgvt[i])
|
||||
{
|
||||
case VT_EMPTY:
|
||||
break;
|
||||
case VT_I8:
|
||||
case VT_UI8:
|
||||
case VT_R8:
|
||||
case VT_DATE:
|
||||
case VT_CY:
|
||||
memcpy( &args[argspos], &V_I8(arg), sizeof(V_I8(arg)) );
|
||||
argspos += sizeof(V_I8(arg)) / sizeof(DWORD);
|
||||
break;
|
||||
case VT_DECIMAL:
|
||||
case VT_VARIANT:
|
||||
memcpy( &args[argspos], arg, sizeof(*arg) );
|
||||
argspos += sizeof(*arg) / sizeof(DWORD);
|
||||
break;
|
||||
case VT_BOOL: /* VT_BOOL is 16-bit but BOOL is 32-bit, needs to be extended */
|
||||
args[argspos++] = V_BOOL(arg);
|
||||
break;
|
||||
default:
|
||||
args[argspos++] = V_UI4(arg);
|
||||
break;
|
||||
}
|
||||
TRACE("arg %u: type %s %s\n", i, debugstr_vt(prgvt[i]), debugstr_variant(arg));
|
||||
}
|
||||
|
||||
switch (vtReturn)
|
||||
{
|
||||
case VT_EMPTY:
|
||||
case VT_DECIMAL:
|
||||
case VT_VARIANT:
|
||||
call_method( func, argspos, args, &stack_offset );
|
||||
break;
|
||||
case VT_R4:
|
||||
V_R4(pvargResult) = call_double_method( func, argspos, args, &stack_offset );
|
||||
break;
|
||||
case VT_R8:
|
||||
case VT_DATE:
|
||||
V_R8(pvargResult) = call_double_method( func, argspos, args, &stack_offset );
|
||||
break;
|
||||
case VT_I8:
|
||||
case VT_UI8:
|
||||
case VT_CY:
|
||||
V_UI8(pvargResult) = call_method( func, argspos, args, &stack_offset );
|
||||
break;
|
||||
default:
|
||||
V_UI4(pvargResult) = call_method( func, argspos, args, &stack_offset );
|
||||
break;
|
||||
}
|
||||
heap_free( args );
|
||||
if (stack_offset && cc == CC_STDCALL)
|
||||
{
|
||||
WARN( "stack pointer off by %d\n", stack_offset );
|
||||
return DISP_E_BADCALLEE;
|
||||
}
|
||||
if (vtReturn != VT_VARIANT) V_VT(pvargResult) = vtReturn;
|
||||
TRACE("retval: %s\n", debugstr_variant(pvargResult));
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#elif defined(__x86_64__)
|
||||
|
||||
extern DWORD_PTR CDECL call_method( void *func, int nb_args, const DWORD_PTR *args );
|
||||
|
@ -6396,6 +6504,92 @@ __ASM_GLOBAL_FUNC( call_method,
|
|||
__ASM_GLOBAL_FUNC( call_double_method,
|
||||
"jmp " __ASM_NAME("call_method") )
|
||||
|
||||
HRESULT WINAPI DispCallFunc( void* pvInstance, ULONG_PTR oVft, CALLCONV cc, VARTYPE vtReturn,
|
||||
UINT cActuals, VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult )
|
||||
{
|
||||
int argspos = 0;
|
||||
UINT i;
|
||||
DWORD_PTR *args;
|
||||
void *func;
|
||||
|
||||
TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n",
|
||||
pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg,
|
||||
pvargResult, V_VT(pvargResult));
|
||||
|
||||
if (cc != CC_STDCALL && cc != CC_CDECL)
|
||||
{
|
||||
FIXME("unsupported calling convention %d\n",cc);
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
/* maximum size for an argument is sizeof(DWORD_PTR) */
|
||||
args = heap_alloc( sizeof(DWORD_PTR) * (cActuals + 2) );
|
||||
|
||||
if (pvInstance)
|
||||
{
|
||||
const FARPROC *vtable = *(FARPROC **)pvInstance;
|
||||
func = vtable[oVft/sizeof(void *)];
|
||||
args[argspos++] = (DWORD_PTR)pvInstance; /* the This pointer is always the first parameter */
|
||||
}
|
||||
else func = (void *)oVft;
|
||||
|
||||
switch (vtReturn)
|
||||
{
|
||||
case VT_DECIMAL:
|
||||
case VT_VARIANT:
|
||||
args[argspos++] = (DWORD_PTR)pvargResult; /* arg 0 is a pointer to the result */
|
||||
break;
|
||||
case VT_HRESULT:
|
||||
WARN("invalid return type %u\n", vtReturn);
|
||||
heap_free( args );
|
||||
return E_INVALIDARG;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < cActuals; i++)
|
||||
{
|
||||
VARIANT *arg = prgpvarg[i];
|
||||
|
||||
switch (prgvt[i])
|
||||
{
|
||||
case VT_DECIMAL:
|
||||
case VT_VARIANT:
|
||||
args[argspos++] = (ULONG_PTR)arg;
|
||||
break;
|
||||
case VT_BOOL: /* VT_BOOL is 16-bit but BOOL is 32-bit, needs to be extended */
|
||||
args[argspos++] = V_BOOL(arg);
|
||||
break;
|
||||
default:
|
||||
args[argspos++] = V_UI8(arg);
|
||||
break;
|
||||
}
|
||||
TRACE("arg %u: type %s %s\n", i, debugstr_vt(prgvt[i]), debugstr_variant(arg));
|
||||
}
|
||||
|
||||
switch (vtReturn)
|
||||
{
|
||||
case VT_R4:
|
||||
V_R4(pvargResult) = call_double_method( func, argspos, args );
|
||||
break;
|
||||
case VT_R8:
|
||||
case VT_DATE:
|
||||
V_R8(pvargResult) = call_double_method( func, argspos, args );
|
||||
break;
|
||||
case VT_DECIMAL:
|
||||
case VT_VARIANT:
|
||||
call_method( func, argspos, args );
|
||||
break;
|
||||
default:
|
||||
V_UI8(pvargResult) = call_method( func, argspos, args );
|
||||
break;
|
||||
}
|
||||
heap_free( args );
|
||||
if (vtReturn != VT_VARIANT) V_VT(pvargResult) = vtReturn;
|
||||
TRACE("retval: %s\n", debugstr_variant(pvargResult));
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#elif defined(__arm__)
|
||||
|
||||
extern LONGLONG CDECL call_method( void *func, int nb_stk_args, const DWORD *stk_args, const DWORD *reg_args );
|
||||
|
@ -6436,7 +6630,196 @@ __ASM_GLOBAL_FUNC( call_float_method,
|
|||
__ASM_GLOBAL_FUNC( call_double_method,
|
||||
"b " __ASM_NAME("call_method") )
|
||||
|
||||
#endif /* __arm__ */
|
||||
HRESULT WINAPI DispCallFunc( void* pvInstance, ULONG_PTR oVft, CALLCONV cc, VARTYPE vtReturn,
|
||||
UINT cActuals, VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult )
|
||||
{
|
||||
int argspos;
|
||||
void *func;
|
||||
UINT i;
|
||||
DWORD *args;
|
||||
struct {
|
||||
#ifndef __SOFTFP__
|
||||
union {
|
||||
float s[16];
|
||||
double d[8];
|
||||
} sd;
|
||||
#endif
|
||||
DWORD r[4];
|
||||
} regs;
|
||||
int rcount; /* 32-bit register index count */
|
||||
#ifndef __SOFTFP__
|
||||
int scount = 0; /* single-precision float register index count */
|
||||
int dcount = 0; /* double-precision float register index count */
|
||||
#endif
|
||||
|
||||
TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n",
|
||||
pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg, pvargResult, V_VT(pvargResult));
|
||||
|
||||
if (cc != CC_STDCALL && cc != CC_CDECL)
|
||||
{
|
||||
FIXME("unsupported calling convention %d\n",cc);
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
argspos = 0;
|
||||
rcount = 0;
|
||||
|
||||
if (pvInstance)
|
||||
{
|
||||
const FARPROC *vtable = *(FARPROC **)pvInstance;
|
||||
func = vtable[oVft/sizeof(void *)];
|
||||
regs.r[rcount++] = (DWORD)pvInstance; /* the This pointer is always the first parameter */
|
||||
}
|
||||
else func = (void *)oVft;
|
||||
|
||||
/* Determine if we need to pass a pointer for the return value as arg 0. If so, do that */
|
||||
/* first as it will need to be in the 'r' registers: */
|
||||
switch (vtReturn)
|
||||
{
|
||||
case VT_DECIMAL:
|
||||
case VT_VARIANT:
|
||||
regs.r[rcount++] = (DWORD)pvargResult; /* arg 0 is a pointer to the result */
|
||||
break;
|
||||
case VT_HRESULT:
|
||||
WARN("invalid return type %u\n", vtReturn);
|
||||
return E_INVALIDARG;
|
||||
default: /* And all others are in 'r', 's', or 'd' registers or have no return value */
|
||||
break;
|
||||
}
|
||||
|
||||
/* maximum size for an argument is sizeof(VARIANT). Also allow for return pointer and stack alignment. */
|
||||
args = heap_alloc( sizeof(VARIANT) * cActuals + sizeof(DWORD) * 4 );
|
||||
|
||||
for (i = 0; i < cActuals; i++)
|
||||
{
|
||||
VARIANT *arg = prgpvarg[i];
|
||||
DWORD *pdwarg = (DWORD *)(arg); /* a reinterpret_cast of the variant, used for copying structures when they are split between registers and stack */
|
||||
int ntemp; /* Used for counting words split between registers and stack */
|
||||
|
||||
switch (prgvt[i])
|
||||
{
|
||||
case VT_EMPTY:
|
||||
break;
|
||||
case VT_R8: /* these must be 8-byte aligned, and put in 'd' regs or stack, as they are double-floats */
|
||||
case VT_DATE:
|
||||
#ifndef __SOFTFP__
|
||||
dcount = max( (scount + 1) / 2, dcount );
|
||||
if (dcount < 8)
|
||||
{
|
||||
regs.sd.d[dcount++] = V_R8(arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
argspos += (argspos % 2); /* align argspos to 8-bytes */
|
||||
memcpy( &args[argspos], &V_R8(arg), sizeof(V_R8(arg)) );
|
||||
argspos += sizeof(V_R8(arg)) / sizeof(DWORD);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case VT_I8: /* these must be 8-byte aligned, and put in 'r' regs or stack, as they are long-longs */
|
||||
case VT_UI8:
|
||||
case VT_CY:
|
||||
if (rcount < 3)
|
||||
{
|
||||
rcount += (rcount % 2); /* align rcount to 8-byte register pair */
|
||||
memcpy( ®s.r[rcount], &V_UI8(arg), sizeof(V_UI8(arg)) );
|
||||
rcount += sizeof(V_UI8(arg)) / sizeof(DWORD);
|
||||
}
|
||||
else
|
||||
{
|
||||
rcount = 4; /* Make sure we flag that all 'r' regs are full */
|
||||
argspos += (argspos % 2); /* align argspos to 8-bytes */
|
||||
memcpy( &args[argspos], &V_UI8(arg), sizeof(V_UI8(arg)) );
|
||||
argspos += sizeof(V_UI8(arg)) / sizeof(DWORD);
|
||||
}
|
||||
break;
|
||||
case VT_DECIMAL: /* these structures are 8-byte aligned, and put in 'r' regs or stack, can be split between the two */
|
||||
case VT_VARIANT:
|
||||
/* 8-byte align 'r' and/or stack: */
|
||||
if (rcount < 3)
|
||||
rcount += (rcount % 2);
|
||||
else
|
||||
{
|
||||
rcount = 4;
|
||||
argspos += (argspos % 2);
|
||||
}
|
||||
ntemp = sizeof(*arg) / sizeof(DWORD);
|
||||
while (ntemp > 0)
|
||||
{
|
||||
if (rcount < 4)
|
||||
regs.r[rcount++] = *pdwarg++;
|
||||
else
|
||||
args[argspos++] = *pdwarg++;
|
||||
--ntemp;
|
||||
}
|
||||
break;
|
||||
case VT_BOOL: /* VT_BOOL is 16-bit but BOOL is 32-bit, needs to be extended */
|
||||
if (rcount < 4)
|
||||
regs.r[rcount++] = V_BOOL(arg);
|
||||
else
|
||||
args[argspos++] = V_BOOL(arg);
|
||||
break;
|
||||
case VT_R4: /* these must be 4-byte aligned, and put in 's' regs or stack, as they are single-floats */
|
||||
#ifndef __SOFTFP__
|
||||
if (!(scount % 2)) scount = max( scount, dcount * 2 );
|
||||
if (scount < 16)
|
||||
regs.sd.s[scount++] = V_R4(arg);
|
||||
else
|
||||
args[argspos++] = V_UI4(arg);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
if (rcount < 4)
|
||||
regs.r[rcount++] = V_UI4(arg);
|
||||
else
|
||||
args[argspos++] = V_UI4(arg);
|
||||
break;
|
||||
}
|
||||
TRACE("arg %u: type %s %s\n", i, debugstr_vt(prgvt[i]), debugstr_variant(arg));
|
||||
}
|
||||
|
||||
argspos += (argspos % 2); /* Make sure stack function alignment is 8-byte */
|
||||
|
||||
switch (vtReturn)
|
||||
{
|
||||
case VT_EMPTY: /* EMPTY = no return value */
|
||||
case VT_DECIMAL: /* DECIMAL and VARIANT already have a pointer argument passed (see above) */
|
||||
case VT_VARIANT:
|
||||
call_method( func, argspos, args, (DWORD*)®s );
|
||||
break;
|
||||
case VT_R4:
|
||||
V_R4(pvargResult) = call_float_method( func, argspos, args, (DWORD*)®s );
|
||||
break;
|
||||
case VT_R8:
|
||||
case VT_DATE:
|
||||
V_R8(pvargResult) = call_double_method( func, argspos, args, (DWORD*)®s );
|
||||
break;
|
||||
case VT_I8:
|
||||
case VT_UI8:
|
||||
case VT_CY:
|
||||
V_UI8(pvargResult) = call_method( func, argspos, args, (DWORD*)®s );
|
||||
break;
|
||||
default:
|
||||
V_UI4(pvargResult) = call_method( func, argspos, args, (DWORD*)®s );
|
||||
break;
|
||||
}
|
||||
heap_free( args );
|
||||
if (vtReturn != VT_VARIANT) V_VT(pvargResult) = vtReturn;
|
||||
TRACE("retval: %s\n", debugstr_variant(pvargResult));
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#else /* __arm__ */
|
||||
|
||||
HRESULT WINAPI DispCallFunc( void* pvInstance, ULONG_PTR oVft, CALLCONV cc, VARTYPE vtReturn,
|
||||
UINT cActuals, VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult )
|
||||
{
|
||||
FIXME( "(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d)): not implemented for this CPU\n",
|
||||
pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg, pvargResult, V_VT(pvargResult));
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static HRESULT userdefined_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt)
|
||||
{
|
||||
|
@ -6625,420 +7008,6 @@ static HRESULT get_iface_guid(ITypeInfo *tinfo, HREFTYPE href, GUID *guid)
|
|||
return hres;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* DispCallFunc (OLEAUT32.@)
|
||||
*
|
||||
* Invokes a function of the specified calling convention, passing the
|
||||
* specified arguments and returns the result.
|
||||
*
|
||||
* PARAMS
|
||||
* pvInstance [I] Optional pointer to the instance whose function to invoke.
|
||||
* oVft [I] The offset in the vtable. See notes.
|
||||
* cc [I] Calling convention of the function to call.
|
||||
* vtReturn [I] The return type of the function.
|
||||
* cActuals [I] Number of parameters.
|
||||
* prgvt [I] The types of the parameters to pass. This is used for sizing only.
|
||||
* prgpvarg [I] The arguments to pass.
|
||||
* pvargResult [O] The return value of the function. Can be NULL.
|
||||
*
|
||||
* RETURNS
|
||||
* Success: S_OK.
|
||||
* Failure: HRESULT code.
|
||||
*
|
||||
* NOTES
|
||||
* The HRESULT return value of this function is not affected by the return
|
||||
* value of the user supplied function, which is returned in pvargResult.
|
||||
*
|
||||
* If pvInstance is NULL then a non-object function is to be called and oVft
|
||||
* is the address of the function to call.
|
||||
*
|
||||
* The cc parameter can be one of the following values:
|
||||
*|CC_FASTCALL
|
||||
*|CC_CDECL
|
||||
*|CC_PASCAL
|
||||
*|CC_STDCALL
|
||||
*|CC_FPFASTCALL
|
||||
*|CC_SYSCALL
|
||||
*|CC_MPWCDECL
|
||||
*|CC_MPWPASCAL
|
||||
*
|
||||
*/
|
||||
HRESULT WINAPI
|
||||
DispCallFunc(
|
||||
void* pvInstance, ULONG_PTR oVft, CALLCONV cc, VARTYPE vtReturn, UINT cActuals,
|
||||
VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult)
|
||||
{
|
||||
#ifdef __i386__
|
||||
int argspos = 0, stack_offset;
|
||||
void *func;
|
||||
UINT i;
|
||||
DWORD *args;
|
||||
|
||||
TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n",
|
||||
pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg,
|
||||
pvargResult, V_VT(pvargResult));
|
||||
|
||||
if (cc != CC_STDCALL && cc != CC_CDECL)
|
||||
{
|
||||
FIXME("unsupported calling convention %d\n",cc);
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
/* maximum size for an argument is sizeof(VARIANT) */
|
||||
args = heap_alloc(sizeof(VARIANT) * cActuals + sizeof(DWORD) * 2 );
|
||||
|
||||
if (pvInstance)
|
||||
{
|
||||
const FARPROC *vtable = *(FARPROC **)pvInstance;
|
||||
func = vtable[oVft/sizeof(void *)];
|
||||
args[argspos++] = (DWORD)pvInstance; /* the This pointer is always the first parameter */
|
||||
}
|
||||
else func = (void *)oVft;
|
||||
|
||||
switch (vtReturn)
|
||||
{
|
||||
case VT_DECIMAL:
|
||||
case VT_VARIANT:
|
||||
args[argspos++] = (DWORD)pvargResult; /* arg 0 is a pointer to the result */
|
||||
break;
|
||||
case VT_HRESULT:
|
||||
WARN("invalid return type %u\n", vtReturn);
|
||||
heap_free( args );
|
||||
return E_INVALIDARG;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < cActuals; i++)
|
||||
{
|
||||
VARIANT *arg = prgpvarg[i];
|
||||
|
||||
switch (prgvt[i])
|
||||
{
|
||||
case VT_EMPTY:
|
||||
break;
|
||||
case VT_I8:
|
||||
case VT_UI8:
|
||||
case VT_R8:
|
||||
case VT_DATE:
|
||||
case VT_CY:
|
||||
memcpy( &args[argspos], &V_I8(arg), sizeof(V_I8(arg)) );
|
||||
argspos += sizeof(V_I8(arg)) / sizeof(DWORD);
|
||||
break;
|
||||
case VT_DECIMAL:
|
||||
case VT_VARIANT:
|
||||
memcpy( &args[argspos], arg, sizeof(*arg) );
|
||||
argspos += sizeof(*arg) / sizeof(DWORD);
|
||||
break;
|
||||
case VT_BOOL: /* VT_BOOL is 16-bit but BOOL is 32-bit, needs to be extended */
|
||||
args[argspos++] = V_BOOL(arg);
|
||||
break;
|
||||
default:
|
||||
args[argspos++] = V_UI4(arg);
|
||||
break;
|
||||
}
|
||||
TRACE("arg %u: type %s %s\n", i, debugstr_vt(prgvt[i]), debugstr_variant(arg));
|
||||
}
|
||||
|
||||
switch (vtReturn)
|
||||
{
|
||||
case VT_EMPTY:
|
||||
case VT_DECIMAL:
|
||||
case VT_VARIANT:
|
||||
call_method( func, argspos, args, &stack_offset );
|
||||
break;
|
||||
case VT_R4:
|
||||
V_R4(pvargResult) = call_double_method( func, argspos, args, &stack_offset );
|
||||
break;
|
||||
case VT_R8:
|
||||
case VT_DATE:
|
||||
V_R8(pvargResult) = call_double_method( func, argspos, args, &stack_offset );
|
||||
break;
|
||||
case VT_I8:
|
||||
case VT_UI8:
|
||||
case VT_CY:
|
||||
V_UI8(pvargResult) = call_method( func, argspos, args, &stack_offset );
|
||||
break;
|
||||
default:
|
||||
V_UI4(pvargResult) = call_method( func, argspos, args, &stack_offset );
|
||||
break;
|
||||
}
|
||||
heap_free( args );
|
||||
if (stack_offset && cc == CC_STDCALL)
|
||||
{
|
||||
WARN( "stack pointer off by %d\n", stack_offset );
|
||||
return DISP_E_BADCALLEE;
|
||||
}
|
||||
if (vtReturn != VT_VARIANT) V_VT(pvargResult) = vtReturn;
|
||||
TRACE("retval: %s\n", debugstr_variant(pvargResult));
|
||||
return S_OK;
|
||||
|
||||
#elif defined(__x86_64__)
|
||||
int argspos = 0;
|
||||
UINT i;
|
||||
DWORD_PTR *args;
|
||||
void *func;
|
||||
|
||||
TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n",
|
||||
pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg,
|
||||
pvargResult, V_VT(pvargResult));
|
||||
|
||||
if (cc != CC_STDCALL && cc != CC_CDECL)
|
||||
{
|
||||
FIXME("unsupported calling convention %d\n",cc);
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
/* maximum size for an argument is sizeof(DWORD_PTR) */
|
||||
args = heap_alloc( sizeof(DWORD_PTR) * (cActuals + 2) );
|
||||
|
||||
if (pvInstance)
|
||||
{
|
||||
const FARPROC *vtable = *(FARPROC **)pvInstance;
|
||||
func = vtable[oVft/sizeof(void *)];
|
||||
args[argspos++] = (DWORD_PTR)pvInstance; /* the This pointer is always the first parameter */
|
||||
}
|
||||
else func = (void *)oVft;
|
||||
|
||||
switch (vtReturn)
|
||||
{
|
||||
case VT_DECIMAL:
|
||||
case VT_VARIANT:
|
||||
args[argspos++] = (DWORD_PTR)pvargResult; /* arg 0 is a pointer to the result */
|
||||
break;
|
||||
case VT_HRESULT:
|
||||
WARN("invalid return type %u\n", vtReturn);
|
||||
heap_free( args );
|
||||
return E_INVALIDARG;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < cActuals; i++)
|
||||
{
|
||||
VARIANT *arg = prgpvarg[i];
|
||||
|
||||
switch (prgvt[i])
|
||||
{
|
||||
case VT_DECIMAL:
|
||||
case VT_VARIANT:
|
||||
args[argspos++] = (ULONG_PTR)arg;
|
||||
break;
|
||||
case VT_BOOL: /* VT_BOOL is 16-bit but BOOL is 32-bit, needs to be extended */
|
||||
args[argspos++] = V_BOOL(arg);
|
||||
break;
|
||||
default:
|
||||
args[argspos++] = V_UI8(arg);
|
||||
break;
|
||||
}
|
||||
TRACE("arg %u: type %s %s\n", i, debugstr_vt(prgvt[i]), debugstr_variant(arg));
|
||||
}
|
||||
|
||||
switch (vtReturn)
|
||||
{
|
||||
case VT_R4:
|
||||
V_R4(pvargResult) = call_double_method( func, argspos, args );
|
||||
break;
|
||||
case VT_R8:
|
||||
case VT_DATE:
|
||||
V_R8(pvargResult) = call_double_method( func, argspos, args );
|
||||
break;
|
||||
case VT_DECIMAL:
|
||||
case VT_VARIANT:
|
||||
call_method( func, argspos, args );
|
||||
break;
|
||||
default:
|
||||
V_UI8(pvargResult) = call_method( func, argspos, args );
|
||||
break;
|
||||
}
|
||||
heap_free( args );
|
||||
if (vtReturn != VT_VARIANT) V_VT(pvargResult) = vtReturn;
|
||||
TRACE("retval: %s\n", debugstr_variant(pvargResult));
|
||||
return S_OK;
|
||||
|
||||
#elif defined(__arm__)
|
||||
int argspos;
|
||||
void *func;
|
||||
UINT i;
|
||||
DWORD *args;
|
||||
struct {
|
||||
#ifndef __SOFTFP__
|
||||
union {
|
||||
float s[16];
|
||||
double d[8];
|
||||
} sd;
|
||||
#endif
|
||||
DWORD r[4];
|
||||
} regs;
|
||||
int rcount; /* 32-bit register index count */
|
||||
#ifndef __SOFTFP__
|
||||
int scount = 0; /* single-precision float register index count */
|
||||
int dcount = 0; /* double-precision float register index count */
|
||||
#endif
|
||||
|
||||
TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n",
|
||||
pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg, pvargResult, V_VT(pvargResult));
|
||||
|
||||
if (cc != CC_STDCALL && cc != CC_CDECL)
|
||||
{
|
||||
FIXME("unsupported calling convention %d\n",cc);
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
argspos = 0;
|
||||
rcount = 0;
|
||||
|
||||
if (pvInstance)
|
||||
{
|
||||
const FARPROC *vtable = *(FARPROC **)pvInstance;
|
||||
func = vtable[oVft/sizeof(void *)];
|
||||
regs.r[rcount++] = (DWORD)pvInstance; /* the This pointer is always the first parameter */
|
||||
}
|
||||
else func = (void *)oVft;
|
||||
|
||||
/* Determine if we need to pass a pointer for the return value as arg 0. If so, do that */
|
||||
/* first as it will need to be in the 'r' registers: */
|
||||
switch (vtReturn)
|
||||
{
|
||||
case VT_DECIMAL:
|
||||
case VT_VARIANT:
|
||||
regs.r[rcount++] = (DWORD)pvargResult; /* arg 0 is a pointer to the result */
|
||||
break;
|
||||
case VT_HRESULT:
|
||||
WARN("invalid return type %u\n", vtReturn);
|
||||
return E_INVALIDARG;
|
||||
default: /* And all others are in 'r', 's', or 'd' registers or have no return value */
|
||||
break;
|
||||
}
|
||||
|
||||
/* maximum size for an argument is sizeof(VARIANT). Also allow for return pointer and stack alignment. */
|
||||
args = heap_alloc( sizeof(VARIANT) * cActuals + sizeof(DWORD) * 4 );
|
||||
|
||||
for (i = 0; i < cActuals; i++)
|
||||
{
|
||||
VARIANT *arg = prgpvarg[i];
|
||||
DWORD *pdwarg = (DWORD *)(arg); /* a reinterpret_cast of the variant, used for copying structures when they are split between registers and stack */
|
||||
int ntemp; /* Used for counting words split between registers and stack */
|
||||
|
||||
switch (prgvt[i])
|
||||
{
|
||||
case VT_EMPTY:
|
||||
break;
|
||||
case VT_R8: /* these must be 8-byte aligned, and put in 'd' regs or stack, as they are double-floats */
|
||||
case VT_DATE:
|
||||
#ifndef __SOFTFP__
|
||||
dcount = max( (scount + 1) / 2, dcount );
|
||||
if (dcount < 8)
|
||||
{
|
||||
regs.sd.d[dcount++] = V_R8(arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
argspos += (argspos % 2); /* align argspos to 8-bytes */
|
||||
memcpy( &args[argspos], &V_R8(arg), sizeof(V_R8(arg)) );
|
||||
argspos += sizeof(V_R8(arg)) / sizeof(DWORD);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case VT_I8: /* these must be 8-byte aligned, and put in 'r' regs or stack, as they are long-longs */
|
||||
case VT_UI8:
|
||||
case VT_CY:
|
||||
if (rcount < 3)
|
||||
{
|
||||
rcount += (rcount % 2); /* align rcount to 8-byte register pair */
|
||||
memcpy( ®s.r[rcount], &V_UI8(arg), sizeof(V_UI8(arg)) );
|
||||
rcount += sizeof(V_UI8(arg)) / sizeof(DWORD);
|
||||
}
|
||||
else
|
||||
{
|
||||
rcount = 4; /* Make sure we flag that all 'r' regs are full */
|
||||
argspos += (argspos % 2); /* align argspos to 8-bytes */
|
||||
memcpy( &args[argspos], &V_UI8(arg), sizeof(V_UI8(arg)) );
|
||||
argspos += sizeof(V_UI8(arg)) / sizeof(DWORD);
|
||||
}
|
||||
break;
|
||||
case VT_DECIMAL: /* these structures are 8-byte aligned, and put in 'r' regs or stack, can be split between the two */
|
||||
case VT_VARIANT:
|
||||
/* 8-byte align 'r' and/or stack: */
|
||||
if (rcount < 3)
|
||||
rcount += (rcount % 2);
|
||||
else
|
||||
{
|
||||
rcount = 4;
|
||||
argspos += (argspos % 2);
|
||||
}
|
||||
ntemp = sizeof(*arg) / sizeof(DWORD);
|
||||
while (ntemp > 0)
|
||||
{
|
||||
if (rcount < 4)
|
||||
regs.r[rcount++] = *pdwarg++;
|
||||
else
|
||||
args[argspos++] = *pdwarg++;
|
||||
--ntemp;
|
||||
}
|
||||
break;
|
||||
case VT_BOOL: /* VT_BOOL is 16-bit but BOOL is 32-bit, needs to be extended */
|
||||
if (rcount < 4)
|
||||
regs.r[rcount++] = V_BOOL(arg);
|
||||
else
|
||||
args[argspos++] = V_BOOL(arg);
|
||||
break;
|
||||
case VT_R4: /* these must be 4-byte aligned, and put in 's' regs or stack, as they are single-floats */
|
||||
#ifndef __SOFTFP__
|
||||
if (!(scount % 2)) scount = max( scount, dcount * 2 );
|
||||
if (scount < 16)
|
||||
regs.sd.s[scount++] = V_R4(arg);
|
||||
else
|
||||
args[argspos++] = V_UI4(arg);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
if (rcount < 4)
|
||||
regs.r[rcount++] = V_UI4(arg);
|
||||
else
|
||||
args[argspos++] = V_UI4(arg);
|
||||
break;
|
||||
}
|
||||
TRACE("arg %u: type %s %s\n", i, debugstr_vt(prgvt[i]), debugstr_variant(arg));
|
||||
}
|
||||
|
||||
argspos += (argspos % 2); /* Make sure stack function alignment is 8-byte */
|
||||
|
||||
switch (vtReturn)
|
||||
{
|
||||
case VT_EMPTY: /* EMPTY = no return value */
|
||||
case VT_DECIMAL: /* DECIMAL and VARIANT already have a pointer argument passed (see above) */
|
||||
case VT_VARIANT:
|
||||
call_method( func, argspos, args, (DWORD*)®s );
|
||||
break;
|
||||
case VT_R4:
|
||||
V_R4(pvargResult) = call_float_method( func, argspos, args, (DWORD*)®s );
|
||||
break;
|
||||
case VT_R8:
|
||||
case VT_DATE:
|
||||
V_R8(pvargResult) = call_double_method( func, argspos, args, (DWORD*)®s );
|
||||
break;
|
||||
case VT_I8:
|
||||
case VT_UI8:
|
||||
case VT_CY:
|
||||
V_UI8(pvargResult) = call_method( func, argspos, args, (DWORD*)®s );
|
||||
break;
|
||||
default:
|
||||
V_UI4(pvargResult) = call_method( func, argspos, args, (DWORD*)®s );
|
||||
break;
|
||||
}
|
||||
heap_free( args );
|
||||
if (vtReturn != VT_VARIANT) V_VT(pvargResult) = vtReturn;
|
||||
TRACE("retval: %s\n", debugstr_variant(pvargResult));
|
||||
return S_OK;
|
||||
|
||||
#else
|
||||
FIXME( "(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d)): not implemented for this CPU\n",
|
||||
pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg, pvargResult, V_VT(pvargResult));
|
||||
return E_NOTIMPL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline BOOL func_restricted( const FUNCDESC *desc )
|
||||
{
|
||||
return (desc->wFuncFlags & FUNCFLAG_FRESTRICTED) && (desc->memid >= 0);
|
||||
|
|
Loading…
Reference in New Issue