[PATCH v2 08/15] propsys: Implement IPersistStream on the in-memory property store

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


---
 dlls/propsys/propstore.c         | 162 +++++++++++++++++++++++++++++++++++++++
 dlls/propsys/propsys_classes.idl |   1 +
 dlls/propsys/tests/Makefile.in   |   2 +-
 dlls/propsys/tests/propstore.c   | 115 +++++++++++++++++++++++++++
 dlls/propsys/tests/propsys.c     |   3 +-
 5 files changed, 280 insertions(+), 3 deletions(-)

diff --git a/dlls/propsys/propstore.c b/dlls/propsys/propstore.c
index 1f5f58f..87b201f 100644
--- a/dlls/propsys/propstore.c
+++ b/dlls/propsys/propstore.c
@@ -67,6 +67,7 @@ typedef struct {
     IPropertyStoreCache IPropertyStoreCache_iface;
     IPersistSerializedPropStorage2 IPersistSerializedPropStorage2_iface;
     INamedPropertyStore INamedPropertyStore_iface;
+    IPersistStream IPersistStream_iface;
     LONG ref;
     CRITICAL_SECTION lock;
     struct list formats; /* list of struct propstore_format */
@@ -88,6 +89,11 @@ static inline PropertyStore *impl_from_INamedPropertyStore(INamedPropertyStore *
     return CONTAINING_RECORD(iface, PropertyStore, INamedPropertyStore_iface);
 }
 
+static inline PropertyStore *impl_from_IPersistStream(IPersistStream *iface)
+{
+    return CONTAINING_RECORD(iface, PropertyStore, IPersistStream_iface);
+}
+
 static HRESULT query_interface(PropertyStore *This, REFIID iid, void **ppv)
 {
     if (!ppv) return E_INVALIDARG;
@@ -106,6 +112,10 @@ static HRESULT query_interface(PropertyStore *This, REFIID iid, void **ppv)
     {
         *ppv = &This->INamedPropertyStore_iface;
     }
+    else if (IsEqualIID(&IID_IPersistStream, iid) || IsEqualIID(&IID_IPersist, iid))
+    {
+        *ppv = &This->IPersistStream_iface;
+    }
     else
     {
         FIXME("No interface for %s\n", debugstr_guid(iid));
@@ -147,6 +157,16 @@ static HRESULT WINAPI PropertyStore_INamedPropertyStore_QueryInterface(
     return query_interface(This, iid, ppv);
 }
 
+static HRESULT WINAPI PropertyStore_IPersistStream_QueryInterface(
+    IPersistStream *iface, REFIID iid, void **ppv)
+{
+    PropertyStore *This = impl_from_IPersistStream(iface);
+
+    TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
+
+    return query_interface(This, iid, ppv);
+}
+
 static ULONG add_ref(PropertyStore *This)
 {
     return InterlockedIncrement(&This->ref);
@@ -182,6 +202,16 @@ static ULONG WINAPI PropertyStore_INamedPropertyStore_AddRef(INamedPropertyStore
     return ref;
 }
 
+static ULONG WINAPI PropertyStore_IPersistStream_AddRef(IPersistStream *iface)
+{
+    PropertyStore *This = impl_from_IPersistStream(iface);
+    ULONG ref = add_ref(This);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    return ref;
+}
+
 static void destroy_format(propstore_format *format)
 {
     propstore_value *cursor, *cursor2;
@@ -250,6 +280,16 @@ static ULONG WINAPI PropertyStore_INamedPropertyStore_Release(INamedPropertyStor
     return ref;
 }
 
+static ULONG WINAPI PropertyStore_IPersistStream_Release(IPersistStream *iface)
+{
+    PropertyStore *This = impl_from_IPersistStream(iface);
+    ULONG ref = release(This);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    return ref;
+}
+
 static HRESULT WINAPI PropertyStore_GetCount(IPropertyStoreCache *iface,
     DWORD *cProps)
 {
@@ -1281,6 +1321,116 @@ out:
     return hr;
 }
 
+static HRESULT WINAPI PropertyStore_GetClassID(IPersistStream *iface, CLSID *pclsid)
+{
+    TRACE("%p,%p\n", iface, pclsid);
+
+    if (!pclsid)
+        return E_POINTER;
+
+    *pclsid = CLSID_InMemoryPropertyStore;
+    return S_OK;
+}
+
+static HRESULT WINAPI PropertyStore_IsDirty(IPersistStream *iface)
+{
+    TRACE("%p: stub\n", iface);
+
+    return S_FALSE;
+}
+
+static HRESULT WINAPI PropertyStore_Load(IPersistStream *iface, IStream *stream)
+{
+    PropertyStore *This = impl_from_IPersistStream(iface);
+    HRESULT hr = S_OK;
+    DWORD count;
+    BYTE  sizeBuffer[4];
+    BYTE *buffer;
+
+    TRACE("%p,%p\n", iface, stream);
+
+    if (!stream)
+        return E_POINTER;
+
+    hr = IStream_Read(stream, sizeBuffer, 4, &count);
+    if (hr != S_OK)
+        return hr;
+
+    read_dword(sizeBuffer, &count);
+    buffer = CoTaskMemAlloc(count);
+    if (!buffer)
+        return E_OUTOFMEMORY;
+
+    hr = IStream_Read(stream, buffer, count, &count);
+    if (hr == S_OK)
+    {
+        hr = PropertyStore_SetPropertyStorage(&This->IPersistSerializedPropStorage2_iface,
+                                              (const SERIALIZEDPROPSTORAGE *)buffer,
+                                              count);
+    }
+
+    CoTaskMemFree(buffer);
+
+    return hr;
+}
+
+static HRESULT WINAPI PropertyStore_Save(IPersistStream *iface,
+                                         IStream *stream,
+                                         BOOL clearDirty)
+{
+    PropertyStore *This = impl_from_IPersistStream(iface);
+    HRESULT hr = S_OK;
+    DWORD count;
+    DWORD written;
+    BYTE  sizeBuffer[4];
+    SERIALIZEDPROPSTORAGE *buffer = NULL;
+
+    TRACE("%p %p %d\n", iface, stream, (int)clearDirty);
+
+    if (!stream)
+        return E_POINTER;
+
+    hr = PropertyStore_GetPropertyStorage(&This->IPersistSerializedPropStorage2_iface,
+                                          &buffer, &count);
+    if (FAILED(hr))
+        goto out;
+
+    write_dword(sizeBuffer, count);
+
+    hr = IStream_Write(stream, sizeBuffer, 4, &written);
+    if (hr != S_OK)
+        goto out;
+
+    hr = IStream_Write(stream, buffer, count, &written);
+
+out:
+    CoTaskMemFree(buffer);
+
+    return hr;
+}
+
+static HRESULT WINAPI PropertyStore_GetSizeMax(IPersistStream *iface, ULARGE_INTEGER *pcbSize)
+{
+    PropertyStore *This = impl_from_IPersistStream(iface);
+    HRESULT hr = S_OK;
+    DWORD   size;
+
+    TRACE("%p,%p", iface, pcbSize);
+
+    if (!pcbSize)
+        return E_POINTER;
+
+    hr = PropertyStore_GetPropertyStorageSize(&This->IPersistSerializedPropStorage2_iface,
+                                              &size);
+    if (SUCCEEDED(hr))
+    {
+        pcbSize->QuadPart = size;
+        pcbSize->QuadPart += 4;
+    }
+
+    return hr;
+}
+
 static const IPropertyStoreCacheVtbl PropertyStore_IPropertyStoreCache_Vtbl = {
     PropertyStore_IPropertyStoreCache_QueryInterface,
     PropertyStore_IPropertyStoreCache_AddRef,
@@ -1317,6 +1467,17 @@ static const INamedPropertyStoreVtbl PropertyStore_INamedPropertyStore_Vtbl = {
     PropertyStore_GetNameAt
 };
 
+static const IPersistStreamVtbl PropertyStore_IPersistStream_Vtbl = {
+    PropertyStore_IPersistStream_QueryInterface,
+    PropertyStore_IPersistStream_AddRef,
+    PropertyStore_IPersistStream_Release,
+    PropertyStore_GetClassID,
+    PropertyStore_IsDirty,
+    PropertyStore_Load,
+    PropertyStore_Save,
+    PropertyStore_GetSizeMax
+};
+
 HRESULT PropertyStore_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
 {
     PropertyStore *This;
@@ -1334,6 +1495,7 @@ HRESULT PropertyStore_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv
     This->IPropertyStoreCache_iface.lpVtbl = &PropertyStore_IPropertyStoreCache_Vtbl;
     This->IPersistSerializedPropStorage2_iface.lpVtbl = &PropertyStore_IPersistSerializedPropStorage_Vtbl;
     This->INamedPropertyStore_iface.lpVtbl = &PropertyStore_INamedPropertyStore_Vtbl;
+    This->IPersistStream_iface.lpVtbl = &PropertyStore_IPersistStream_Vtbl;
     This->ref = 1;
     InitializeCriticalSection(&This->lock);
     This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": PropertyStore.lock");
diff --git a/dlls/propsys/propsys_classes.idl b/dlls/propsys/propsys_classes.idl
index b4fd550..32eefa0 100644
--- a/dlls/propsys/propsys_classes.idl
+++ b/dlls/propsys/propsys_classes.idl
@@ -29,4 +29,5 @@ coclass InMemoryPropertyStore {
     interface IPropertyStoreCache;
     interface INamedPropertyStore;
     interface IPersistSerializedPropStorage2;
+    interface IPersistStream;
 }
diff --git a/dlls/propsys/tests/Makefile.in b/dlls/propsys/tests/Makefile.in
index d07d675..2913673 100644
--- a/dlls/propsys/tests/Makefile.in
+++ b/dlls/propsys/tests/Makefile.in
@@ -1,5 +1,5 @@
 TESTDLL   = propsys.dll
-IMPORTS   = propsys ole32 oleaut32
+IMPORTS   = propsys ole32 oleaut32 uuid
 
 C_SRCS = \
 	propstore.c \
diff --git a/dlls/propsys/tests/propstore.c b/dlls/propsys/tests/propstore.c
index a91e456..41c3fe8 100644
--- a/dlls/propsys/tests/propstore.c
+++ b/dlls/propsys/tests/propstore.c
@@ -272,9 +272,11 @@ static void test_persistserialized(void)
     IPropertyStore *propstore = NULL;
     INamedPropertyStore *named = NULL;
     IPersistSerializedPropStorage *serialized = NULL;
+    IPersistStream *persiststream = NULL;
     HRESULT hr;
     SERIALIZEDPROPSTORAGE *result;
     DWORD result_size;
+    HGLOBAL hSerialized;
 
     WCHAR hello[] = { 'H', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'l', 'd', 0 };
     WCHAR wcsJava[] = { 'J', 'a', 'v', 'a', 0 };
@@ -524,6 +526,119 @@ static void test_persistserialized(void)
         CoTaskMemFree(result);
     }
 
+    /* Serialize using IPersistStream */
+    hr = IPropertyStore_QueryInterface(propstore, &IID_IPersistStream, (void**)&persiststream);
+    ok(hr == S_OK, "QueryInterface(IPersistStream) failed, hr=%x\n", hr);
+
+    if (persiststream)
+    {
+        IStream *stream;
+        CLSID clazz;
+        BYTE *mem;
+        DWORD size;
+
+        hr = CreateStreamOnHGlobal(NULL, FALSE, &stream);
+        ok(hr == S_OK, "Failed to create stream on HGLOBAL, hr=%x\n", hr);
+
+        /* check the CLSID */
+        hr = IPersistStream_GetClassID(persiststream, &clazz);
+        ok(hr == S_OK, "Failed to retrieve CLSID, hr=%x\n", hr);
+        ok(IsEqualGUID(&clazz, &CLSID_InMemoryPropertyStore),
+           "Wrong CLSID %s returned\n", wine_dbgstr_guid(&clazz));
+
+        hr = IPersistStream_Save(persiststream, stream, TRUE);
+        ok(hr == S_OK, "IPersistStream::Save failed, hr=%x\n", hr);
+
+        /* The HGLOBAL should now contain one of the possible serializations,
+         * prefixed with the length of the following serialized storage. */
+        hr = GetHGlobalFromStream(stream, &hSerialized);
+        ok(hr == S_OK, "WTF: Can't retrieve HGLOBAL from stream, hr=%x\n", hr);
+
+        ok(GlobalSize(hSerialized)-4 == sizeof(expected_result1),
+           "Serialized result has invalid size %lu, expected %lu\n",
+           (unsigned long)GlobalSize(hSerialized), (unsigned long)sizeof(expected_result1) + 4);
+
+        mem = GlobalLock(hSerialized);
+        ok(mem != NULL, "WTF: Can't lock HGLOBAL");
+
+        size = mem[0] | (mem[1] << 8) | (mem[2] << 16) | (mem[3] << 24);
+
+        ok(size == sizeof(expected_result1),
+           "Serialized result encodes invalid size %lu, expected %lu\n",
+           (unsigned long)size, (unsigned long)sizeof(expected_result1));
+        ok(memcmp(mem+4, expected_result1, sizeof(expected_result1)) == 0
+            || memcmp(mem+4, expected_result2, sizeof(expected_result2)) == 0,
+           "Serialized result differs from expected result\n");
+        GlobalUnlock(hSerialized);
+
+        IPersistStream_Release(persiststream);
+        IStream_Release(stream);
+    }
+
+    /* Deserialize using IPersistStream */
+    if (hSerialized)
+    {
+        IStream *stream;
+        IPropertyStore *propstore2 = NULL;
+        IPersistStream *persiststream2 = NULL;
+        INamedPropertyStore *named2 = NULL;
+        PROPVARIANT vHello;
+        PROPVARIANT vJava;
+        PROPERTYKEY key;
+
+        hr = CreateStreamOnHGlobal(hSerialized, FALSE, &stream);
+        ok(hr == S_OK, "Failed to create stream on HGLOBAL, hr=%x\n", hr);
+
+        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_IPersistStream,
+            (void**)&persiststream2);
+        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 = IPersistStream_Load(persiststream2, stream);
+        ok(hr == S_OK, "IPersistStream::Load 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);
+        IPersistStream_Release(persiststream2);
+        IStream_Release(stream);
+
+        GlobalFree(hSerialized);
+    }
+
     IPropertyStore_Release(propstore);
     INamedPropertyStore_Release(named);
     IPersistSerializedPropStorage_Release(serialized);
diff --git a/dlls/propsys/tests/propsys.c b/dlls/propsys/tests/propsys.c
index 4044a38..1199b0e 100644
--- a/dlls/propsys/tests/propsys.c
+++ b/dlls/propsys/tests/propsys.c
@@ -29,12 +29,11 @@
 #include "windef.h"
 #include "winbase.h"
 #include "objbase.h"
-#include "initguid.h"
 #include "propsys.h"
 #include "propvarutil.h"
 #include "wine/test.h"
 
-DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
+#include "initguid.h"
 DEFINE_GUID(dummy_guid, 0xdeadbeef, 0xdead, 0xbeef, 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0xba, 0xbe);
 DEFINE_GUID(expect_guid, 0x12345678, 0x1234, 0x1234, 0x12, 0x34, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12);
 
-- 
2.4.3




More information about the wine-devel mailing list