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