[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