--- 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