oleaut32: Add tests for DispCallFunc and fix a number of corner cases.
This commit is contained in:
parent
56b8d5d384
commit
a0a4667fde
|
@ -60,6 +60,8 @@ static HRESULT WINAPI (*pUnRegisterTypeLibForUser)(REFGUID,WORD,WORD,LCID,SYSKIN
|
|||
|
||||
static const WCHAR wszStdOle2[] = {'s','t','d','o','l','e','2','.','t','l','b',0};
|
||||
|
||||
static const int is_win64 = sizeof(void *) > sizeof(int);
|
||||
|
||||
static void init_function_pointers(void)
|
||||
{
|
||||
HMODULE hmod = GetModuleHandleA("oleaut32.dll");
|
||||
|
@ -628,6 +630,191 @@ static void test_TypeInfo(void)
|
|||
ITypeLib_Release(pTypeLib);
|
||||
}
|
||||
|
||||
static int WINAPI int_func( int a0, int a1, int a2, int a3, int a4 )
|
||||
{
|
||||
ok( a0 == 1, "wrong arg0 %x\n", a0 );
|
||||
ok( a1 == -1, "wrong arg1 %x\n", a1 );
|
||||
ok( a2 == (0x55550000 | 1234), "wrong arg2 %x\n", a2 );
|
||||
ok( a3 == 0xdeadbeef, "wrong arg3 %x\n", a3 );
|
||||
ok( a4 == 0x555555fd, "wrong arg4 %x\n", a4 );
|
||||
return 4321;
|
||||
}
|
||||
|
||||
static double WINAPI double_func( double a0, float a1, double a2, int a3 )
|
||||
{
|
||||
ok( a0 == 1.2, "wrong arg0 %f\n", (double)a0 );
|
||||
ok( a1 == 3.25, "wrong arg1 %f\n", (double)a1 );
|
||||
ok( a2 == 1.2e12, "wrong arg2 %f\n", (double)a2);
|
||||
ok( a3 == -4433.0, "wrong arg3 %f\n", (double)a3 );
|
||||
return 4321;
|
||||
}
|
||||
|
||||
static LONGLONG WINAPI longlong_func( LONGLONG a0, CY a1 )
|
||||
{
|
||||
ok( a0 == (((ULONGLONG)0xdead << 32) | 0xbeef), "wrong arg0 %08x%08x\n", (DWORD)(a0 >> 32), (DWORD)a0);
|
||||
ok( a1.int64 == ((ULONGLONG)10000 * 12345678), "wrong arg1 %08x%08x\n",
|
||||
(DWORD)(a1.int64 >> 32), (DWORD)a1.int64 );
|
||||
return ((ULONGLONG)4321 << 32) | 8765;
|
||||
}
|
||||
|
||||
static VARIANT WINAPI variant_func( int a0, BOOL a1, DECIMAL a2, VARIANT a3 )
|
||||
{
|
||||
VARIANT var;
|
||||
ok( a0 == 2233, "wrong arg0 %x\n", a0 );
|
||||
ok( a1 == 1 || broken(a1 == 0x55550001), "wrong arg1 %x\n", a1 );
|
||||
V_VT(&var) = VT_LPWSTR;
|
||||
V_UI4(&var) = 0xbabe;
|
||||
ok( a2.Hi32 == 1122, "wrong arg2.Hi32 %x\n", a2.Hi32 );
|
||||
ok( a2.Lo64 == 3344, "wrong arg2.Lo64 %08x%08x\n", (DWORD)(a2.Lo64 >> 32), (DWORD)a2.Lo64 );
|
||||
ok( V_VT(&a3) == VT_EMPTY, "wrong arg3 type %x\n", V_VT(&a3) );
|
||||
ok( V_UI4(&a3) == 0xdeadbeef, "wrong arg3 value %x\n", V_UI4(&a3) );
|
||||
return var;
|
||||
}
|
||||
|
||||
static int CDECL void_func( int a0, int a1 )
|
||||
{
|
||||
if (is_win64) /* VT_EMPTY is passed as real arg on win64 */
|
||||
{
|
||||
ok( a0 == 0x55555555, "wrong arg0 %x\n", a0 );
|
||||
ok( a1 == 1111, "wrong arg1 %x\n", a1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
ok( a0 == 1111, "wrong arg0 %x\n", a0 );
|
||||
ok( a1 == 0, "wrong arg1 %x\n", a1 );
|
||||
}
|
||||
return 12;
|
||||
}
|
||||
|
||||
static int WINAPI stdcall_func( int a )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int WINAPI inst_func( void *inst, int a )
|
||||
{
|
||||
ok( (*(void ***)inst)[3] == inst_func, "wrong ptr %p\n", inst );
|
||||
ok( a == 3, "wrong arg %x\n", a );
|
||||
return a * 2;
|
||||
}
|
||||
|
||||
static const void *vtable[] = { NULL, NULL, NULL, inst_func };
|
||||
|
||||
static void test_DispCallFunc(void)
|
||||
{
|
||||
const void **inst = vtable;
|
||||
HRESULT res;
|
||||
VARIANT result, args[5];
|
||||
VARIANTARG *pargs[5];
|
||||
VARTYPE types[5];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 5; i++) pargs[i] = &args[i];
|
||||
|
||||
memset( args, 0x55, sizeof(args) );
|
||||
types[0] = VT_UI4;
|
||||
V_UI4(&args[0]) = 1;
|
||||
types[1] = VT_I4;
|
||||
V_I4(&args[1]) = -1;
|
||||
types[2] = VT_I2;
|
||||
V_I2(&args[2]) = 1234;
|
||||
types[3] = VT_UI4;
|
||||
V_UI4(&args[3]) = 0xdeadbeef;
|
||||
types[4] = VT_UI4;
|
||||
V_I1(&args[4]) = -3;
|
||||
memset( &result, 0xcc, sizeof(result) );
|
||||
res = DispCallFunc( NULL, (ULONG_PTR)int_func, CC_STDCALL, VT_UI4, 5, types, pargs, &result );
|
||||
ok( res == S_OK, "DispCallFunc failed %x\n", res );
|
||||
ok( V_VT(&result) == VT_UI4, "wrong result type %d\n", V_VT(&result) );
|
||||
ok( V_UI4(&result) == 4321, "wrong result %u\n", V_UI4(&result) );
|
||||
|
||||
/* the function checks the argument sizes for stdcall */
|
||||
if (!is_win64) /* no stdcall on 64-bit */
|
||||
{
|
||||
res = DispCallFunc( NULL, (ULONG_PTR)stdcall_func, CC_STDCALL, VT_UI4, 0, types, pargs, &result );
|
||||
ok( res == DISP_E_BADCALLEE, "DispCallFunc wrong error %x\n", res );
|
||||
res = DispCallFunc( NULL, (ULONG_PTR)stdcall_func, CC_STDCALL, VT_UI4, 1, types, pargs, &result );
|
||||
ok( res == S_OK, "DispCallFunc failed %x\n", res );
|
||||
res = DispCallFunc( NULL, (ULONG_PTR)stdcall_func, CC_STDCALL, VT_UI4, 2, types, pargs, &result );
|
||||
ok( res == DISP_E_BADCALLEE, "DispCallFunc wrong error %x\n", res );
|
||||
}
|
||||
|
||||
memset( args, 0x55, sizeof(args) );
|
||||
types[0] = VT_R8;
|
||||
V_R8(&args[0]) = 1.2;
|
||||
types[1] = VT_R4;
|
||||
V_R4(&args[1]) = 3.25;
|
||||
types[2] = VT_R8;
|
||||
V_R8(&args[2]) = 1.2e12;
|
||||
types[3] = VT_I4;
|
||||
V_I4(&args[3]) = -4433;
|
||||
memset( &result, 0xcc, sizeof(result) );
|
||||
res = DispCallFunc( NULL, (ULONG_PTR)double_func, CC_STDCALL, VT_R8, 4, types, pargs, &result );
|
||||
ok( res == S_OK, "DispCallFunc failed %x\n", res );
|
||||
ok( V_VT(&result) == VT_R8, "wrong result type %d\n", V_VT(&result) );
|
||||
ok( V_R8(&result) == 4321, "wrong result %f\n", V_R8(&result) );
|
||||
|
||||
memset( args, 0x55, sizeof(args) );
|
||||
types[0] = VT_I8;
|
||||
V_I8(&args[0]) = ((ULONGLONG)0xdead << 32) | 0xbeef;
|
||||
types[1] = VT_CY;
|
||||
V_CY(&args[1]).int64 = (ULONGLONG)10000 * 12345678;
|
||||
memset( &result, 0xcc, sizeof(result) );
|
||||
res = DispCallFunc( NULL, (ULONG_PTR)longlong_func, CC_STDCALL, VT_I8, 2, types, pargs, &result );
|
||||
ok( res == S_OK || broken(res == E_INVALIDARG), /* longlong not supported on <= win2k */
|
||||
"DispCallFunc failed %x\n", res );
|
||||
if (res == S_OK)
|
||||
{
|
||||
ok( V_VT(&result) == VT_I8, "wrong result type %d\n", V_VT(&result) );
|
||||
ok( V_I8(&result) == (((ULONGLONG)4321 << 32) | 8765), "wrong result %08x%08x\n",
|
||||
(DWORD)(V_I8(&result) >> 32), (DWORD)V_I8(&result) );
|
||||
}
|
||||
|
||||
memset( args, 0x55, sizeof(args) );
|
||||
types[0] = VT_I4;
|
||||
V_I4(&args[0]) = 2233;
|
||||
types[1] = VT_BOOL;
|
||||
V_BOOL(&args[1]) = 1;
|
||||
types[2] = VT_DECIMAL;
|
||||
V_DECIMAL(&args[2]).Hi32 = 1122;
|
||||
V_DECIMAL(&args[2]).Lo64 = 3344;
|
||||
types[3] = VT_VARIANT;
|
||||
V_VT(&args[3]) = VT_EMPTY;
|
||||
V_UI4(&args[3]) = 0xdeadbeef;
|
||||
types[4] = VT_EMPTY;
|
||||
memset( &result, 0xcc, sizeof(result) );
|
||||
res = DispCallFunc( NULL, (ULONG_PTR)variant_func, CC_STDCALL, VT_VARIANT, 5, types, pargs, &result );
|
||||
ok( res == S_OK, "DispCallFunc failed %x\n", res );
|
||||
ok( V_VT(&result) == VT_LPWSTR, "wrong result type %d\n", V_VT(&result) );
|
||||
ok( V_UI4(&result) == 0xbabe, "wrong result %08x\n", V_UI4(&result) );
|
||||
|
||||
memset( args, 0x55, sizeof(args) );
|
||||
types[0] = VT_EMPTY;
|
||||
types[1] = VT_I4;
|
||||
V_I4(&args[1]) = 1111;
|
||||
types[2] = VT_EMPTY;
|
||||
types[3] = VT_I4;
|
||||
V_I4(&args[3]) = 0;
|
||||
types[4] = VT_EMPTY;
|
||||
memset( &result, 0xcc, sizeof(result) );
|
||||
res = DispCallFunc( NULL, (ULONG_PTR)void_func, CC_CDECL, VT_EMPTY, 5, types, pargs, &result );
|
||||
ok( res == S_OK, "DispCallFunc failed %x\n", res );
|
||||
ok( V_VT(&result) == VT_EMPTY, "wrong result type %d\n", V_VT(&result) );
|
||||
if (is_win64)
|
||||
ok( V_UI4(&result) == 12, "wrong result %08x\n", V_UI4(&result) );
|
||||
else
|
||||
ok( V_UI4(&result) == 0xcccccccc, "wrong result %08x\n", V_UI4(&result) );
|
||||
|
||||
memset( args, 0x55, sizeof(args) );
|
||||
types[0] = VT_I4;
|
||||
V_I4(&args[0]) = 3;
|
||||
memset( &result, 0xcc, sizeof(result) );
|
||||
res = DispCallFunc( &inst, 3 * sizeof(void*), CC_STDCALL, VT_I4, 1, types, pargs, &result );
|
||||
ok( res == S_OK, "DispCallFunc failed %x\n", res );
|
||||
ok( V_VT(&result) == VT_I4, "wrong result type %d\n", V_VT(&result) );
|
||||
ok( V_I4(&result) == 6, "wrong result %08x\n", V_I4(&result) );
|
||||
}
|
||||
|
||||
/* RegDeleteTreeW from dlls/advapi32/registry.c */
|
||||
static LSTATUS myRegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey)
|
||||
{
|
||||
|
@ -2603,9 +2790,9 @@ static void test_register_typelib(BOOL system_registration)
|
|||
}
|
||||
|
||||
if (system_registration)
|
||||
hr = UnRegisterTypeLib(&LIBID_register_test, 1, 0, LOCALE_NEUTRAL, sizeof(void*) == 8 ? SYS_WIN64 : SYS_WIN32);
|
||||
hr = UnRegisterTypeLib(&LIBID_register_test, 1, 0, LOCALE_NEUTRAL, is_win64 ? SYS_WIN64 : SYS_WIN32);
|
||||
else
|
||||
hr = pUnRegisterTypeLibForUser(&LIBID_register_test, 1, 0, LOCALE_NEUTRAL, sizeof(void*) == 8 ? SYS_WIN64 : SYS_WIN32);
|
||||
hr = pUnRegisterTypeLibForUser(&LIBID_register_test, 1, 0, LOCALE_NEUTRAL, is_win64 ? SYS_WIN64 : SYS_WIN32);
|
||||
ok(SUCCEEDED(hr), "got %08x\n", hr);
|
||||
|
||||
ITypeLib_Release(typelib);
|
||||
|
@ -2622,6 +2809,7 @@ START_TEST(typelib)
|
|||
test_TypeComp();
|
||||
test_CreateDispTypeInfo();
|
||||
test_TypeInfo();
|
||||
test_DispCallFunc();
|
||||
test_QueryPathOfRegTypeLib(32);
|
||||
if(sizeof(void*) == 8)
|
||||
test_QueryPathOfRegTypeLib(64);
|
||||
|
|
|
@ -5706,7 +5706,7 @@ static HRESULT WINAPI ITypeInfo_fnGetIDsOfNames( ITypeInfo2 *iface,
|
|||
|
||||
#ifdef __i386__
|
||||
|
||||
extern LONGLONG CDECL call_method( void *func, int nb_args, const DWORD *args );
|
||||
extern LONGLONG call_method( void *func, int nb_args, const DWORD *args, int *stack_offset );
|
||||
__ASM_GLOBAL_FUNC( call_method,
|
||||
"pushl %ebp\n\t"
|
||||
__ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
|
||||
|
@ -5718,16 +5718,20 @@ __ASM_GLOBAL_FUNC( call_method,
|
|||
"pushl %edi\n\t"
|
||||
__ASM_CFI(".cfi_rel_offset %edi,-8\n\t")
|
||||
"movl 12(%ebp),%edx\n\t"
|
||||
"movl %esp,%edi\n\t"
|
||||
"shll $2,%edx\n\t"
|
||||
"jz 1f\n\t"
|
||||
"subl %edx,%esp\n\t"
|
||||
"andl $~15,%esp\n\t"
|
||||
"subl %edx,%edi\n\t"
|
||||
"andl $~15,%edi\n\t"
|
||||
"movl %edi,%esp\n\t"
|
||||
"movl 12(%ebp),%ecx\n\t"
|
||||
"movl 16(%ebp),%esi\n\t"
|
||||
"movl %esp,%edi\n\t"
|
||||
"cld\n\t"
|
||||
"rep; movsl\n"
|
||||
"1:\tcall *8(%ebp)\n\t"
|
||||
"subl %esp,%edi\n\t"
|
||||
"movl 20(%ebp),%ecx\n\t"
|
||||
"movl %edi,(%ecx)\n\t"
|
||||
"leal -8(%ebp),%esp\n\t"
|
||||
"popl %edi\n\t"
|
||||
__ASM_CFI(".cfi_same_value %edi\n\t")
|
||||
|
@ -5738,6 +5742,9 @@ __ASM_GLOBAL_FUNC( call_method,
|
|||
__ASM_CFI(".cfi_same_value %ebp\n\t")
|
||||
"ret" )
|
||||
|
||||
/* same function but returning floating point */
|
||||
static const double (*call_double_method)(void*,int,const DWORD*,int*) = (void *)call_method;
|
||||
|
||||
/* ITypeInfo::Invoke
|
||||
*
|
||||
* Invokes a method, or accesses a property of an object, that implements the
|
||||
|
@ -5746,6 +5753,7 @@ __ASM_GLOBAL_FUNC( call_method,
|
|||
DWORD
|
||||
_invoke(FARPROC func,CALLCONV callconv, int nrargs, DWORD *args) {
|
||||
DWORD res;
|
||||
int stack_offset;
|
||||
|
||||
if (TRACE_ON(ole)) {
|
||||
int i;
|
||||
|
@ -5758,7 +5766,7 @@ _invoke(FARPROC func,CALLCONV callconv, int nrargs, DWORD *args) {
|
|||
switch (callconv) {
|
||||
case CC_STDCALL:
|
||||
case CC_CDECL:
|
||||
res = call_method( func, nrargs, args );
|
||||
res = call_method( func, nrargs, args, &stack_offset );
|
||||
break;
|
||||
default:
|
||||
FIXME("unsupported calling convention %d\n",callconv);
|
||||
|
@ -5796,6 +5804,10 @@ __ASM_GLOBAL_FUNC( call_method,
|
|||
"movq 8(%rsp),%rdx\n\t"
|
||||
"movq 16(%rsp),%r8\n\t"
|
||||
"movq 24(%rsp),%r9\n\t"
|
||||
"movq %rcx,%xmm0\n\t"
|
||||
"movq %rdx,%xmm1\n\t"
|
||||
"movq %r8,%xmm2\n\t"
|
||||
"movq %r9,%xmm3\n\t"
|
||||
"callq *%rax\n\t"
|
||||
"leaq -16(%rbp),%rsp\n\t"
|
||||
"popq %rdi\n\t"
|
||||
|
@ -5808,6 +5820,9 @@ __ASM_GLOBAL_FUNC( call_method,
|
|||
__ASM_CFI(".cfi_same_value %rbp\n\t")
|
||||
"ret")
|
||||
|
||||
/* same function but returning floating point */
|
||||
static const double (CDECL *call_double_method)(void*,int,const DWORD_PTR*) = (void *)call_method;
|
||||
|
||||
#endif /* __x86_64__ */
|
||||
|
||||
static HRESULT userdefined_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt)
|
||||
|
@ -5989,10 +6004,10 @@ DispCallFunc(
|
|||
VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult)
|
||||
{
|
||||
#ifdef __i386__
|
||||
int argspos;
|
||||
int argspos, stack_offset;
|
||||
void *func;
|
||||
UINT i;
|
||||
DWORD *args;
|
||||
LONGLONG ret;
|
||||
|
||||
TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n",
|
||||
pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg,
|
||||
|
@ -6005,21 +6020,26 @@ DispCallFunc(
|
|||
}
|
||||
|
||||
/* maximum size for an argument is sizeof(VARIANT) */
|
||||
args = HeapAlloc( GetProcessHeap(), 0, sizeof(VARIANT) * cActuals + sizeof(DWORD) );
|
||||
args = HeapAlloc( GetProcessHeap(), 0, sizeof(VARIANT) * cActuals + sizeof(DWORD) * 2 );
|
||||
|
||||
argspos = 0;
|
||||
/* start at 1 in case we need to pass a pointer to the return value as arg 0 */
|
||||
argspos = 1;
|
||||
if (pvInstance)
|
||||
{
|
||||
args[0] = (DWORD)pvInstance; /* the This pointer is always the first parameter */
|
||||
argspos++;
|
||||
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;
|
||||
|
||||
for (i=0;i<cActuals;i++)
|
||||
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:
|
||||
|
@ -6029,16 +6049,13 @@ DispCallFunc(
|
|||
argspos += sizeof(V_I8(arg)) / sizeof(DWORD);
|
||||
break;
|
||||
case VT_DECIMAL:
|
||||
memcpy( &args[argspos], &V_DECIMAL(arg), sizeof(V_DECIMAL(arg)) );
|
||||
argspos += sizeof(V_DECIMAL(arg)) / sizeof(DWORD);
|
||||
break;
|
||||
case VT_VARIANT:
|
||||
memcpy( &args[argspos], arg, sizeof(*arg) );
|
||||
argspos += sizeof(*arg) / sizeof(DWORD);
|
||||
break;
|
||||
case VT_RECORD:
|
||||
FIXME("VT_RECORD not implemented\n");
|
||||
/* fall through */
|
||||
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;
|
||||
|
@ -6047,29 +6064,47 @@ DispCallFunc(
|
|||
dump_Variant(arg);
|
||||
}
|
||||
|
||||
if (pvInstance)
|
||||
switch (vtReturn)
|
||||
{
|
||||
FARPROC *vtable = *(FARPROC**)pvInstance;
|
||||
ret = call_method(vtable[oVft/sizeof(void *)], argspos, args);
|
||||
case VT_EMPTY:
|
||||
call_method( func, argspos - 1, args + 1, &stack_offset );
|
||||
break;
|
||||
case VT_R4:
|
||||
V_R4(pvargResult) = call_double_method( func, argspos - 1, args + 1, &stack_offset );
|
||||
break;
|
||||
case VT_R8:
|
||||
case VT_DATE:
|
||||
V_R8(pvargResult) = call_double_method( func, argspos - 1, args + 1, &stack_offset );
|
||||
break;
|
||||
case VT_DECIMAL:
|
||||
case VT_VARIANT:
|
||||
args[0] = (DWORD)pvargResult; /* arg 0 is a pointer to the result */
|
||||
call_method( func, argspos, args, &stack_offset );
|
||||
break;
|
||||
case VT_I8:
|
||||
case VT_UI8:
|
||||
case VT_CY:
|
||||
V_UI8(pvargResult) = call_method( func, argspos - 1, args + 1, &stack_offset );
|
||||
break;
|
||||
default:
|
||||
V_UI4(pvargResult) = call_method( func, argspos - 1, args + 1, &stack_offset );
|
||||
break;
|
||||
}
|
||||
else
|
||||
/* if we aren't invoking an object then the function pointer is stored
|
||||
* in oVft */
|
||||
ret = call_method((FARPROC)oVft, argspos, args);
|
||||
|
||||
if (pvargResult && (vtReturn != VT_EMPTY))
|
||||
HeapFree( GetProcessHeap(), 0, args );
|
||||
if (stack_offset && cc == CC_STDCALL)
|
||||
{
|
||||
TRACE("Method returned %s\n",wine_dbgstr_longlong(ret));
|
||||
V_VT(pvargResult) = vtReturn;
|
||||
V_UI8(pvargResult) = ret;
|
||||
WARN( "stack pointer off by %d\n", stack_offset );
|
||||
return DISP_E_BADCALLEE;
|
||||
}
|
||||
HeapFree(GetProcessHeap(),0,args);
|
||||
if (vtReturn != VT_VARIANT) V_VT(pvargResult) = vtReturn;
|
||||
TRACE("retval: "); dump_Variant(pvargResult);
|
||||
return S_OK;
|
||||
|
||||
#elif defined(__x86_64__)
|
||||
int argspos;
|
||||
UINT i;
|
||||
DWORD_PTR *args, ret;
|
||||
DWORD_PTR *args;
|
||||
void *func;
|
||||
|
||||
TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n",
|
||||
pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg,
|
||||
|
@ -6081,15 +6116,18 @@ DispCallFunc(
|
|||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
/* maximum size for an argument is sizeof(VARIANT) */
|
||||
args = HeapAlloc( GetProcessHeap(), 0, sizeof(VARIANT) * cActuals + sizeof(DWORD_PTR) );
|
||||
/* maximum size for an argument is sizeof(DWORD_PTR) */
|
||||
args = HeapAlloc( GetProcessHeap(), 0, sizeof(DWORD_PTR) * (cActuals + 2) );
|
||||
|
||||
argspos = 0;
|
||||
/* start at 1 in case we need to pass a pointer to the return value as arg 0 */
|
||||
argspos = 1;
|
||||
if (pvInstance)
|
||||
{
|
||||
args[0] = (DWORD_PTR)pvInstance; /* the This pointer is always the first parameter */
|
||||
argspos++;
|
||||
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;
|
||||
|
||||
for (i = 0; i < cActuals; i++)
|
||||
{
|
||||
|
@ -6097,24 +6135,13 @@ DispCallFunc(
|
|||
|
||||
switch (prgvt[i])
|
||||
{
|
||||
case VT_R4:
|
||||
case VT_R8:
|
||||
case VT_DATE:
|
||||
FIXME(" floating point not supported properly\n" );
|
||||
memcpy( &args[argspos], &V_R8(arg), sizeof(V_R8(arg)) );
|
||||
argspos++;
|
||||
break;
|
||||
case VT_DECIMAL:
|
||||
memcpy( &args[argspos], &V_DECIMAL(arg), sizeof(V_DECIMAL(arg)) );
|
||||
argspos += sizeof(V_DECIMAL(arg)) / sizeof(DWORD_PTR);
|
||||
break;
|
||||
case VT_VARIANT:
|
||||
memcpy( &args[argspos], arg, sizeof(*arg) );
|
||||
argspos += sizeof(*arg) / sizeof(DWORD_PTR);
|
||||
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;
|
||||
case VT_RECORD:
|
||||
FIXME("VT_RECORD not implemented\n");
|
||||
/* fall through */
|
||||
default:
|
||||
args[argspos++] = V_UI8(arg);
|
||||
break;
|
||||
|
@ -6123,23 +6150,27 @@ DispCallFunc(
|
|||
dump_Variant(arg);
|
||||
}
|
||||
|
||||
if (pvInstance)
|
||||
switch (vtReturn)
|
||||
{
|
||||
FARPROC *vtable = *(FARPROC**)pvInstance;
|
||||
ret = call_method(vtable[oVft/sizeof(void *)], argspos, args);
|
||||
case VT_R4:
|
||||
V_R4(pvargResult) = call_double_method( func, argspos - 1, args + 1 );
|
||||
break;
|
||||
case VT_R8:
|
||||
case VT_DATE:
|
||||
V_R8(pvargResult) = call_double_method( func, argspos - 1, args + 1 );
|
||||
break;
|
||||
case VT_DECIMAL:
|
||||
case VT_VARIANT:
|
||||
args[0] = (DWORD_PTR)pvargResult; /* arg 0 is a pointer to the result */
|
||||
call_method( func, argspos, args );
|
||||
break;
|
||||
default:
|
||||
V_UI8(pvargResult) = call_method( func, argspos - 1, args + 1 );
|
||||
break;
|
||||
}
|
||||
else
|
||||
/* if we aren't invoking an object then the function pointer is stored
|
||||
* in oVft */
|
||||
ret = call_method((FARPROC)oVft, argspos, args);
|
||||
|
||||
if (pvargResult && (vtReturn != VT_EMPTY))
|
||||
{
|
||||
TRACE("Method returned 0x%lx\n",ret);
|
||||
V_VT(pvargResult) = vtReturn;
|
||||
V_UI8(pvargResult) = ret;
|
||||
}
|
||||
HeapFree(GetProcessHeap(),0,args);
|
||||
HeapFree( GetProcessHeap(), 0, args );
|
||||
if (vtReturn != VT_VARIANT) V_VT(pvargResult) = vtReturn;
|
||||
TRACE("retval: "); dump_Variant(pvargResult);
|
||||
return S_OK;
|
||||
|
||||
#else
|
||||
|
|
Loading…
Reference in New Issue