[PATCH v2 07/15] propsys: Implement serialization of the in-memory property store
Jonas Kümmerlin
rgcjonas at gmail.com
Sat Jul 18 11:26:46 CDT 2015
The in-memory property store now supports IPersistSerializedPropStorage2.
---
dlls/propsys/propstore.c | 625 +++++++++++++++++++++++++++++++++++++++
dlls/propsys/propsys_classes.idl | 1 +
dlls/propsys/tests/propstore.c | 216 +++++++++++++-
3 files changed, 839 insertions(+), 3 deletions(-)
diff --git a/dlls/propsys/propstore.c b/dlls/propsys/propstore.c
index 3f028e9..1f5f58f 100644
--- a/dlls/propsys/propstore.c
+++ b/dlls/propsys/propstore.c
@@ -2,6 +2,7 @@
* standard IPropertyStore implementation
*
* Copyright 2012 Vincent Povirk for CodeWeavers
+ * Copyright 2015 Jonas Kümmerlin
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -32,6 +33,7 @@
#include "wine/debug.h"
#include "wine/unicode.h"
#include "wine/list.h"
+#include "mimeole.h"
#include "initguid.h"
#include "propsys_private.h"
@@ -63,6 +65,7 @@ typedef struct {
typedef struct {
IPropertyStoreCache IPropertyStoreCache_iface;
+ IPersistSerializedPropStorage2 IPersistSerializedPropStorage2_iface;
INamedPropertyStore INamedPropertyStore_iface;
LONG ref;
CRITICAL_SECTION lock;
@@ -75,6 +78,11 @@ static inline PropertyStore *impl_from_IPropertyStoreCache(IPropertyStoreCache *
return CONTAINING_RECORD(iface, PropertyStore, IPropertyStoreCache_iface);
}
+static inline PropertyStore *impl_from_IPersistSerializedPropStorage2(IPersistSerializedPropStorage2 *iface)
+{
+ return CONTAINING_RECORD(iface, PropertyStore, IPersistSerializedPropStorage2_iface);
+}
+
static inline PropertyStore *impl_from_INamedPropertyStore(INamedPropertyStore *iface)
{
return CONTAINING_RECORD(iface, PropertyStore, INamedPropertyStore_iface);
@@ -89,6 +97,11 @@ static HRESULT query_interface(PropertyStore *This, REFIID iid, void **ppv)
{
*ppv = &This->IPropertyStoreCache_iface;
}
+ else if (IsEqualIID(&IID_IPersistSerializedPropStorage, iid)
+ || IsEqualIID(&IID_IPersistSerializedPropStorage2, iid))
+ {
+ *ppv = &This->IPersistSerializedPropStorage2_iface;
+ }
else if (IsEqualIID(&IID_INamedPropertyStore, iid))
{
*ppv = &This->INamedPropertyStore_iface;
@@ -114,6 +127,16 @@ static HRESULT WINAPI PropertyStore_IPropertyStoreCache_QueryInterface(
return query_interface(This, iid, ppv);
}
+static HRESULT WINAPI PropertyStore_IPersistSerializedPropStorage_QueryInterface(
+ IPersistSerializedPropStorage2 *iface, REFIID iid, void **ppv)
+{
+ PropertyStore *This = impl_from_IPersistSerializedPropStorage2(iface);
+
+ TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
+
+ return query_interface(This, iid, ppv);
+}
+
static HRESULT WINAPI PropertyStore_INamedPropertyStore_QueryInterface(
INamedPropertyStore *iface, REFIID iid, void **ppv)
{
@@ -139,6 +162,16 @@ static ULONG WINAPI PropertyStore_IPropertyStoreCache_AddRef(IPropertyStoreCache
return ref;
}
+static ULONG WINAPI PropertyStore_IPersistSerializedPropStorage_AddRef(IPersistSerializedPropStorage2 *iface)
+{
+ PropertyStore *This = impl_from_IPersistSerializedPropStorage2(iface);
+ ULONG ref = add_ref(This);
+
+ TRACE("(%p) refcount=%u\n", iface, ref);
+
+ return ref;
+}
+
static ULONG WINAPI PropertyStore_INamedPropertyStore_AddRef(INamedPropertyStore *iface)
{
PropertyStore *This = impl_from_INamedPropertyStore(iface);
@@ -197,6 +230,16 @@ static ULONG WINAPI PropertyStore_IPropertyStoreCache_Release(IPropertyStoreCach
return ref;
}
+static ULONG WINAPI PropertyStore_IPersistSerializedPropStorage_Release(IPersistSerializedPropStorage2 *iface)
+{
+ PropertyStore *This = impl_from_IPersistSerializedPropStorage2(iface);
+ ULONG ref = release(This);
+
+ TRACE("(%p) refcount=%u\n", iface, ref);
+
+ return ref;
+}
+
static ULONG WINAPI PropertyStore_INamedPropertyStore_Release(INamedPropertyStore *iface)
{
PropertyStore *This = impl_from_INamedPropertyStore(iface);
@@ -668,6 +711,576 @@ static HRESULT WINAPI PropertyStore_SetValueAndState(IPropertyStoreCache *iface,
return hr;
}
+static HRESULT WINAPI PropertyStore_SetFlags(IPersistSerializedPropStorage2 *iface,
+ PERSIST_SPROPSTORE_FLAGS flags)
+{
+ TRACE("%p,%d: stub\n", iface, flags);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI PropertyStore_GetPropertyStorageSize(
+ IPersistSerializedPropStorage2 *iface, DWORD *pcb)
+{
+ DWORD count;
+ DWORD size = 0;
+ HRESULT hr = S_OK;
+ PropertyStore *This = impl_from_IPersistSerializedPropStorage2(iface);
+ propstore_format *format;
+ propstore_value *value;
+ propstore_named_value *named_value;
+
+ TRACE("%p,%p\n", iface, pcb);
+
+ if (!pcb)
+ return E_POINTER;
+
+ EnterCriticalSection(&This->lock);
+
+ /* As a special case, an empty propstore has size 0 */
+ hr = PropertyStore_GetCount(&This->IPropertyStoreCache_iface, &count);
+ if (FAILED(hr) || !count)
+ goto out;
+
+ LIST_FOR_EACH_ENTRY(format, &This->formats, propstore_format, entry)
+ {
+ size += 4; /* DWORD Storage size */
+ size += 4; /* DWORD Storage Version */
+ size += 16; /* GUID fmtid */
+
+ LIST_FOR_EACH_ENTRY(value, &format->values, propstore_value, entry)
+ {
+ DWORD propsize;
+
+ size += 4; /* DWORD Size */
+ size += 4; /* DWORD pid */
+ size += 1; /* Reserved. */
+
+ hr = StgSerializePropVariant(&value->propvar, NULL, &propsize);
+ if (FAILED(hr))
+ {
+ WARN("Property of type %d is not serializable\n", value->propvar.vt);
+ size = 0;
+ goto out;
+ }
+
+ size += propsize;
+ }
+
+ size += 4; /* Terminating Element */
+ }
+
+ if (!list_empty(&This->named))
+ {
+ size += 4; /* DWORD Storage size */
+ size += 4; /* DWORD Storage Version */
+ size += 16; /* GUID fmtid */
+
+ LIST_FOR_EACH_ENTRY(named_value, &This->named, propstore_named_value, entry)
+ {
+ DWORD propsize;
+ DWORD namesize;
+
+ size += 4; /* DWORD Size */
+ size += 4; /* DWORD String size */
+ size += 1; /* Reserved */
+
+ namesize = (lstrlenW(named_value->name) + 1) * sizeof(WCHAR);
+
+ hr = StgSerializePropVariant(&named_value->propvar, NULL, &propsize);
+ if (FAILED(hr))
+ {
+ WARN("Property of type %d is not serializable\n", named_value->propvar.vt);
+ size = 0;
+ goto out;
+ }
+
+ size += namesize + propsize;
+ }
+
+ size += 4; /* Terminating element */
+ }
+
+ size += 4; /* Terminating Storage */
+
+out:
+ LeaveCriticalSection(&This->lock);
+
+ *pcb = size;
+ return hr;
+}
+
+static inline void write_dword(BYTE *buffer, DWORD dw)
+{
+ buffer[0] = (dw & 0x000000FF);
+ buffer[1] = (dw & 0x0000FF00) >> 8;
+ buffer[2] = (dw & 0x00FF0000) >> 16;
+ buffer[3] = (dw & 0xFF000000) >> 24;
+}
+
+static inline void write_word(BYTE *buffer, WORD w)
+{
+ buffer[0] = (w & 0x00FF);
+ buffer[1] = (w & 0xFF00) >> 8;
+}
+
+static inline void write_clsid(BYTE *buffer, const CLSID *id)
+{
+ write_dword(buffer, id->Data1);
+ write_word(buffer + 4, id->Data2);
+ write_word(buffer + 6, id->Data3);
+ memcpy(buffer + 8, id->Data4, 8);
+}
+
+static inline void write_wstring(BYTE *buffer, const WCHAR *str, ULONG cChar)
+{
+ for (; cChar; --cChar, buffer += 2, ++str)
+ {
+ write_word(buffer, (WORD)*str);
+ }
+}
+
+static HRESULT WINAPI PropertyStore_GetPropertyStorageBuffer(
+ IPersistSerializedPropStorage2 *iface, SERIALIZEDPROPSTORAGE *psps, DWORD cb, DWORD *cbUsed)
+{
+ HRESULT hr = S_OK;
+ PropertyStore *This = impl_from_IPersistSerializedPropStorage2(iface);
+ propstore_format *format;
+ propstore_value *value;
+ propstore_named_value *named_value;
+ DWORD cb_Start = cb;
+ BYTE *buffer = (BYTE*)psps;
+
+#define REQUIRE_SPACE(cBytes) \
+ do { \
+ if ((cBytes) > cb) \
+ { \
+ hr = E_INVALIDARG; \
+ goto out; \
+ } \
+ } while(0)
+#define MOVE(cBytes) \
+ do { \
+ buffer += cBytes; \
+ cb -= cBytes; \
+ } while(0)
+
+ TRACE("%p,%p,%d,%p\n", iface, psps, cb, cbUsed);
+
+ if (!psps)
+ return E_POINTER;
+
+ EnterCriticalSection(&This->lock);
+
+ LIST_FOR_EACH_ENTRY(format, &This->formats, propstore_format, entry)
+ {
+ BYTE *pStorageSizeBuf = buffer; /* we set it afterwards */
+ DWORD storageSize = 24; /* storage size, storage version, fmtid */
+
+ REQUIRE_SPACE(24); /* Storage size, storage version, fmtid */
+
+ write_dword(buffer + 4, 0x53505331); /* DWORD Version */
+ write_clsid(buffer + 8, &format->fmtid);
+
+ MOVE(24);
+
+ LIST_FOR_EACH_ENTRY(value, &format->values, propstore_value, entry)
+ {
+ DWORD propsize;
+ SERIALIZEDPROPERTYVALUE *tmp = NULL;
+
+ hr = StgSerializePropVariant(&value->propvar, &tmp, &propsize);
+ if (FAILED(hr))
+ {
+ WARN("Property of type %d is not serializable\n", value->propvar.vt);
+ goto out;
+ }
+
+ if (cb < (9 + propsize)) /* Size, pid, reserved, content */
+ {
+ CoTaskMemFree(buffer);
+ hr = E_INVALIDARG;
+ goto out;
+ }
+
+ write_dword(buffer, propsize + 9); /* size */
+ write_dword(buffer + 4, value->pid); /* pid */
+ buffer[8] = 0; /* reserved byte to make sure everything is misaligned */
+
+ memcpy(buffer + 9, tmp, propsize);
+ CoTaskMemFree(tmp);
+
+ MOVE(9 + propsize);
+ storageSize += propsize + 9;
+ }
+
+ /* Terminating Element */
+ REQUIRE_SPACE(4);
+ ZeroMemory(buffer, 4);
+ MOVE(4);
+ storageSize += 4;
+
+ write_dword(pStorageSizeBuf, storageSize);
+ }
+
+ if (!list_empty(&This->named))
+ {
+ BYTE *pStorageSizeBuf = buffer; /* we set it afterwards */
+ DWORD storageSize = 24; /* storage size, storage version, fmtid */
+
+ REQUIRE_SPACE(24); /* Storage size, storage version, fmtid */
+
+ write_dword(buffer + 4, 0x53505331); /* DWORD Version */
+ write_clsid(buffer + 8, &FMTID_NamedProperties);
+
+ MOVE(24);
+
+ LIST_FOR_EACH_ENTRY(named_value, &This->named, propstore_named_value, entry)
+ {
+ DWORD propsize;
+ SERIALIZEDPROPERTYVALUE *tmp;
+ DWORD namesize;
+
+ namesize = (lstrlenW(named_value->name) + 1) * sizeof(WCHAR);
+ TRACE("Writing named property with name %s:%u\n", wine_dbgstr_w(named_value->name), namesize);
+
+ hr = StgSerializePropVariant(&named_value->propvar, &tmp, &propsize);
+ if (FAILED(hr))
+ {
+ WARN("Property of type %d is not serializable\n", named_value->propvar.vt);
+ goto out;
+ }
+
+ if ((9 + namesize + propsize) > cb)
+ {
+ CoTaskMemFree(tmp);
+ hr = E_INVALIDARG;
+ goto out;
+ }
+
+ write_dword(buffer, 9 + namesize + propsize);
+ write_dword(buffer + 4, namesize);
+ buffer[8] = 0;
+
+ write_wstring(buffer + 9, named_value->name, namesize/2);
+ memcpy(buffer + 9 + namesize, tmp, propsize);
+
+ MOVE(9 + namesize + propsize);
+ storageSize += namesize + propsize + 9;
+ }
+
+ /* Terminating Element */
+ REQUIRE_SPACE(4);
+ ZeroMemory(buffer, 4);
+ MOVE(4);
+ storageSize += 4;
+
+ write_dword(pStorageSizeBuf, storageSize);
+ }
+
+ /* Terminating Storage */
+ REQUIRE_SPACE(4);
+ ZeroMemory(buffer, 4);
+ MOVE(4);
+
+#undef REQUIRE_SPACE
+#undef MOVE
+
+out:
+ LeaveCriticalSection(&This->lock);
+
+ if (cbUsed)
+ *cbUsed = SUCCEEDED(hr) ? cb_Start - cb : 0;
+
+ return hr;
+}
+
+static HRESULT WINAPI PropertyStore_GetPropertyStorage(
+ IPersistSerializedPropStorage2 *iface, SERIALIZEDPROPSTORAGE **ppsps, DWORD *pcb)
+{
+ HRESULT hr;
+ DWORD size;
+ DWORD usedSize;
+ PropertyStore *This = impl_from_IPersistSerializedPropStorage2(iface);
+
+ TRACE("%p,%p,%p\n", iface, ppsps, pcb);
+
+ if (!ppsps || !pcb)
+ return E_POINTER;
+
+ EnterCriticalSection(&This->lock);
+
+ hr = PropertyStore_GetPropertyStorageSize(iface, &size);
+
+ if (SUCCEEDED(hr))
+ {
+ if (size == 0)
+ {
+ usedSize = 0;
+ *ppsps = NULL;
+ }
+ else if ((*ppsps = CoTaskMemAlloc(size)))
+ {
+ hr = PropertyStore_GetPropertyStorageBuffer(iface, *ppsps, size, &usedSize);
+ if (FAILED(hr))
+ {
+ CoTaskMemFree(*ppsps);
+ }
+
+ if (size != usedSize)
+ {
+ WARN("Buffer calculation was off by %u bytes\n", size - usedSize);
+ }
+ }
+ else
+ {
+ hr = E_OUTOFMEMORY;
+ }
+ }
+
+ LeaveCriticalSection(&This->lock);
+
+ if (SUCCEEDED(hr))
+ {
+ *pcb = usedSize;
+ }
+ else
+ {
+ *ppsps = NULL;
+ *pcb = 0;
+ }
+
+ return hr;
+}
+
+static inline void read_dword(const BYTE *buffer, DWORD *dw)
+{
+ *dw = buffer[0]
+ | (buffer[1] << 8)
+ | (buffer[2] << 16)
+ | (buffer[3] << 24);
+}
+
+static inline void read_word(const BYTE *buffer, WORD *w)
+{
+ *w = buffer[0] | (buffer[1] << 8);
+}
+
+static inline void read_clsid(const BYTE *buffer, CLSID *id)
+{
+ read_dword(buffer, &id->Data1);
+ read_word(buffer + 4, &id->Data2);
+ read_word(buffer + 6, &id->Data3);
+ memcpy(id->Data4, buffer + 8, 8);
+}
+
+static inline void read_wstring(const BYTE *buffer, WCHAR *str, ULONG cChar)
+{
+ for (; cChar; --cChar, ++str, buffer += 2)
+ {
+ read_word(buffer, (WORD*)str);
+ }
+}
+
+static HRESULT WINAPI PropertyStore_SetPropertyStorage(
+ IPersistSerializedPropStorage2 *iface, const SERIALIZEDPROPSTORAGE *psps, DWORD cb)
+{
+ HRESULT hr = S_OK;
+ PropertyStore *This = impl_from_IPersistSerializedPropStorage2(iface);
+ const BYTE *buffer = (const BYTE*)psps;
+
+#define REQUIRE_SPACE(cBytes) \
+ do { \
+ if (cBytes > cb) \
+ { \
+ WARN("Trying to read %u bytes at offset %u where only %u are available\n", \
+ cBytes, (unsigned)(buffer - (const BYTE*)psps), cb); \
+ hr = E_INVALIDARG; \
+ goto out; \
+ } \
+ } while(0)
+#define MOVE(cBytes) \
+ do { \
+ buffer += cBytes; \
+ cb -= cBytes; \
+ } while(0)
+
+ TRACE("%p,%p,%d\n", iface, psps, cb);
+
+ /*FIXME: Should we clear existing properties in the store? */
+
+ if (cb == 0) /* special case: empty storage */
+ return S_OK;
+
+ if (!psps)
+ return E_POINTER;
+
+ EnterCriticalSection(&This->lock);
+
+ for (;;)
+ {
+ DWORD storageSize;
+ DWORD version;
+ CLSID fmtid;
+
+ REQUIRE_SPACE(4);
+
+ /* Read size field */
+ read_dword(buffer, &storageSize);
+
+ if (storageSize == 0) /* final element */
+ {
+ MOVE(4);
+ break;
+ }
+
+ REQUIRE_SPACE(24);
+ read_dword(buffer + 4, &version);
+ read_clsid(buffer + 8, &fmtid);
+
+ if (version != 0x53505331)
+ {
+ WARN("Found invalid version 0x%X\n", version);
+ hr = E_INVALIDARG;
+ goto out;
+ }
+
+ MOVE(24);
+
+ if (IsEqualGUID(&fmtid, &FMTID_NamedProperties))
+ {
+ for (;;)
+ {
+ DWORD propsize;
+ DWORD namesize;
+ PROPVARIANT prop;
+ WCHAR *name;
+
+ REQUIRE_SPACE(4);
+ read_dword(buffer, &propsize);
+
+ if (propsize == 0) /* final element */
+ {
+ MOVE(4);
+ break;
+ }
+
+ REQUIRE_SPACE(9);
+ read_dword(buffer + 4, &namesize);
+
+ if (namesize % 2 || namesize > (propsize - 9 - 4))
+ {
+ WARN("unicode string has invalid number of bytes\n");
+ hr = E_INVALIDARG;
+ goto out;
+ }
+
+ if (buffer[8])
+ WARN("reserved byte should be zero, but is 0x%X\n", (unsigned)buffer[4]);
+
+ REQUIRE_SPACE(propsize); /* includes header */
+ MOVE(9);
+
+ /* read the name */
+ name = CoTaskMemAlloc(namesize + sizeof(WCHAR));
+ if (!name)
+ {
+ WARN("not enough memory for reading name\n");
+ hr = E_OUTOFMEMORY;
+ goto out;
+ }
+
+ read_wstring(buffer, name, namesize/2);
+ name[namesize/2] = 0; /* just to be safe */
+ MOVE(namesize);
+
+ /* read the property */
+ hr = StgDeserializePropVariant(
+ (const SERIALIZEDPROPERTYVALUE *)buffer, propsize - 9, &prop);
+ if (FAILED(hr))
+ {
+ WARN("Couldn't deserialize property, hr=%08x\n", (unsigned)hr);
+ CoTaskMemFree(name);
+ goto out;
+ }
+
+ /* add it to the store */
+ hr = PropertyStore_SetNamedValue(&This->INamedPropertyStore_iface, name, &prop);
+ PropVariantClear(&prop);
+ CoTaskMemFree(name);
+
+ if (FAILED(hr))
+ {
+ WARN("Couldn't save deserialized property in store, hr=%08x\n", (unsigned)hr);
+ goto out;
+ }
+
+ MOVE(propsize - namesize - 9);
+ }
+ }
+ else
+ {
+ for (;;)
+ {
+ DWORD propsize;
+ DWORD pid;
+ PROPVARIANT prop;
+ PROPERTYKEY key;
+
+ REQUIRE_SPACE(4);
+ read_dword(buffer, &propsize);
+
+ if (propsize == 0) /* final element */
+ {
+ MOVE(4);
+ break;
+ }
+
+ REQUIRE_SPACE(9);
+ read_dword(buffer + 4, &pid);
+
+ if (buffer[8])
+ WARN("reserved byte should be zero, but is 0x%X\n", (unsigned)buffer[4]);
+
+ REQUIRE_SPACE(propsize); /* includes header */
+ MOVE(9);
+
+ /* read the property */
+ hr = StgDeserializePropVariant(
+ (const SERIALIZEDPROPERTYVALUE *)buffer, propsize - 9, &prop);
+ if (FAILED(hr))
+ {
+ WARN("Couldn't deserialize property, hr=%08x\n", (unsigned)hr);
+ goto out;
+ }
+
+ /* add it to the store */
+ key.fmtid = fmtid;
+ key.pid = pid;
+
+ hr = PropertyStore_SetValue(&This->IPropertyStoreCache_iface, &key, &prop);
+ PropVariantClear(&prop);
+
+ if (FAILED(hr))
+ {
+ WARN("Couldn't save deserialized property in store, hr=%08x\n", (unsigned)hr);
+ goto out;
+ }
+
+ MOVE(propsize - 9);
+ }
+ }
+ }
+
+#undef REQUIRE_SPACE
+#undef MOVE
+
+out:
+ LeaveCriticalSection(&This->lock);
+
+ return hr;
+}
+
static const IPropertyStoreCacheVtbl PropertyStore_IPropertyStoreCache_Vtbl = {
PropertyStore_IPropertyStoreCache_QueryInterface,
PropertyStore_IPropertyStoreCache_AddRef,
@@ -683,6 +1296,17 @@ static const IPropertyStoreCacheVtbl PropertyStore_IPropertyStoreCache_Vtbl = {
PropertyStore_SetValueAndState
};
+static const IPersistSerializedPropStorage2Vtbl PropertyStore_IPersistSerializedPropStorage_Vtbl = {
+ PropertyStore_IPersistSerializedPropStorage_QueryInterface,
+ PropertyStore_IPersistSerializedPropStorage_AddRef,
+ PropertyStore_IPersistSerializedPropStorage_Release,
+ PropertyStore_SetFlags,
+ PropertyStore_SetPropertyStorage,
+ PropertyStore_GetPropertyStorage,
+ PropertyStore_GetPropertyStorageSize,
+ PropertyStore_GetPropertyStorageBuffer
+};
+
static const INamedPropertyStoreVtbl PropertyStore_INamedPropertyStore_Vtbl = {
PropertyStore_INamedPropertyStore_QueryInterface,
PropertyStore_INamedPropertyStore_AddRef,
@@ -708,6 +1332,7 @@ HRESULT PropertyStore_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv
if (!This) return E_OUTOFMEMORY;
This->IPropertyStoreCache_iface.lpVtbl = &PropertyStore_IPropertyStoreCache_Vtbl;
+ This->IPersistSerializedPropStorage2_iface.lpVtbl = &PropertyStore_IPersistSerializedPropStorage_Vtbl;
This->INamedPropertyStore_iface.lpVtbl = &PropertyStore_INamedPropertyStore_Vtbl;
This->ref = 1;
InitializeCriticalSection(&This->lock);
diff --git a/dlls/propsys/propsys_classes.idl b/dlls/propsys/propsys_classes.idl
index cdbbb77..b4fd550 100644
--- a/dlls/propsys/propsys_classes.idl
+++ b/dlls/propsys/propsys_classes.idl
@@ -28,4 +28,5 @@
coclass InMemoryPropertyStore {
interface IPropertyStoreCache;
interface INamedPropertyStore;
+ interface IPersistSerializedPropStorage2;
}
diff --git a/dlls/propsys/tests/propstore.c b/dlls/propsys/tests/propstore.c
index 67ab80a..a91e456 100644
--- a/dlls/propsys/tests/propstore.c
+++ b/dlls/propsys/tests/propstore.c
@@ -269,19 +269,121 @@ static void test_namedpropertystore(void)
static void test_persistserialized(void)
{
- IPropertyStore *propstore;
- IPersistSerializedPropStorage *serialized;
+ IPropertyStore *propstore = NULL;
+ INamedPropertyStore *named = NULL;
+ IPersistSerializedPropStorage *serialized = NULL;
HRESULT hr;
SERIALIZEDPROPSTORAGE *result;
DWORD result_size;
+ WCHAR hello[] = { 'H', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'l', 'd', 0 };
+ WCHAR wcsJava[] = { 'J', 'a', 'v', 'a', 0 };
+
+ /* The spec doesn't impose any order.
+ * Since we have two properties, there are two valid serializations */
+ BYTE expected_result1[] = {
+ /* WTF: Contrary to what the spec says, the store size field is missing! */
+
+ 0x45, 0x00, 0x00, 0x00, /* 1st Storage size (69 bytes) */
+
+ 0x31, 0x53, 0x50, 0x53, /* Version (DWORD) 0x53505331 */
+
+ /* fmtid GUID 0x7b317433, 0xdfa3, 0x4c44, 0xad, 0x3e, 0x2f, 0x80, 0x4b, 0x90, 0xdb, 0xf4 */
+ 0x33, 0x74, 0x31, 0x7b, 0xa3, 0xdf, 0x44, 0x4c,
+ 0xad, 0x3e, 0x2f, 0x80, 0x4b, 0x90, 0xdb, 0xf4,
+
+ 0x29, 0x00, 0x00, 0x00, /* Value size */
+ 0x02, 0x00, 0x00, 0x00, /* PID */
+ 0x00, /* random reserved byte to make everything misaligned */
+
+ 0x1f, 0x00, 0x00, 0x00, /* Variant Type */
+ 0x0b, 0x00, 0x00, 0x00, /* String length */
+
+ /* UTF-16 string: "HelloWorld", padded to 4 bytes */
+ 0x48, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x6c, 0x00,
+ 0x6f, 0x00, 0x57, 0x00, 0x6f, 0x00, 0x72, 0x00,
+ 0x6c, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ 0x00, 0x00, 0x00, 0x00, /* Final value with size 0 */
+
+ 0x37, 0x00, 0x00, 0x00, /* 2nd Storage size */
+ 0x31, 0x53, 0x50, 0x53, /* Version */
+
+ /* fmtid named properties */
+ 0x05, 0xd5, 0xcd, 0xd5, 0x9c, 0x2e, 0x1b, 0x10,
+ 0x93, 0x97, 0x08, 0x00, 0x2b, 0x2c, 0xf9, 0xae,
+
+ 0x1b, 0x00, 0x00, 0x00, /* Value size */
+ 0x0a, 0x00, 0x00, 0x00, /* Name size */
+ 0x00, /* random reserved byte to ensure misalignment */
+
+ /* UTF-16 string "Java" */
+ 0x4a, 0x00, 0x61, 0x00, 0x76, 0x00, 0x61, 0x00, 0x00, 0x00,
+
+ 0x13, 0x00, 0x00, 0x00, /* Variant Type */
+ 0xbe, 0xba, 0xfe, 0xca, /* Variant Value */
+
+ 0x00, 0x00, 0x00, 0x00, /* Final value with size 0 */
+ 0x00, 0x00, 0x00, 0x00 /* Final storage with size 0 */
+ };
+ BYTE expected_result2[] = {
+ /* WTF: Contrary to what the spec says, the store size field is missing! */
+
+ 0x37, 0x00, 0x00, 0x00, /* 2nd Storage size */
+ 0x31, 0x53, 0x50, 0x53, /* Version */
+
+ /* fmtid named properties */
+ 0x05, 0xd5, 0xcd, 0xd5, 0x9c, 0x2e, 0x1b, 0x10,
+ 0x93, 0x97, 0x08, 0x00, 0x2b, 0x2c, 0xf9, 0xae,
+
+ 0x1b, 0x00, 0x00, 0x00, /* Value size */
+ 0x0a, 0x00, 0x00, 0x00, /* Name size */
+ 0x00, /* random reserved byte to ensure misalignment */
+
+ /* UTF-16 string "Java" */
+ 0x4a, 0x00, 0x61, 0x00, 0x76, 0x00, 0x61, 0x00, 0x00, 0x00,
+
+ 0x13, 0x00, 0x00, 0x00, /* Variant Type */
+ 0xbe, 0xba, 0xfe, 0xca, /* Variant Value */
+
+ 0x00, 0x00, 0x00, 0x00, /* Final value with size 0 */
+
+ 0x45, 0x00, 0x00, 0x00, /* 1st Storage size (69 bytes) */
+
+ 0x31, 0x53, 0x50, 0x53, /* Version (DWORD) 0x53505331 */
+
+ /* fmtid GUID 0x7b317433, 0xdfa3, 0x4c44, 0xad, 0x3e, 0x2f, 0x80, 0x4b, 0x90, 0xdb, 0xf4 */
+ 0x33, 0x74, 0x31, 0x7b, 0xa3, 0xdf, 0x44, 0x4c,
+ 0xad, 0x3e, 0x2f, 0x80, 0x4b, 0x90, 0xdb, 0xf4,
+
+ 0x29, 0x00, 0x00, 0x00, /* Value size */
+ 0x02, 0x00, 0x00, 0x00, /* PID */
+ 0x00, /* random reserved byte to make everything misaligned */
+
+ 0x1f, 0x00, 0x00, 0x00, /* Variant Type */
+ 0x0b, 0x00, 0x00, 0x00, /* String length */
+
+ /* UTF-16 string: "HelloWorld", padded to 4 bytes */
+ 0x48, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x6c, 0x00,
+ 0x6f, 0x00, 0x57, 0x00, 0x6f, 0x00, 0x72, 0x00,
+ 0x6c, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ 0x00, 0x00, 0x00, 0x00, /* Final value with size 0 */
+
+ 0x00, 0x00, 0x00, 0x00 /* Final storage with size 0 */
+ };
+
hr = CoCreateInstance(&CLSID_InMemoryPropertyStore, NULL, CLSCTX_INPROC_SERVER,
&IID_IPropertyStore, (void**)&propstore);
ok(hr == S_OK, "CoCreateInstance failed, hr=%x\n", hr);
+ hr = IPropertyStore_QueryInterface(propstore, &IID_INamedPropertyStore,
+ (void**)&named);
+ ok(hr == S_OK, "QueryInterface failed, hr=%x\n", hr);
+
hr = IPropertyStore_QueryInterface(propstore, &IID_IPersistSerializedPropStorage,
(void**)&serialized);
- todo_wine ok(hr == S_OK, "QueryInterface failed, hr=%x\n", hr);
+ ok(hr == S_OK, "QueryInterface failed, hr=%x\n", hr);
if (FAILED(hr))
{
@@ -311,11 +413,119 @@ static void test_persistserialized(void)
hr = IPersistSerializedPropStorage_SetPropertyStorage(serialized, NULL, 0);
ok(hr == S_OK, "SetPropertyStorage failed, hr=%x\n", hr);
+ hr = IPersistSerializedPropStorage_SetPropertyStorage(serialized, (void*)0xdeadcafe, 0);
+ ok(hr == S_OK, "SetPropertyStorage failed, hr=%x\n", hr);
+
hr = IPropertyStore_GetCount(propstore, &result_size);
ok(hr == S_OK, "GetCount failed, hr=%x\n", hr);
ok(result_size == 0, "expecting 0, got %d\n", result_size);
+ {
+ PROPVARIANT vHello;
+ PROPVARIANT vUlong;
+ PROPERTYKEY kHello = { PKEY_WineTest, PID_FIRST_USABLE };
+
+ vHello.vt = VT_LPWSTR;
+ vHello.u.pwszVal = hello;
+ vUlong.vt = VT_UI4;
+ vUlong.u.ulVal = 0xCAFEBABE;
+
+ hr = INamedPropertyStore_SetNamedValue(named, wcsJava, &vUlong);
+ ok(hr == S_OK, "SetValue failed, hr=%08x\n", hr);
+
+ hr = IPropertyStore_SetValue(propstore, &kHello, &vHello);
+ ok(hr == S_OK, "SetValue failed, hr=%08x\n", hr);
+ }
+
+ hr = IPersistSerializedPropStorage_GetPropertyStorage(serialized, &result, &result_size);
+ ok(hr == S_OK, "GetPropertyStorage failed, hr=%x\n", hr);
+ ok(result != NULL, "GetPropertyStorage returned NULL where it shouldn't\n");
+
+ /* compare the result */
+ if (result)
+ {
+ BOOL same;
+
+ same = result_size == sizeof(expected_result1)
+ && (!memcmp(expected_result1, result, result_size)
+ || !memcmp(expected_result2, result, result_size));
+ ok(same, "GetPropertyStorage returned unexpected result of size %u (%u expected)\n",
+ result_size, (unsigned)sizeof(expected_result1));
+
+ if (!same)
+ {
+ size_t i;
+
+ printf("Got result: {");
+ for (i = 0; i < result_size; ++i)
+ {
+ printf("0x%02x, ", (unsigned)((BYTE*)result)[i]);
+ }
+ printf("}\n");
+ }
+ }
+
+ /* Load it again into a new property store */
+ if (result)
+ {
+ IPropertyStore *propstore2 = NULL;
+ IPersistSerializedPropStorage *serialized2 = NULL;
+ INamedPropertyStore *named2 = NULL;
+ PROPVARIANT vHello;
+ PROPVARIANT vJava;
+ PROPERTYKEY key;
+
+ hr = CoCreateInstance(&CLSID_InMemoryPropertyStore, NULL, CLSCTX_INPROC_SERVER,
+ &IID_IPropertyStore, (void**)&propstore2);
+ ok(hr == S_OK, "CoCreateInstance failed, hr=%x\n", hr);
+
+ hr = IPropertyStore_QueryInterface(propstore2, &IID_IPersistSerializedPropStorage,
+ (void**)&serialized2);
+ ok(hr == S_OK, "QueryInterface failed, hr=%x\n", hr);
+
+ hr = IPropertyStore_QueryInterface(propstore2, &IID_INamedPropertyStore,
+ (void**)&named2);
+ ok(hr == S_OK, "QueryInterface failed, hr=%x\n", hr);
+
+ hr = IPersistSerializedPropStorage_SetPropertyStorage(serialized2, result, result_size);
+ ok(hr == S_OK, "SetPropertyStorage failed, hr=%x\n", hr);
+
+ hr = IPropertyStore_GetCount(propstore2, &result_size);
+ ok(hr == S_OK, "GetCount failed, hr=%x\n", hr);
+ ok(result_size == 1, "expecting 1, got %d\n", result_size);
+
+ hr = INamedPropertyStore_GetNameCount(named2, &result_size);
+ ok(hr == S_OK, "GetNameCount failed, hr=%x\n", hr);
+ ok(result_size == 1, "expecting 1, got %d\n", result_size);
+
+ key.fmtid = PKEY_WineTest;
+ key.pid = PID_FIRST_USABLE;
+
+ hr = IPropertyStore_GetValue(propstore2, &key, &vHello);
+ ok(hr == S_OK, "GetValue failed, hr=%x\n", hr);
+
+ ok(vHello.vt == VT_LPWSTR, "Variant has wrong type %d\n", vHello.vt);
+ ok(lstrcmpW(vHello.u.pwszVal, hello) == 0,
+ "Variant has wrong value %s\n", wine_dbgstr_w(vHello.u.pwszVal));
+
+ hr = INamedPropertyStore_GetNamedValue(named2, wcsJava, &vJava);
+ ok(hr == S_OK, "GetNamedValue failed, hr=%x\n", hr);
+
+ ok(vJava.vt == VT_UI4, "Variant has wrong type %d\n", vJava.vt);
+ ok(vJava.u.ulVal == 0xCAFEBABE, "Variant has wrong value %X\n", vJava.u.ulVal);
+
+ PropVariantClear(&vHello);
+ PropVariantClear(&vJava);
+
+ IPropertyStore_Release(propstore2);
+ INamedPropertyStore_Release(named2);
+ IPersistSerializedPropStorage_Release(serialized2);
+
+ CoTaskMemFree(result);
+ }
+
IPropertyStore_Release(propstore);
+ INamedPropertyStore_Release(named);
IPersistSerializedPropStorage_Release(serialized);
}
--
2.4.3
More information about the wine-devel
mailing list