Connor McAdams : oleaut32/tests: Add tests for LPSAFEARRAY user marshal interface marshaling.
Alexandre Julliard
julliard at winehq.org
Wed Nov 24 15:17:17 CST 2021
Module: wine
Branch: master
Commit: b2574278f7ab6709b920f562bb03f23073827327
URL: https://source.winehq.org/git/wine.git/?a=commit;h=b2574278f7ab6709b920f562bb03f23073827327
Author: Connor McAdams <cmcadams at codeweavers.com>
Date: Tue Nov 23 20:07:31 2021 -0500
oleaut32/tests: Add tests for LPSAFEARRAY user marshal interface marshaling.
Signed-off-by: Connor McAdams <cmcadams at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/oleaut32/tests/usrmarshal.c | 179 ++++++++++++++++++++++++++++++++++++---
1 file changed, 169 insertions(+), 10 deletions(-)
diff --git a/dlls/oleaut32/tests/usrmarshal.c b/dlls/oleaut32/tests/usrmarshal.c
index 92d0da3403b..0e7c2cacb4b 100644
--- a/dlls/oleaut32/tests/usrmarshal.c
+++ b/dlls/oleaut32/tests/usrmarshal.c
@@ -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);
More information about the wine-cvs
mailing list