Commit 2e8a74d5 authored by Huw Davies's avatar Huw Davies Committed by Alexandre Julliard

oleaut32: Fix BSTR marshaling to be wire compatible with Windows.

parent 36712631
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
/* doesn't work on Windows due to needing more of the /* doesn't work on Windows due to needing more of the
* MIDL_STUB_MESSAGE structure to be filled out */ * MIDL_STUB_MESSAGE structure to be filled out */
#define LPSAFEARRAY_UNMARSHAL_WORKS 0 #define LPSAFEARRAY_UNMARSHAL_WORKS 0
#define BSTR_UNMARSHAL_WORKS 0
static void test_marshal_LPSAFEARRAY(void) static void test_marshal_LPSAFEARRAY(void)
{ {
...@@ -115,11 +116,78 @@ static void test_marshal_LPSAFEARRAY(void) ...@@ -115,11 +116,78 @@ static void test_marshal_LPSAFEARRAY(void)
HeapFree(GetProcessHeap(), 0, buffer); HeapFree(GetProcessHeap(), 0, buffer);
} }
static void test_marshal_BSTR(void)
{
unsigned long size;
MIDL_STUB_MESSAGE stubMsg = { 0 };
USER_MARSHAL_CB umcb = { 0 };
unsigned char *buffer;
BSTR b, b2;
WCHAR str[] = {'m','a','r','s','h','a','l',' ','t','e','s','t','1',0};
DWORD *wireb, len;
umcb.Flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
umcb.pReserve = NULL;
umcb.pStubMsg = &stubMsg;
b = SysAllocString(str);
len = SysStringLen(b);
ok(len == 13, "get %ld\n", len);
/* BSTRs are DWORD aligned */
size = BSTR_UserSize(&umcb.Flags, 1, &b);
ok(size == 42, "size %ld\n", size);
size = BSTR_UserSize(&umcb.Flags, 0, &b);
ok(size == 38, "size %ld\n", size);
buffer = HeapAlloc(GetProcessHeap(), 0, size);
BSTR_UserMarshal(&umcb.Flags, buffer, &b);
wireb = (DWORD*)buffer;
ok(*wireb == len, "wv[0] %08lx\n", *wireb);
wireb++;
ok(*wireb == len * 2, "wv[1] %08lx\n", *wireb);
wireb++;
ok(*wireb == len, "wv[2] %08lx\n", *wireb);
wireb++;
ok(!memcmp(wireb, str, len * 2), "strings differ\n");
if (BSTR_UNMARSHAL_WORKS)
{
b2 = NULL;
BSTR_UserUnmarshal(&umcb.Flags, buffer, &b2);
ok(b2 != NULL, "NULL LPSAFEARRAY didn't unmarshal\n");
ok(!memcmp(b, b2, (len + 1) * 2), "strings differ\n");
BSTR_UserFree(&umcb.Flags, &b2);
}
HeapFree(GetProcessHeap(), 0, buffer);
SysFreeString(b);
b = NULL;
size = BSTR_UserSize(&umcb.Flags, 0, &b);
ok(size == 12, "size %ld\n", size);
buffer = HeapAlloc(GetProcessHeap(), 0, size);
BSTR_UserMarshal(&umcb.Flags, buffer, &b);
wireb = (DWORD*)buffer;
ok(*wireb == 0, "wv[0] %08lx\n", *wireb);
wireb++;
ok(*wireb == 0xffffffff, "wv[1] %08lx\n", *wireb);
wireb++;
ok(*wireb == 0, "wv[2] %08lx\n", *wireb);
HeapFree(GetProcessHeap(), 0, buffer);
}
START_TEST(usrmarshal) START_TEST(usrmarshal)
{ {
CoInitialize(NULL); CoInitialize(NULL);
test_marshal_LPSAFEARRAY(); test_marshal_LPSAFEARRAY();
test_marshal_BSTR();
CoUninitialize(); CoUninitialize();
} }
...@@ -140,50 +140,73 @@ void WINAPI CLEANLOCALSTORAGE_UserFree(unsigned long *pFlags, CLEANLOCALSTORAGE ...@@ -140,50 +140,73 @@ void WINAPI CLEANLOCALSTORAGE_UserFree(unsigned long *pFlags, CLEANLOCALSTORAGE
/* BSTR */ /* BSTR */
typedef struct
{
DWORD len; /* No. of chars not including trailing '\0' */
DWORD byte_len; /* len * 2 or 0xffffffff if len == 0 */
DWORD len2; /* == len */
} bstr_wire_t;
unsigned long WINAPI BSTR_UserSize(unsigned long *pFlags, unsigned long Start, BSTR *pstr) unsigned long WINAPI BSTR_UserSize(unsigned long *pFlags, unsigned long Start, BSTR *pstr)
{ {
TRACE("(%lx,%ld,%p) => %p\n", *pFlags, Start, pstr, *pstr); TRACE("(%lx,%ld,%p) => %p\n", *pFlags, Start, pstr, *pstr);
if (*pstr) TRACE("string=%s\n", debugstr_w(*pstr)); if (*pstr) TRACE("string=%s\n", debugstr_w(*pstr));
Start += sizeof(FLAGGED_WORD_BLOB) + sizeof(OLECHAR) * (SysStringLen(*pstr) - 1); ALIGN_LENGTH(Start, 3);
TRACE("returning %ld\n", Start); Start += sizeof(bstr_wire_t) + sizeof(OLECHAR) * (SysStringLen(*pstr));
return Start; TRACE("returning %ld\n", Start);
return Start;
} }
unsigned char * WINAPI BSTR_UserMarshal(unsigned long *pFlags, unsigned char *Buffer, BSTR *pstr) unsigned char * WINAPI BSTR_UserMarshal(unsigned long *pFlags, unsigned char *Buffer, BSTR *pstr)
{ {
wireBSTR str = (wireBSTR)Buffer; bstr_wire_t *header;
TRACE("(%lx,%p,%p) => %p\n", *pFlags, Buffer, pstr, *pstr);
if (*pstr) TRACE("string=%s\n", debugstr_w(*pstr));
TRACE("(%lx,%p,%p) => %p\n", *pFlags, Buffer, pstr, *pstr); ALIGN_POINTER(Buffer, 3);
if (*pstr) TRACE("string=%s\n", debugstr_w(*pstr)); header = (bstr_wire_t*)Buffer;
str->fFlags = 0; header->len = header->len2 = SysStringLen(*pstr);
str->clSize = SysStringLen(*pstr); if (header->len)
if (str->clSize) {
memcpy(&str->asData, *pstr, sizeof(OLECHAR) * str->clSize); header->byte_len = header->len * sizeof(OLECHAR);
return Buffer + sizeof(FLAGGED_WORD_BLOB) + sizeof(OLECHAR) * (str->clSize - 1); memcpy(header + 1, *pstr, header->byte_len);
}
else
header->byte_len = 0xffffffff; /* special case for an empty string */
return Buffer + sizeof(*header) + sizeof(OLECHAR) * header->len;
} }
unsigned char * WINAPI BSTR_UserUnmarshal(unsigned long *pFlags, unsigned char *Buffer, BSTR *pstr) unsigned char * WINAPI BSTR_UserUnmarshal(unsigned long *pFlags, unsigned char *Buffer, BSTR *pstr)
{ {
wireBSTR str = (wireBSTR)Buffer; bstr_wire_t *header;
TRACE("(%lx,%p,%p) => %p\n", *pFlags, Buffer, pstr, *pstr); TRACE("(%lx,%p,%p) => %p\n", *pFlags, Buffer, pstr, *pstr);
if (str->clSize) {
SysReAllocStringLen(pstr, (OLECHAR*)&str->asData, str->clSize); ALIGN_POINTER(Buffer, 3);
} header = (bstr_wire_t*)Buffer;
else if (*pstr) { if(header->len != header->len2)
SysFreeString(*pstr); FIXME("len %08lx != len2 %08lx\n", header->len, header->len2);
*pstr = NULL;
} if(header->len)
if (*pstr) TRACE("string=%s\n", debugstr_w(*pstr)); SysReAllocStringLen(pstr, (OLECHAR*)(header + 1), header->len);
return Buffer + sizeof(FLAGGED_WORD_BLOB) + sizeof(OLECHAR) * (str->clSize - 1); else if (*pstr)
{
SysFreeString(*pstr);
*pstr = NULL;
}
if (*pstr) TRACE("string=%s\n", debugstr_w(*pstr));
return Buffer + sizeof(*header) + sizeof(OLECHAR) * header->len;
} }
void WINAPI BSTR_UserFree(unsigned long *pFlags, BSTR *pstr) void WINAPI BSTR_UserFree(unsigned long *pFlags, BSTR *pstr)
{ {
TRACE("(%lx,%p) => %p\n", *pFlags, pstr, *pstr); TRACE("(%lx,%p) => %p\n", *pFlags, pstr, *pstr);
if (*pstr) { if (*pstr)
SysFreeString(*pstr); {
*pstr = NULL; SysFreeString(*pstr);
} *pstr = NULL;
}
} }
/* VARIANT */ /* VARIANT */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment