From aa3a23480308a2bc222e6087cbefb32427aff9a7 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Fri, 15 May 2015 14:03:35 +0300 Subject: [PATCH] ole32: Implement SNB marshalling. --- dlls/ole32/tests/usrmarshal.c | 94 +++++++++++++++++++++++++++++ dlls/ole32/usrmarshal.c | 108 +++++++++++++++++++++++++++++++--- 2 files changed, 194 insertions(+), 8 deletions(-) diff --git a/dlls/ole32/tests/usrmarshal.c b/dlls/ole32/tests/usrmarshal.c index c994af500a..51ccc596c7 100644 --- a/dlls/ole32/tests/usrmarshal.c +++ b/dlls/ole32/tests/usrmarshal.c @@ -768,6 +768,99 @@ static void test_marshal_STGMEDIUM(void) HeapFree(GetProcessHeap(), 0, expect_buffer); } +static void test_marshal_SNB(void) +{ + static const WCHAR str1W[] = {'s','t','r','i','n','g','1',0}; + static const WCHAR str2W[] = {'s','t','r','2',0}; + unsigned char *buffer, *src, *mbuf; + MIDL_STUB_MESSAGE stub_msg; + WCHAR **ptrW, *dataW; + USER_MARSHAL_CB umcb; + RPC_MESSAGE rpc_msg; + RemSNB *wiresnb; + SNB snb, snb2; + ULONG size; + + /* 4 bytes alignment */ + snb = NULL; + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL); + size = SNB_UserSize(&umcb.Flags, 3, &snb); + ok(size == 16, "Size should be 16, instead of %d\n", size); + + /* NULL block */ + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL); + size = SNB_UserSize(&umcb.Flags, 0, &snb); + ok(size == 12, "Size should be 12, instead of %d\n", size); + + buffer = HeapAlloc(GetProcessHeap(), 0, size); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL); + mbuf = SNB_UserMarshal(&umcb.Flags, buffer, &snb); + ok(mbuf == buffer + size, "got %p, %p\n", mbuf, buffer + size); + + wiresnb = (RemSNB*)buffer; + ok(wiresnb->ulCntStr == 0, "got %u\n", wiresnb->ulCntStr); + ok(wiresnb->ulCntChar == 0, "got %u\n", wiresnb->ulCntChar); + ok(*(ULONG*)wiresnb->rgString == 0, "got %u\n", *(ULONG*)wiresnb->rgString); + + snb2 = NULL; + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL); + SNB_UserUnmarshal(&umcb.Flags, buffer, &snb2); + ok(snb2 == NULL, "got %p\n", snb2); + + HeapFree(GetProcessHeap(), 0, buffer); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL); + SNB_UserFree(&umcb.Flags, &snb2); + + /* block with actual data */ + + /* allocate source block, n+1 pointers first, then data */ + src = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR*)*3 + sizeof(str1W) + sizeof(str2W)); + ptrW = (WCHAR**)src; + dataW = *ptrW = (WCHAR*)(src + 3*sizeof(WCHAR*)); + ptrW++; + *ptrW = (WCHAR*)(src + 3*sizeof(WCHAR*) + sizeof(str1W)); + ptrW++; + *ptrW = NULL; + lstrcpyW(dataW, str1W); + dataW += lstrlenW(str1W) + 1; + lstrcpyW(dataW, str2W); + + snb = (SNB)src; + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL); + size = SNB_UserSize(&umcb.Flags, 0, &snb); + ok(size == 38, "Size should be 38, instead of %d\n", size); + + buffer = HeapAlloc(GetProcessHeap(), 0, size); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL); + SNB_UserMarshal(&umcb.Flags, buffer, &snb); + + wiresnb = (RemSNB*)buffer; + ok(wiresnb->ulCntStr == 13, "got %u\n", wiresnb->ulCntStr); + ok(wiresnb->ulCntChar == 2, "got %u\n", wiresnb->ulCntChar); + /* payload length is stored one more time, as ULONG */ + ok(*(ULONG*)wiresnb->rgString == wiresnb->ulCntStr, "got %u\n", *(ULONG*)wiresnb->rgString); + dataW = &wiresnb->rgString[2]; + ok(!lstrcmpW(dataW, str1W), "marshalled string 0: %s\n", wine_dbgstr_w(dataW)); + dataW += sizeof(str1W)/sizeof(WCHAR); + ok(!lstrcmpW(dataW, str2W), "marshalled string 1: %s\n", wine_dbgstr_w(dataW)); + + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL); + + snb2 = NULL; + SNB_UserUnmarshal(&umcb.Flags, buffer, &snb2); + + ptrW = snb2; + ok(!lstrcmpW(*ptrW, str1W), "unmarshalled string 0: %s\n", wine_dbgstr_w(*ptrW)); + ptrW++; + ok(!lstrcmpW(*ptrW, str2W), "unmarshalled string 1: %s\n", wine_dbgstr_w(*ptrW)); + ptrW++; + ok(*ptrW == NULL, "expected terminating NULL ptr, got %p, start %p\n", *ptrW, snb2); + + HeapFree(GetProcessHeap(), 0, buffer); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL); + SNB_UserFree(&umcb.Flags, &snb2); +} + START_TEST(usrmarshal) { CoInitialize(NULL); @@ -780,6 +873,7 @@ START_TEST(usrmarshal) test_marshal_HMETAFILEPICT(); test_marshal_WdtpInterfacePointer(); test_marshal_STGMEDIUM(); + test_marshal_SNB(); CoUninitialize(); } diff --git a/dlls/ole32/usrmarshal.c b/dlls/ole32/usrmarshal.c index cd16fb2888..7875bef0a1 100644 --- a/dlls/ole32/usrmarshal.c +++ b/dlls/ole32/usrmarshal.c @@ -2160,25 +2160,117 @@ void __RPC_USER FLAG_STGMEDIUM_UserFree(ULONG *pFlags, FLAG_STGMEDIUM *pStgMediu ULONG __RPC_USER SNB_UserSize(ULONG *pFlags, ULONG StartingSize, SNB *pSnb) { - FIXME(":stub\n"); - return StartingSize; + ULONG size = StartingSize; + + TRACE("(%s, %d, %p\n", debugstr_user_flags(pFlags), StartingSize, pSnb); + + ALIGN_LENGTH(size, 3); + + /* two counters from RemSNB header, plus one more ULONG */ + size += 3*sizeof(ULONG); + + /* now actual data length */ + if (*pSnb) + { + WCHAR **ptrW = *pSnb; + + while (*ptrW) + { + size += (strlenW(*ptrW) + 1)*sizeof(WCHAR); + ptrW++; + } + } + + return size; } -unsigned char * __RPC_USER SNB_UserMarshal( ULONG *pFlags, unsigned char *pBuffer, SNB *pSnb) +struct SNB_wire { + ULONG charcnt; + ULONG strcnt; + ULONG datalen; + WCHAR data[1]; +}; + +unsigned char * __RPC_USER SNB_UserMarshal(ULONG *pFlags, unsigned char *pBuffer, SNB *pSnb) { - FIXME(":stub\n"); - return pBuffer; + struct SNB_wire *wire; + ULONG size; + + TRACE("(%s, %p, %p)\n", debugstr_user_flags(pFlags), pBuffer, pSnb); + + ALIGN_POINTER(pBuffer, 3); + + wire = (struct SNB_wire*)pBuffer; + wire->charcnt = wire->strcnt = 0; + size = 3*sizeof(ULONG); + + if (*pSnb) + { + WCHAR **ptrW = *pSnb; + WCHAR *dataW = wire->data; + + while (*ptrW) + { + ULONG len = strlenW(*ptrW) + 1; + + wire->strcnt++; + wire->charcnt += len; + memcpy(dataW, *ptrW, len*sizeof(WCHAR)); + dataW += len; + + size += len*sizeof(WCHAR); + ptrW++; + } + } + + wire->datalen = wire->charcnt; + return pBuffer + size; } unsigned char * __RPC_USER SNB_UserUnmarshal(ULONG *pFlags, unsigned char *pBuffer, SNB *pSnb) { - FIXME(":stub\n"); - return pBuffer; + USER_MARSHAL_CB *umcb = (USER_MARSHAL_CB*)pFlags; + struct SNB_wire *wire; + + TRACE("(%s, %p, %p)\n", debugstr_user_flags(pFlags), pBuffer, pSnb); + + wire = (struct SNB_wire*)pBuffer; + + if (*pSnb) + umcb->pStubMsg->pfnFree(*pSnb); + + if (wire->datalen == 0) + *pSnb = NULL; + else + { + WCHAR *src = wire->data, *dest; + WCHAR **ptrW; + ULONG i; + + ptrW = *pSnb = umcb->pStubMsg->pfnAllocate((wire->strcnt+1)*sizeof(WCHAR*) + wire->datalen); + dest = (WCHAR*)(*pSnb + wire->strcnt + 1); + + for (i = 0; i < wire->strcnt; i++) + { + ULONG len = strlenW(src); + memcpy(dest, src, (len + 1)*sizeof(WCHAR)); + *ptrW = dest; + src += len + 1; + dest += len + 1; + ptrW++; + } + *ptrW = NULL; + } + + return pBuffer + 3*sizeof(ULONG) + wire->datalen*sizeof(WCHAR); } void __RPC_USER SNB_UserFree(ULONG *pFlags, SNB *pSnb) { - FIXME(":stub\n"); + USER_MARSHAL_CB *umcb = (USER_MARSHAL_CB*)pFlags; + TRACE("(%p)\n", pSnb); + if (*pSnb) + umcb->pStubMsg->pfnFree(*pSnb); } /* call_as/local stubs for unknwn.idl */