[PATCH v2 05/15] propsys: Implement Stg(De)SerializePropVariant

Jonas Kümmerlin rgcjonas at gmail.com
Sat Jul 18 11:26:44 CDT 2015


---
 dlls/propsys/propsys.spec    |   4 +-
 dlls/propsys/propvar.c       | 172 ++++++++++++++++++++
 dlls/propsys/tests/propsys.c | 374 +++++++++++++++++++++++++++++++++++++++++++
 include/propvarutil.h        |   7 +
 4 files changed, 555 insertions(+), 2 deletions(-)

diff --git a/dlls/propsys/propsys.spec b/dlls/propsys/propsys.spec
index 100f825..50bdf6e 100644
--- a/dlls/propsys/propsys.spec
+++ b/dlls/propsys/propsys.spec
@@ -151,8 +151,8 @@
 @ stub PropVariantToUInt64VectorAlloc
 @ stub PropVariantToUInt64WithDefault
 @ stub PropVariantToVariant
-@ stub StgDeserializePropVariant
-@ stub StgSerializePropVariant
+@ stdcall StgDeserializePropVariant(ptr long ptr)
+@ stdcall StgSerializePropVariant(ptr ptr ptr)
 @ stub VariantCompare
 @ stub VariantGetBooleanElem
 @ stub VariantGetDoubleElem
diff --git a/dlls/propsys/propvar.c b/dlls/propsys/propvar.c
index ae3fd2f..54d72ad 100644
--- a/dlls/propsys/propvar.c
+++ b/dlls/propsys/propvar.c
@@ -30,9 +30,13 @@
 #include "winuser.h"
 #include "shlobj.h"
 #include "propvarutil.h"
+#include "mimeole.h"
+#include "oleauto.h"
 
 #include "wine/debug.h"
 #include "wine/unicode.h"
+#include "wine/exception.h"
+#include "winternl.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(propsys);
 
@@ -995,3 +999,171 @@ INT WINAPI PropVariantCompareEx(REFPROPVARIANT propvar1, REFPROPVARIANT propvar2
 
     return res;
 }
