[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