oleaut32/tests: Add tests for LPSAFEARRAY user marshal interface marshaling.

Signed-off-by: Connor McAdams <cmcadams@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Connor McAdams 2021-11-23 20:07:31 -05:00 committed by Alexandre Julliard
parent a1f2b44a1b
commit b2574278f7
1 changed files with 169 additions and 10 deletions

View File

@ -36,6 +36,14 @@
# define V_U2(A) (*(A))
#endif
typedef struct
{
IUnknown IUnknown_iface;
ULONG refs;
} HeapUnknown;
static const IUnknownVtbl HeapUnknown_Vtbl;
static inline SF_TYPE get_union_type(SAFEARRAY *psa)
{
VARTYPE vt;
@ -108,10 +116,17 @@ static ULONG get_cell_count(const SAFEARRAY *psa)
static DWORD elem_wire_size(LPSAFEARRAY lpsa, SF_TYPE sftype)
{
if (sftype == SF_BSTR)
switch (sftype)
{
case SF_HAVEIID:
case SF_UNKNOWN:
case SF_DISPATCH:
case SF_BSTR:
return sizeof(DWORD);
else
default:
return lpsa->cbElements;
}
}
static void check_safearray(void *buffer, LPSAFEARRAY lpsa)
@ -129,7 +144,8 @@ static void check_safearray(void *buffer, LPSAFEARRAY lpsa)
return;
}
if(FAILED(SafeArrayGetVartype(lpsa, &vt)))
/* If FADF_HAVEIID is set, VT will be 0. */
if((lpsa->fFeatures & FADF_HAVEIID) || FAILED(SafeArrayGetVartype(lpsa, &vt)))
vt = 0;
sftype = get_union_type(lpsa);
@ -217,8 +233,9 @@ static void init_user_marshal_cb(USER_MARSHAL_CB *umcb,
static void test_marshal_LPSAFEARRAY(void)
{
HeapUnknown *heap_unknown[10];
unsigned char *buffer, *next;
ULONG size, expected;
ULONG size, expected, size2;
LPSAFEARRAY lpsa;
LPSAFEARRAY lpsa2 = NULL;
SAFEARRAYBOUND sab[2];
@ -503,6 +520,154 @@ static void test_marshal_LPSAFEARRAY(void)
ok(hr == S_OK, "got 0x%08x\n", hr);
hr = SafeArrayDestroyDescriptor(lpsa);
ok(hr == S_OK, "got 0x%08x\n", hr);
/* Test an array of VT_UNKNOWN */
sab[0].lLbound = 3;
sab[0].cElements = ARRAY_SIZE(heap_unknown);
lpsa = SafeArrayCreate(VT_UNKNOWN, 1, sab);
/*
* Calculate approximate expected size. Sizes are different between Windows
* versions, so this should calculate the smallest size that seems sane.
*/
expected = 60;
for (i = 0; i < sab[0].cElements; i++)
{
HeapUnknown *unk;
VARIANT v;
unk = HeapAlloc(GetProcessHeap(), 0, sizeof(*unk));
unk->IUnknown_iface.lpVtbl = &HeapUnknown_Vtbl;
unk->refs = 1;
indices[0] = i + sab[0].lLbound;
heap_unknown[i] = unk;
hr = SafeArrayPutElement(lpsa, indices, &heap_unknown[i]->IUnknown_iface);
ok(hr == S_OK, "Failed to put unknown element hr 0x%x\n", hr);
ok(unk->refs == 2, "VT_UNKNOWN safearray elem %d, refcount %d\n", i, unk->refs);
V_VT(&v) = VT_UNKNOWN;
V_UNKNOWN(&v) = &unk->IUnknown_iface;
expected += VARIANT_UserSize(&umcb.Flags, 0, &v) - 20;
}
init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
size = LPSAFEARRAY_UserSize(&umcb.Flags, 0, &lpsa);
ok(size >= expected || size >= (expected + 12 ),
"size should be at least %u bytes, not %u\n", expected, size);
init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
size2 = LPSAFEARRAY_UserSize(&umcb.Flags, 1, &lpsa);
ok(size2 == (size + sizeof(DWORD)) || size2 == (size + sizeof(DWORD) + 12),
"size should be %u bytes, not %u\n", size + (ULONG) sizeof(DWORD), size2);
buffer = HeapAlloc(GetProcessHeap(), 0, size);
memset(buffer, 0xcc, size);
init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
next = LPSAFEARRAY_UserMarshal(&umcb.Flags, buffer, &lpsa);
ok((next - buffer) <= size, "Marshaled %u bytes, expected at most %u\n", (ULONG) (next - buffer), size);
check_safearray(buffer, lpsa);
todo_wine
ok(heap_unknown[0]->refs == 3, "Unexpected refcount %d\n", heap_unknown[0]->refs);
lpsa2 = NULL;
init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
next = LPSAFEARRAY_UserUnmarshal(&umcb.Flags, buffer, &lpsa2);
ok((next - buffer) <= size, "Marshaled %u bytes, expected at most %u\n", (ULONG) (next - buffer), size);
ok(lpsa2 != NULL, "LPSAFEARRAY didn't unmarshal, result %p\n", next);
for (i = 0; i < ARRAY_SIZE(heap_unknown); i++)
{
IUnknown *gotvalue = NULL;
if (lpsa2)
{
indices[0] = i + sab[0].lLbound;
hr = SafeArrayGetElement(lpsa2, indices, &gotvalue);
ok(hr == S_OK, "Failed to get unk element at %d, hres 0x%x\n", i, hr);
if (hr == S_OK)
{
ok(gotvalue == &heap_unknown[i]->IUnknown_iface, "Interface %d mismatch, expected %p, got %p\n",
i, &heap_unknown[i]->IUnknown_iface, gotvalue);
IUnknown_Release(gotvalue);
}
}
}
init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
LPSAFEARRAY_UserFree(&umcb.Flags, &lpsa2);
/* Set one of the elements to NULL, see how this effects size. */
indices[0] = 3 + sab[0].lLbound;
hr = SafeArrayPutElement(lpsa, indices, NULL);
ok(hr == S_OK, "Failed to put unknown element hr 0x%x\n", hr);
expected = 60;
for (i = 0; i < sab[0].cElements; i++)
{
VARIANT v;
V_VT(&v) = VT_UNKNOWN;
V_UNKNOWN(&v) = (i != 3) ? &heap_unknown[i]->IUnknown_iface : NULL;
expected += VARIANT_UserSize(&umcb.Flags, 0, &v) - 20;
}
init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
size = LPSAFEARRAY_UserSize(&umcb.Flags, 0, &lpsa);
ok(size >= expected || size >= (expected + 12 ),
"size should be at least %u bytes, not %u\n", expected, size);
init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
size2 = LPSAFEARRAY_UserSize(&umcb.Flags, 1, &lpsa);
ok(size2 == (size + sizeof(DWORD)) || size2 == (size + sizeof(DWORD) + 12),
"size should be %u bytes, not %u\n", size + (ULONG) sizeof(DWORD), size2);
buffer = HeapAlloc(GetProcessHeap(), 0, size);
memset(buffer, 0xcc, size);
init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
next = LPSAFEARRAY_UserMarshal(&umcb.Flags, buffer, &lpsa);
ok((next - buffer) <= expected, "Marshaled %u bytes, expected at most %u bytes\n", (ULONG) (next - buffer), expected);
check_safearray(buffer, lpsa);
lpsa2 = NULL;
init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
next = LPSAFEARRAY_UserUnmarshal(&umcb.Flags, buffer, &lpsa2);
ok((next - buffer) <= expected, "Marshaled %u bytes, expected at most %u bytes\n", (ULONG) (next - buffer), expected);
ok(lpsa2 != NULL, "LPSAFEARRAY didn't unmarshal, result %p\n", next);
for (i = 0; i < ARRAY_SIZE(heap_unknown); i++)
{
IUnknown *gotvalue = NULL;
if (lpsa2)
{
indices[0] = i + sab[0].lLbound;
hr = SafeArrayGetElement(lpsa2, indices, &gotvalue);
ok(hr == S_OK, "Failed to get unk element at %d, hres 0x%x\n", i, hr);
if (hr == S_OK)
{
/* Our NULL interface. */
if (i == 3)
ok(gotvalue == NULL, "Interface %d expected NULL, got %p\n", i, gotvalue);
else
{
ok(gotvalue == &heap_unknown[i]->IUnknown_iface, "Interface %d mismatch, expected %p, got %p\n",
i, &heap_unknown[i]->IUnknown_iface, gotvalue);
IUnknown_Release(gotvalue);
}
}
}
IUnknown_Release(&heap_unknown[i]->IUnknown_iface);
}
init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
LPSAFEARRAY_UserFree(&umcb.Flags, &lpsa2);
ok(heap_unknown[0]->refs == 1, "Unexpected refcount %d\n", heap_unknown[0]->refs);
hr = SafeArrayDestroy(lpsa);
ok(hr == S_OK, "got 0x%08x\n", hr);
}
static void check_bstr(void *buffer, BSTR b)
@ -648,12 +813,6 @@ static void test_marshal_BSTR(void)
SysFreeString(b);
}
typedef struct
{
IUnknown IUnknown_iface;
ULONG refs;
} HeapUnknown;
static inline HeapUnknown *impl_from_IUnknown(IUnknown *iface)
{
return CONTAINING_RECORD(iface, HeapUnknown, IUnknown_iface);