+
+struct _PMemoryAllocator_vtable {
+    void *Allocate; /* virtual void* Allocate(ULONG cbSize); */
+    void *Free; /* virtual void Free(void *pv); */
+};
+
+typedef struct _PMemoryAllocator {
+    struct _PMemoryAllocator_vtable *vt;
+} PMemoryAllocator;
+
+static void * WINAPI PMemoryAllocator_Allocate(PMemoryAllocator *_this, ULONG cbSize)
+{
+    return CoTaskMemAlloc(cbSize);
+}
+
+static void WINAPI PMemoryAllocator_Free(PMemoryAllocator *_this, void *pv)
+{
+    CoTaskMemFree(pv);
+}
+
+#ifdef __i386__
+
+#include "pshpack1.h"
+typedef struct
+{
+    BYTE pop_eax;  /* popl  %eax  */
+    BYTE push_ecx; /* pushl %ecx  */
+    BYTE push_eax; /* pushl %eax  */
+    BYTE jmp_func; /* jmp   $func */
+    DWORD func;
+} THISCALL_TO_STDCALL_THUNK;
+#include "poppack.h"
+
+static THISCALL_TO_STDCALL_THUNK *wrapperCodeMem = NULL;
+
+static void fill_thunk(THISCALL_TO_STDCALL_THUNK *thunk, void *fn)
+{
+    thunk->pop_eax = 0x58;
+    thunk->push_ecx = 0x51;
+    thunk->push_eax = 0x50;
+    thunk->jmp_func = 0xe9;
+    thunk->func = (char*)fn - (char*)(&thunk->func + 1);
+}
+
+static void setup_allocator_vtable(struct _PMemoryAllocator_vtable *vtable)
+{
+    if (!wrapperCodeMem)
+    {
+        wrapperCodeMem = VirtualAlloc(NULL, 2 * sizeof(*wrapperCodeMem),
+                                    MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+
+        fill_thunk(&wrapperCodeMem[0], PMemoryAllocator_Allocate);
+        fill_thunk(&wrapperCodeMem[1], PMemoryAllocator_Free);
+    }
+
+    vtable->Allocate = &wrapperCodeMem[0];
+    vtable->Free = &wrapperCodeMem[1];
+}
+
+#else
+
+static void setup_allocator_vtable(struct _PMemoryAllocator_vtable *vtable)
+{
+    vtable->Allocate = PMemoryAllocator_Allocate;
+    vtable->Free = PMemoryAllocator_Free;
+}
+
+#endif
+
+
+HRESULT WINAPI StgDeserializePropVariant(const SERIALIZEDPROPERTYVALUE *pprop,
+                                         ULONG cbMax,
+                                         PROPVARIANT *pvar)
+{
+    PMemoryAllocator allocator;
+    struct _PMemoryAllocator_vtable vtbl;
+
+    TRACE("(%p, %lu, %p)\n", pprop, (unsigned long)cbMax, pvar);
+
+    allocator.vt = &vtbl;
+    setup_allocator_vtable(&vtbl);
+
+    if (!pprop || !pvar)
+        return E_INVALIDARG;
+
+    __TRY
+    {
+        StgConvertPropertyToVariant(pprop, CP_UNICODE, pvar, &allocator);
+    }
+    __EXCEPT_ALL
+    {
+        return HRESULT_FROM_WIN32(RtlNtStatusToDosError(GetExceptionCode()));
+    }
+    __ENDTRY
+
+    return S_OK;
+}
+
+HRESULT WINAPI StgSerializePropVariant(const PROPVARIANT *pVar,
+                                       SERIALIZEDPROPERTYVALUE **ppProp,
+                                       ULONG *pcb)
+{
+    HRESULT hr = S_OK;
+    ULONG   space = 0;
+    void   *buffer = NULL;
+
+    TRACE("(%p, %p, %p)\n", pVar, ppProp, pcb);
+
+    if (!pVar || !pcb)
+        return E_POINTER;
+
+    __TRY
+    {
+        StgConvertVariantToProperty(pVar, CP_UNICODE, NULL, &space, 0, FALSE, 0);
+    }
+    __EXCEPT_ALL
+    {
+        WARN("Failed to serialize property of type %d: hr=%08x\n", pVar->vt, hr);
+        return HRESULT_FROM_WIN32(RtlNtStatusToDosError(GetExceptionCode()));
+    }
+    __ENDTRY;
+
+    *pcb = 0;
+
+    /* MSDN requires ppProp to be defined, but, as an extension, we allow
+     * a NULL value and return the required size instead.
+     */
+    if (ppProp) *ppProp = NULL;
+
+    if (ppProp)
+    {
+        buffer = CoTaskMemAlloc(space);
+        if (!buffer)
+            return E_OUTOFMEMORY;
+
+        __TRY
+        {
+            *ppProp = StgConvertVariantToProperty(pVar, CP_UNICODE, buffer, &space, 0, FALSE, 0);
+            if (!*ppProp)
+                hr = E_FAIL;
+        }
+        __EXCEPT_ALL
+        {
+            WARN("Failed to serialize property of type %d: hr=%08x\n", pVar->vt, hr);
+            *ppProp = NULL;
+            CoTaskMemFree(buffer);
+            return HRESULT_FROM_WIN32(RtlNtStatusToDosError(GetExceptionCode()));
+        }
+        __ENDTRY;
+
+        if (FAILED(hr))
+        {
+            WARN("Failed to serialize property of type %d: hr=%08x\n", pVar->vt, hr);
+            CoTaskMemFree(buffer);
+
+            return hr;
+        }
+
+        *pcb    = space;
+    }
+    else
+    {
+        /* This is a wine extension */
+        *pcb = space;
+    }
+
+    return S_OK;
+}
diff --git a/dlls/propsys/tests/propsys.c b/dlls/propsys/tests/propsys.c
index 99d1c46..4044a38 100644
--- a/dlls/propsys/tests/propsys.c
+++ b/dlls/propsys/tests/propsys.c
@@ -866,6 +866,379 @@ static void test_intconversions(void)
     ok(llval == -7, "got wrong value %s\n", debugstr_longlong(llval));
 }
 
