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

Alexandre Julliard julliard at wine.codeweavers.com
Fri May 5 15:24:08 CDT 2006


Module: wine
Branch: refs/heads/master
Commit: 2e8a74d520311e60d70f40fd0af69a57c6d00ab6
URL:    http://source.winehq.org/git/?p=wine.git;a=commit;h=2e8a74d520311e60d70f40fd0af69a57c6d00ab6

Author: Huw Davies <huw at codeweavers.com>
Date:   Sat Apr 29 14:40:28 2006 +0100

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

---

 dlls/oleaut32/tests/usrmarshal.c |   68 ++++++++++++++++++++++++++++++++
 dlls/oleaut32/usrmarshal.c       |   81 ++++++++++++++++++++++++--------------
 2 files changed, 120 insertions(+), 29 deletions(-)

diff --git a/dlls/oleaut32/tests/usrmarshal.c b/dlls/oleaut32/tests/usrmarshal.c
index b5ca2fb..5d79315 100644
--- a/dlls/oleaut32/tests/usrmarshal.c
+++ b/dlls/oleaut32/tests/usrmarshal.c
@@ -30,6 +30,7 @@ #include "wine/test.h"
 /* doesn't work on Windows due to needing more of the
  * MIDL_STUB_MESSAGE structure to be filled out */
 #define LPSAFEARRAY_UNMARSHAL_WORKS 0
+#define BSTR_UNMARSHAL_WORKS 0
 
 static void test_marshal_LPSAFEARRAY(void)
 {
@@ -115,11 +116,78 @@ static void test_marshal_LPSAFEARRAY(voi
     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)
 {
     CoInitialize(NULL);
 
     test_marshal_LPSAFEARRAY();
+    test_marshal_BSTR();
 
     CoUninitialize();
 }
diff --git a/dlls/oleaut32/usrmarshal.c b/dlls/oleaut32/usrmarshal.c
index 9140c9e..05aef80 100644
--- a/dlls/oleaut32/usrmarshal.c
+++ b/dlls/oleaut32/usrmarshal.c
@@ -140,50 +140,73 @@ void WINAPI CLEANLOCALSTORAGE_UserFree(u
 
 /* 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)
 {
-  TRACE("(%lx,%ld,%p) => %p\n", *pFlags, Start, pstr, *pstr);
-  if (*pstr) TRACE("string=%s\n", debugstr_w(*pstr));
-  Start += sizeof(FLAGGED_WORD_BLOB) + sizeof(OLECHAR) * (SysStringLen(*pstr) - 1);
-  TRACE("returning %ld\n", Start);
-  return Start;
+    TRACE("(%lx,%ld,%p) => %p\n", *pFlags, Start, pstr, *pstr);
+    if (*pstr) TRACE("string=%s\n", debugstr_w(*pstr));
+    ALIGN_LENGTH(Start, 3);
+    Start += sizeof(bstr_wire_t) + sizeof(OLECHAR) * (SysStringLen(*pstr));
+    TRACE("returning %ld\n", Start);
+    return Start;
 }
 
 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);
-  if (*pstr) TRACE("string=%s\n", debugstr_w(*pstr));
-  str->fFlags = 0;
-  str->clSize = SysStringLen(*pstr);
-  if (str->clSize)
-    memcpy(&str->asData, *pstr, sizeof(OLECHAR) * str->clSize);
-  return Buffer + sizeof(FLAGGED_WORD_BLOB) + sizeof(OLECHAR) * (str->clSize - 1);
+    ALIGN_POINTER(Buffer, 3);
+    header = (bstr_wire_t*)Buffer;
+    header->len = header->len2 = SysStringLen(*pstr);
+    if (header->len)
+    {
+        header->byte_len = header->len * sizeof(OLECHAR);
+        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)
 {
-  wireBSTR str = (wireBSTR)Buffer;
-  TRACE("(%lx,%p,%p) => %p\n", *pFlags, Buffer, pstr, *pstr);
-  if (str->clSize) {
-    SysReAllocStringLen(pstr, (OLECHAR*)&str->asData, str->clSize);
-  }
-  else if (*pstr) {
-    SysFreeString(*pstr);
-    *pstr = NULL;
-  }
-  if (*pstr) TRACE("string=%s\n", debugstr_w(*pstr));
-  return Buffer + sizeof(FLAGGED_WORD_BLOB) + sizeof(OLECHAR) * (str->clSize - 1);
+    bstr_wire_t *header;
+    TRACE("(%lx,%p,%p) => %p\n", *pFlags, Buffer, pstr, *pstr);
+
+    ALIGN_POINTER(Buffer, 3);
+    header = (bstr_wire_t*)Buffer;
+    if(header->len != header->len2)
+        FIXME("len %08lx != len2 %08lx\n", header->len, header->len2);
+    
+    if(header->len)
+        SysReAllocStringLen(pstr, (OLECHAR*)(header + 1), header->len);
+    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)
 {
-  TRACE("(%lx,%p) => %p\n", *pFlags, pstr, *pstr);
-  if (*pstr) {
-    SysFreeString(*pstr);
-    *pstr = NULL;
-  }
+    TRACE("(%lx,%p) => %p\n", *pFlags, pstr, *pstr);
+    if (*pstr)
+    {
+        SysFreeString(*pstr);
+        *pstr = NULL;
+    }
 }
 
 /* VARIANT */




More information about the wine-cvs mailing list