From b08d3d2656746cfd78be59cea2e06abd178a1ddc Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Tue, 19 Oct 2010 02:35:27 +0400 Subject: [PATCH] oleaut32: Fix multidimensional SAFEARRAY marshalling. --- dlls/oleaut32/tests/usrmarshal.c | 96 +++++++++++++++++++++++++------- dlls/oleaut32/usrmarshal.c | 9 ++- 2 files changed, 84 insertions(+), 21 deletions(-) diff --git a/dlls/oleaut32/tests/usrmarshal.c b/dlls/oleaut32/tests/usrmarshal.c index 92758374b1e..1aae0f5ee51 100644 --- a/dlls/oleaut32/tests/usrmarshal.c +++ b/dlls/oleaut32/tests/usrmarshal.c @@ -120,9 +120,11 @@ static DWORD elem_wire_size(LPSAFEARRAY lpsa, SF_TYPE sftype) static void check_safearray(void *buffer, LPSAFEARRAY lpsa) { unsigned char *wiresa = buffer; + const SAFEARRAYBOUND *bounds; VARTYPE vt; SF_TYPE sftype; ULONG cell_count; + int i; if(!lpsa) { @@ -163,7 +165,18 @@ static void check_safearray(void *buffer, LPSAFEARRAY lpsa) ok(IsEqualGUID(&guid, wiresa), "guid mismatch\n"); wiresa += sizeof(GUID); } - ok(!memcmp(wiresa, lpsa->rgsabound, sizeof(lpsa->rgsabound[0]) * lpsa->cDims), "bounds mismatch\n"); + + /* bounds are marshaled in natural dimensions order */ + bounds = (SAFEARRAYBOUND*)wiresa; + for(i=0; icDims; i++) + { + ok(memcmp(bounds, &lpsa->rgsabound[lpsa->cDims-i-1], sizeof(SAFEARRAYBOUND)) == 0, + "bounds mismatch for dimension %d, got (%d,%d), expected (%d,%d)\n", i, + bounds->lLbound, bounds->cElements, lpsa->rgsabound[lpsa->cDims-i-1].lLbound, + lpsa->rgsabound[lpsa->cDims-i-1].cElements); + bounds++; + } + wiresa += sizeof(lpsa->rgsabound[0]) * lpsa->cDims; ok(*(DWORD *)wiresa == cell_count, "wiresa + 0x28 should be %u instead of %u\n", cell_count, *(DWORD*)wiresa); @@ -209,7 +222,7 @@ static void test_marshal_LPSAFEARRAY(void) ULONG size, expected; LPSAFEARRAY lpsa; LPSAFEARRAY lpsa2 = NULL; - SAFEARRAYBOUND sab; + SAFEARRAYBOUND sab[2]; RPC_MESSAGE rpc_msg; MIDL_STUB_MESSAGE stub_msg; USER_MARSHAL_CB umcb; @@ -220,22 +233,66 @@ static void test_marshal_LPSAFEARRAY(void) int i; LONG indices[1]; - sab.lLbound = 5; - sab.cElements = 10; + sab[0].lLbound = 5; + sab[0].cElements = 10; - lpsa = SafeArrayCreate(VT_I2, 1, &sab); + lpsa = SafeArrayCreate(VT_I2, 1, sab); *(DWORD *)lpsa->pvData = 0xcafebabe; lpsa->cLocks = 7; init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); size = LPSAFEARRAY_UserSize(&umcb.Flags, 1, &lpsa); expected = (44 + 1 + sizeof(ULONG) - 1) & ~(sizeof(ULONG) - 1); - expected += sab.cElements * sizeof(USHORT); + expected += sab[0].cElements * sizeof(USHORT); ok(size == expected || size == expected + 12, /* win64 */ "size should be %u bytes, not %u\n", expected, size); init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); size = LPSAFEARRAY_UserSize(&umcb.Flags, 0, &lpsa); - expected = 44 + sab.cElements * sizeof(USHORT); + expected = 44 + sab[0].cElements * sizeof(USHORT); + ok(size == expected || size == expected + 12, /* win64 */ + "size should be %u bytes, not %u\n", expected, size); + buffer = HeapAlloc(GetProcessHeap(), 0, 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 %u\n", (ULONG) (next - buffer), expected); + + check_safearray(buffer, lpsa); + + if (LPSAFEARRAY_UNMARSHAL_WORKS) + { + VARTYPE vt, vt2; + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); + LPSAFEARRAY_UserUnmarshal(&umcb.Flags, buffer, &lpsa2); + ok(lpsa2 != NULL, "LPSAFEARRAY didn't unmarshal\n"); + SafeArrayGetVartype(lpsa, &vt); + SafeArrayGetVartype(lpsa2, &vt2); + ok(vt == vt2, "vts differ %x %x\n", vt, vt2); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); + LPSAFEARRAY_UserFree(&umcb.Flags, &lpsa2); + } + HeapFree(GetProcessHeap(), 0, buffer); + lpsa->cLocks = 0; + SafeArrayDestroy(lpsa); + + /* use two dimensions */ + sab[0].lLbound = 5; + sab[0].cElements = 10; + sab[1].lLbound = 1; + sab[1].cElements = 2; + + lpsa = SafeArrayCreate(VT_I2, 2, sab); + *(DWORD *)lpsa->pvData = 0xcafebabe; + + lpsa->cLocks = 7; + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); + size = LPSAFEARRAY_UserSize(&umcb.Flags, 1, &lpsa); + expected = (44 + 1 + +sizeof(SAFEARRAYBOUND) + sizeof(ULONG) - 1) & ~(sizeof(ULONG) - 1); + expected += max(sab[0].cElements, sab[1].cElements) * lpsa->cDims * sizeof(USHORT); + ok(size == expected || size == expected + 12, /* win64 */ + "size should be %u bytes, not %u\n", expected, size); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); + size = LPSAFEARRAY_UserSize(&umcb.Flags, 0, &lpsa); + expected = 52 + max(sab[0].cElements, sab[1].cElements) * lpsa->cDims * sizeof(USHORT); ok(size == expected || size == expected + 12, /* win64 */ "size should be %u bytes, not %u\n", expected, size); buffer = HeapAlloc(GetProcessHeap(), 0, size); @@ -284,22 +341,22 @@ static void test_marshal_LPSAFEARRAY(void) } HeapFree(GetProcessHeap(), 0, buffer); - sab.lLbound = 5; - sab.cElements = 10; + sab[0].lLbound = 5; + sab[0].cElements = 10; - lpsa = SafeArrayCreate(VT_R8, 1, &sab); + lpsa = SafeArrayCreate(VT_R8, 1, sab); *(double *)lpsa->pvData = 3.1415; lpsa->cLocks = 7; init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); size = LPSAFEARRAY_UserSize(&umcb.Flags, 1, &lpsa); expected = (44 + 1 + (sizeof(double) - 1)) & ~(sizeof(double) - 1); - expected += sab.cElements * sizeof(double); + expected += sab[0].cElements * sizeof(double); ok(size == expected || size == expected + 16, /* win64 */ "size should be %u bytes, not %u\n", expected, size); init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); expected = (44 + (sizeof(double) - 1)) & ~(sizeof(double) - 1); - expected += sab.cElements * sizeof(double); + expected += sab[0].cElements * sizeof(double); size = LPSAFEARRAY_UserSize(&umcb.Flags, 0, &lpsa); ok(size == expected || size == expected + 8, /* win64 */ "size should be %u bytes, not %u\n", expected, size); @@ -344,19 +401,19 @@ static void test_marshal_LPSAFEARRAY(void) SafeArrayDestroyDescriptor(lpsa); /* Test an array of VT_BSTR */ - sab.lLbound = 3; - sab.cElements = sizeof(values) / sizeof(values[0]); + sab[0].lLbound = 3; + sab[0].cElements = sizeof(values) / sizeof(values[0]); - lpsa = SafeArrayCreate(VT_BSTR, 1, &sab); + lpsa = SafeArrayCreate(VT_BSTR, 1, sab); expected_bstr_size = 0; - for (i = 0; i < sab.cElements; i++) + for (i = 0; i < sab[0].cElements; i++) { int j; WCHAR buf[128]; for (j = 0; j <= i; j++) buf[j] = 'a' + j; buf[j] = 0; - indices[0] = i + sab.lLbound; + indices[0] = i + sab[0].lLbound; values[i] = SysAllocString(buf); hr = SafeArrayPutElement(lpsa, indices, values[i]); ok(hr == S_OK, "Failed to put bstr element hr 0x%x\n", hr); @@ -367,7 +424,7 @@ static void test_marshal_LPSAFEARRAY(void) init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); size = LPSAFEARRAY_UserSize(&umcb.Flags, 1, &lpsa); - expected = 44 + (sab.cElements * sizeof(DWORD)) + expected_bstr_size; + expected = 44 + (sab[0].cElements * sizeof(DWORD)) + expected_bstr_size; todo_wine ok(size == expected + sizeof(DWORD) || size == (expected + sizeof(DWORD) + 12 /* win64 */), "size should be %u bytes, not %u\n", expected + (ULONG) sizeof(DWORD), size); @@ -401,7 +458,7 @@ static void test_marshal_LPSAFEARRAY(void) if (lpsa2) { - indices[0] = i + sab.lLbound; + indices[0] = i + sab[0].lLbound; hr = SafeArrayGetElement(lpsa2, indices, &gotvalue); ok(hr == S_OK, "Failed to get bstr element at hres 0x%x\n", hr); if (hr == S_OK) @@ -423,7 +480,6 @@ static void test_marshal_LPSAFEARRAY(void) HeapFree(GetProcessHeap(), 0, buffer); SafeArrayDestroy(lpsa); - /* VARTYPE-less arrays with FADF_VARIANT */ hr = SafeArrayAllocDescriptor(1, &lpsa); ok(hr == S_OK, "saad failed %08x\n", hr); diff --git a/dlls/oleaut32/usrmarshal.c b/dlls/oleaut32/usrmarshal.c index 402794ce333..4884c66a34a 100644 --- a/dlls/oleaut32/usrmarshal.c +++ b/dlls/oleaut32/usrmarshal.c @@ -898,8 +898,10 @@ unsigned char * WINAPI LPSAFEARRAY_UserMarshal(ULONG *pFlags, unsigned char *Buf VARTYPE vt; SAFEARRAY *psa = *ppsa; ULONG ulCellCount = SAFEARRAY_GetCellCount(psa); + SAFEARRAYBOUND *bound; SF_TYPE sftype; GUID guid; + INT i; sftype = SAFEARRAY_GetUnionType(psa); @@ -932,7 +934,12 @@ unsigned char * WINAPI LPSAFEARRAY_UserMarshal(ULONG *pFlags, unsigned char *Buf Buffer += sizeof(guid); } - memcpy(Buffer, psa->rgsabound, sizeof(psa->rgsabound[0]) * psa->cDims); + /* bounds are marshaled in opposite order comparing to storage layout */ + bound = (SAFEARRAYBOUND*)Buffer; + for (i = 0; i < psa->cDims; i++) + { + memcpy(bound++, &psa->rgsabound[psa->cDims-i-1], sizeof(psa->rgsabound[0])); + } Buffer += sizeof(psa->rgsabound[0]) * psa->cDims; *(ULONG *)Buffer = ulCellCount;