+static char *buffer_printable(void *buffer, size_t buffer_size)
+{
+    char *heap_buffer, *p;
+    unsigned char *source_buffer;
+
+    p = heap_buffer = HeapAlloc(GetProcessHeap(), 0, buffer_size * 4 + 5);
+    if (!heap_buffer)
+        return NULL;
+
+    source_buffer = buffer;
+    *p++ = '"';
+
+    for (; buffer_size; --buffer_size)
+    {
+        if ((*source_buffer >= '0' && *source_buffer <= '9')
+            || (*source_buffer >= 'a' && *source_buffer <= 'z')
+            || (*source_buffer >= 'A' && *source_buffer <= 'Z')
+            || *source_buffer == ' ' || *source_buffer == ',')
+        {
+            *p++ = (char)*source_buffer++;
+        }
+        else
+        {
+            sprintf(p, "\\%03o", (unsigned)*source_buffer++);
+            p += 4;
+        }
+    }
+
+    *p++ = '"';
+    *p++ = '\0';
+
+    return heap_buffer;
+}
+
+static void ok_compare(const char *type,
+                       BYTE *expected_buffer,
+                       size_t expected_buffer_size,
+                       BYTE *got_buffer,
+                       size_t got_buffer_size)
+{
+    int same = got_buffer_size == expected_buffer_size &&
+        !memcmp(expected_buffer, got_buffer, got_buffer_size);
+
+    char *got = buffer_printable(got_buffer, got_buffer_size);
+    char *expected = buffer_printable(expected_buffer, expected_buffer_size);
+
+    ok(same, "Comparing serialized %s: Expected %s:%lu but got %s:%lu\n", type, expected, (unsigned long)expected_buffer_size, got, (unsigned long)got_buffer_size);
+
+    HeapFree(GetProcessHeap(), 0, got);
+    HeapFree(GetProcessHeap(), 0, expected);
+}
+
+static void check_serialize_func(const char *type, const PROPVARIANT *prop, BYTE *expected, size_t expected_size)
+{
+    PROPVARIANT out;
+    HRESULT hr;
+    INT cmp;
+    SERIALIZEDPROPERTYVALUE *serialized = NULL;
+    ULONG                    serialized_size = 0;
+
+    PropVariantInit(&out);
+
+    hr = StgSerializePropVariant(prop, &serialized, &serialized_size);
+    ok(hr == S_OK, "Serializing %s: %08x\n", type, (unsigned)hr);
+
+    ok_compare(type, expected, expected_size, (BYTE*)serialized, (size_t)serialized_size);
+
+    hr = StgDeserializePropVariant(serialized, serialized_size, &out);
+    /* WTF: Win8 chokes on VT_DECIMAL, won't deserialize it but whatever it
+            deserializes compares equal to the original value                */
+    ok(hr == S_OK || broken(hr == E_FAIL && prop->vt == VT_DECIMAL), "Deserializing %s: %08x\n", type, (unsigned)hr);
+
+    cmp = PropVariantCompare(prop, &out);
+    ok(cmp == 0, "Deserialized %s is different from original value!\n", type);
+
+    PropVariantClear(&out);
+    CoTaskMemFree(serialized);
+}
+
+#define CHECK_SERIALIZE(type, prop, buffer_str_literal) \
+    do { \
+        unsigned char _str[] = buffer_str_literal; \
+        check_serialize_func(type, prop, _str, sizeof(_str) - 1); \
+    } while (0)
+
+#define DO_INT_TEST(ctype, functype, single_buffer_str, vector_buffer_str, values...) \
+    do { \
+        PROPVARIANT v; \
+        HRESULT hr; \
+        ctype vbuffer[] = { values }; \
+        \
+        /* first try a single value */ \
+        PropVariantInit(&v); \
+        hr = InitPropVariantFrom##functype(vbuffer[0], &v); \
+        ok(hr == S_OK, "Initializing PROPVARIANT from " #ctype ": %08x\n", (unsigned)hr); \
+        \
+        CHECK_SERIALIZE(#ctype, &v, single_buffer_str); \
+        \
+        PropVariantClear(&v); \
+        \
+        /* then try a vector */ \
+        PropVariantInit(&v); \
+        hr = InitPropVariantFrom##functype##Vector(vbuffer, sizeof(vbuffer)/sizeof(vbuffer[0]), &v); \
+        ok(hr == S_OK, "Initializing PROPVARIANT from " #ctype " Vector: %08x\n", (unsigned)hr); \
+        \
+        CHECK_SERIALIZE(#ctype " Vector", &v, vector_buffer_str); \
+        \
+        PropVariantClear(&v); \
+    } while(0)
+
+/* FIXME: In wine, this really tests OLE32.dll */
+static void test_serialization(void)
+{
+    HRESULT hr;
+
+    DO_INT_TEST(SHORT, Int16, "\002\000\000\000\040\000\000\000", "\002\020\000\000\003\000\000\000\040\000\167\362\052\000\000\000", 32, -3465, 42);
+    DO_INT_TEST(USHORT, UInt16, "\022\000\000\000\040\000\000\000", "\022\020\000\000\003\000\000\000\040\000\376\377\052\000\000\000", 32, 65534, 42);
+    DO_INT_TEST(LONG, Int32, "\003\000\000\000\040\000\000\000", "\003\020\000\000\003\000\000\000\040\000\000\000\066\113\005\000\312\366\377\377", 32, 346934, -2358);
+    DO_INT_TEST(ULONG, UInt32, "\023\000\000\000\357\276\255\336", "\023\020\000\000\005\000\000\000\357\276\255\336\276\272\376\312\276\272\255\336\376\312\357\276\357\276\276\272", 0xDEADBEEF, 0xCAFEBABE, 0xDEADBABE, 0xBEEFCAFE, 0xBABEBEEF);
+    DO_INT_TEST(LONGLONG, Int64, "\024\000\000\000\065\065\043\316\114\000\000\000", "\024\020\000\000\003\000\000\000\065\065\043\316\114\000\000\000\341\030\011\376\377\377\377\377\343\226\003\000\000\000\000\000", 329875928373, -32958239, 235235);
+    DO_INT_TEST(ULONGLONG, UInt64, "\025\000\000\000\276\272\357\276\376\312\355\015", "\025\020\000\000\001\000\000\000\276\272\357\276\376\312\355\015", 0xDEDCAFEBEEFBABE);
+    DO_INT_TEST(BOOL, Boolean, "\013\000\000\000\377\377\000\000", "\013\020\000\000\005\000\000\000\377\377\000\000\377\377\000\000\000\000\000\000", TRUE, FALSE, TRUE, FALSE, FALSE);
+
+    /* FileTime */
+    {
+        PROPVARIANT vSingle;
+        PROPVARIANT vVector;
+        FILETIME ftVec[] = { { 0xDEADBEEF, 0xCAFEBABE }, { 0xDEADBABE, 0xCAFEBEEF }, { 239508, 2484 } };
+
+        PropVariantInit(&vSingle); PropVariantInit(&vVector);
+
+        hr = InitPropVariantFromFileTime(&ftVec[0], &vSingle);
+        ok(hr == S_OK, "InitPropVariantFromFileTime: %08x\n", (unsigned)hr);
+
+        hr = InitPropVariantFromFileTimeVector(ftVec, sizeof(ftVec)/sizeof(ftVec[0]), &vVector);
+        ok(hr == S_OK, "InitPropVariantFromFileTimeVector: %08x\n", (unsigned)hr);
+
+        CHECK_SERIALIZE("FILETIME", &vSingle, "\100\000\000\000\357\276\255\336\276\272\376\312");
+        CHECK_SERIALIZE("FILETIME Vector", &vVector, "\100\020\000\000\003\000\000\000\357\276\255\336\276\272\376\312\276\272\255\336\357\276\376\312\224\247\003\000\264\011\000\000");
+
+        PropVariantClear(&vSingle); PropVariantClear(&vVector);
+    }
+
+    /* Int8 / Uint8 */
+    {
+        PROPVARIANT vc;
+        PROPVARIANT vac;
+        PROPVARIANT vb;
+        PROPVARIANT vab;
+
+        char cVec[] = "Hello World, How are You?";
+        BYTE bVec[] = { 0xDE, 0xAD, 0xCA, 0xFE, 0xBA };
+
+        vc.vt = VT_I1;
+        vc.u.cVal = cVec[0];
+
+        vac.vt = VT_VECTOR|VT_I1;
+        vac.u.cac.cElems = sizeof(cVec)/sizeof(cVec[0]);
+        vac.u.cac.pElems = cVec;
+
+        vb.vt = VT_UI1;
+        vb.u.bVal = bVec[0];
+
+        vab.vt = VT_VECTOR|VT_UI1;
+        vab.u.caub.cElems = sizeof(bVec)/sizeof(bVec[0]);
+        vab.u.caub.pElems = bVec;
+
+        CHECK_SERIALIZE("char", &vc, "\020\000\000\000\110\000\000\000");
+        CHECK_SERIALIZE("char vector", &vac, "\020\020\000\000\032\000\000\000\110\145\154\154\157\040\127\157\162\154\144\054\040\110\157\167\040\141\162\145\040\131\157\165\077\000\000\000");
+        CHECK_SERIALIZE("byte", &vb, "\021\000\000\000\336\000\000\000");
+        CHECK_SERIALIZE("byte vector", &vab, "\021\020\000\000\005\000\000\000\336\255\312\376\272\000\000\000");
+    }
+
+    /* Float */
+    {
+        PROPVARIANT vSingle;
+        PROPVARIANT vVector;
+
+        FLOAT fVec[] = { 3.14156778354f, 0.239852935758f, 128471284.354f, -523525.236f };
+
+        PropVariantInit(&vSingle); PropVariantInit(&vVector);
+
+        vSingle.vt = VT_R4;
+        vSingle.u.fltVal = fVec[0];
+        vVector.vt = VT_VECTOR|VT_R4;
+        vVector.u.caflt.cElems = sizeof(fVec)/sizeof(fVec[0]);
+        vVector.u.caflt.pElems = fVec;
+
+        CHECK_SERIALIZE("float", &vSingle, "\004\000\000\000\162\017\111\100");
+        CHECK_SERIALIZE("float vector", &vVector, "\004\020\000\000\004\000\000\000\162\017\111\100\002\234\165\076\037\012\365\114\250\240\377\310");
+    }
+
+    /* LPSTR */
+    /* The serialization routine converts these to UTF-16 and back to CP_ACP
+     * on return */
+    {
+        PROPVARIANT vSingle;
+        PROPVARIANT vVector;
+
+        char str1[] = "HelloWorld";
+        char str2[] = "aBc";
+        char str3[] = "Blub";
+        char *arr[] = { str1, str2, str3 };
+
+        vSingle.vt = VT_LPSTR;
+        vSingle.u.pszVal = str1;
+
+        vVector.vt = VT_VECTOR|VT_LPSTR;
+        vVector.u.calpstr.cElems = sizeof(arr)/sizeof(arr[0]);
+        vVector.u.calpstr.pElems = arr;
+
+        CHECK_SERIALIZE("lpstr", &vSingle, "\036\000\000\000\026\000\000\000H\000e\000l\000l\000o\000W\000o\000r\000l\000d\000\000\000\000\000");
+        CHECK_SERIALIZE("lpstr vector", &vVector, "\036\020\000\000\003\000\000\000\026\000\000\000H\000e\000l\000l\000o\000W\000o\000r\000l\000d\000\000\000\000\000\010\000\000\000a\000B\000c\000\000\000\012\000\000\000B\000l\000u\000b\000\000\000\000\000");
+    }
+
+    /* LPWSTR */
+    {
+        PROPVARIANT vSingle;
+        PROPVARIANT vVector;
+
+        WCHAR str1[] = { 'H', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'l', 'd', 0 };
+        WCHAR str2[] = { 'a', 'B', 'c', 0 };
+        WCHAR str3[] = { 'B', 'l', 'u', 'b', 0 };
+        /* disclaimer: I don't speak chinese, I just want to test some Unicode characters */
+        WCHAR str4[] = { 0x4E40, 0x4FB0, 0x4F47, 0x4EB9, 0 };
+        const WCHAR *arr[] = { str1, str2, str3, str4 };
+
+        PropVariantInit(&vSingle); PropVariantInit(&vVector);
+
+        hr = InitPropVariantFromString(str1, &vSingle);
+        ok(hr == S_OK, "InitPropVariantFromString: %08x\n", (unsigned)hr);
+
+        hr = InitPropVariantFromStringVector(arr, sizeof(arr)/sizeof(arr[0]), &vVector);
+
+        CHECK_SERIALIZE("lpwstr", &vSingle, "\037\000\000\000\013\000\000\000\110\000\145\000\154\000\154\000\157\000\127\000\157\000\162\000\154\000\144\000\000\000\000\000");
+        CHECK_SERIALIZE("lpwstr vector", &vVector, "\037\020\000\000\004\000\000\000\013\000\000\000\110\000\145\000\154\000\154\000\157\000\127\000\157\000\162\000\154\000\144\000\000\000\000\000\004\000\000\000\141\000\102\000\143\000\000\000\005\000\000\000\102\000\154\000\165\000\142\000\000\000\000\000\005\000\000\000\100\116\260\117\107\117\271\116\000\000\000\000");
+
+        PropVariantClear(&vSingle);
+        PropVariantClear(&vVector);
+    }
+
+    /* BSTR */
+    {
+        PROPVARIANT vSingle;
+        PROPVARIANT vVector;
+
+        WCHAR str1[] = { 'H', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'l', 'd', 0 };
+        WCHAR str2[] = { 'a', 'B', 'c', 0 };
+        WCHAR str3[] = { 'B', 'l', 'u', 'b', 0 };
+        /* disclaimer: I don't speak chinese, I just want to test some Unicode characters */
+        WCHAR str4[] = { 0x4E40, 0x4FB0, 0x4F47, 0x4EB9, 0 };
+
+        BSTR arr[4];
+
+        arr[0] = SysAllocString(str1); /*FIXME: handle NULL*/
+        arr[1] = SysAllocString(str2);
+        arr[2] = SysAllocString(str3);
+        arr[3] = SysAllocString(str4);
+
+        vSingle.vt = VT_BSTR;
+        vSingle.u.bstrVal = arr[0];
+        vVector.vt = VT_VECTOR|VT_BSTR;
+        vVector.u.cabstr.cElems = sizeof(arr)/sizeof(arr[0]);
+        vVector.u.cabstr.pElems = arr;
+
+        CHECK_SERIALIZE("BSTR", &vSingle, "\010\000\000\000\026\000\000\000H\000e\000l\000l\000o\000W\000o\000r\000l\000d\000\000\000\000\000");
+        CHECK_SERIALIZE("BSTR vector", &vVector, "\010\020\000\000\004\000\000\000\026\000\000\000H\000e\000l\000l\000o\000W\000o\000r\000l\000d\000\000\000\000\000\010\000\000\000a\000B\000c\000\000\000\012\000\000\000B\000l\000u\000b\000\000\000\000\000\012\000\000\000\100N\260OGO\271N\000\000\000\000");
+
+        SysFreeString(arr[0]);
+        SysFreeString(arr[1]);
+        SysFreeString(arr[2]);
+        SysFreeString(arr[3]);
+    }
+
+    /* Clipdata */
+    {
+        PROPVARIANT vSingle;
+        PROPVARIANT vVector;
+
+        char data1[] = "Hello World, how are you today?";
+        char data2[] = "Boo";
+
+        CLIPDATA cfArr[] = {
+            {
+                sizeof(data1) + 4,
+                42,
+                (BYTE*)data1
+            }, {
+                sizeof(data2) + 4,
+                0xBABE,
+                (BYTE*)data2
+            }
+
+        };
+
+        vSingle.vt = VT_CF;
+        vSingle.u.pclipdata = &cfArr[0];
+
+        vVector.vt = VT_VECTOR|VT_CF;
+        vVector.u.caclipdata.cElems = sizeof(cfArr)/sizeof(cfArr[0]);
+        vVector.u.caclipdata.pElems = cfArr;
+
+        CHECK_SERIALIZE("CF", &vSingle, "G\000\000\000\044\000\000\000\052\000\000\000Hello World, how are you today\077\000");
+        CHECK_SERIALIZE("CF vector", &vVector, "G\020\000\000\002\000\000\000\044\000\000\000\052\000\000\000Hello World, how are you today\077\000\010\000\000\000\276\272\000\000Boo\000");
+    }
+
+    /* CLSID */
+    {
+        PROPVARIANT vSingle;
+        PROPVARIANT vVector;
+
+        CLSID arr[] = {
+            {  0x557cf406, 0x1a04, 0x11d3, { 0x9a,0x73,0x00,0x00,0xf8,0x1e,0xf3,0x2e } },
+            {  0xDEADBEEF, 0xCAFE, 0xBABE, { 0xDE,0xAD,0xBA,0xBE,0xCA,0xFE,0xBE,0xEF } }
+        };
+
+        InitPropVariantFromCLSID(&arr[0], &vSingle);
+
+        vVector.vt = VT_VECTOR|VT_CLSID;
+        vVector.u.cauuid.cElems = sizeof(arr)/sizeof(arr[0]);
+        vVector.u.cauuid.pElems = arr;
+
+        CHECK_SERIALIZE("CLSID", &vSingle, "H\000\000\000\006\364\174U\004\032\323\021\232s\000\000\370\036\363\056");
+        CHECK_SERIALIZE("CLSID", &vVector, "H\020\000\000\002\000\000\000\006\364\174U\004\032\323\021\232s\000\000\370\036\363\056\357\276\255\336\376\312\276\272\336\255\272\276\312\376\276\357");
+
+        PropVariantClear(&vSingle);
+    }
+
+    /* DECIMAL */
+    {
+        PROPVARIANT v;
+        DECIMAL *asDecimal = (DECIMAL*)&v;
+
+        PropVariantInit(&v);
+        asDecimal->u.sign = DECIMAL_NEG;
+        asDecimal->u.scale = 5;
+        asDecimal->Hi32 = 0xCAFEBABE;
+        asDecimal->u1.Lo64 = 0xDEADBABECAFEBEEF;
+        v.vt = VT_DECIMAL;
+
+
+        CHECK_SERIALIZE("DECIMAL", &v, "\016\000\000\000\000\000\005\200\276\272\376\312\357\276\376\312\276\272\255\336");
+    }
+
+    /* VARIANT */
+    /* Unfortunately, we may only apply one level of variants :( */
+    {
+        PROPVARIANT vVec[2];
+        PROPVARIANT v;
+
+        InitPropVariantFromUInt32(0xDEADBABE, &vVec[0]);
+        InitPropVariantFromInt16(1342, &vVec[1]);
+
+        v.vt = VT_VECTOR|VT_VARIANT;
+        v.u.capropvar.cElems = sizeof(vVec)/sizeof(vVec[0]);
+        v.u.capropvar.pElems = vVec;
+
+        CHECK_SERIALIZE("VARIANT vector", &v, "\014\020\000\000\002\000\000\000\023\000\000\000\276\272\255\336\002\000\000\000\076\005\000\000");
+    }
+
+    /* BLOB */
+    {
+        PROPVARIANT vBlob;
+        char buffer[] = "Hello, World";
+
+        vBlob.vt = VT_BLOB;
+        vBlob.u.blob.cbSize = sizeof(buffer);
+        vBlob.u.blob.pBlobData = (BYTE*)buffer;
+
+        CHECK_SERIALIZE("BLOB", &vBlob, "A\000\000\000\015\000\000\000Hello, World\000\000\000\000");
+    }
+}
+
 START_TEST(propsys)
 {
     test_PSStringFromPropertyKey();
@@ -876,4 +1249,5 @@ START_TEST(propsys)
     test_PropVariantToGUID();
     test_PropVariantCompare();
     test_intconversions();
+    test_serialization();
 }
diff --git a/include/propvarutil.h b/include/propvarutil.h
index b0a1731..0a35ca8 100644
--- a/include/propvarutil.h
+++ b/include/propvarutil.h
@@ -96,6 +96,13 @@ HRESULT WINAPI InitPropVariantFromFileTime(const FILETIME *pft, PROPVARIANT *ppr
 HRESULT WINAPI InitPropVariantFromFileTimeVector(const FILETIME *pv, ULONG c, PROPVARIANT *pprop);
 HRESULT WINAPI InitPropVariantFromStringVector(const WCHAR **pstr, ULONG c, PROPVARIANT *pprop);
 
+HRESULT WINAPI StgSerializePropVariant(const PROPVARIANT *ppropvar,
+                                       SERIALIZEDPROPERTYVALUE **ppProp,
+                                       ULONG *pcb);
+HRESULT WINAPI StgDeserializePropVariant(const SERIALIZEDPROPERTYVALUE *pprop,
+                                         ULONG cbMax,
+                                         PROPVARIANT *ppropvar);
+
 /* FIXME: Make this available only if the compiler supports the inline keyword */
 #ifndef NO_PROPVAR_INLINES
 
-- 
2.4.3




More information about the wine-devel mailing list