The in-memory property store now supports INamedPropertyStore. --- dlls/propsys/propstore.c | 275 ++++++++++++++++++++++++++++++++++++--- dlls/propsys/propsys_classes.idl | 5 +- dlls/propsys/tests/propstore.c | 72 ++++++++++ 3 files changed, 336 insertions(+), 16 deletions(-)
diff --git a/dlls/propsys/propstore.c b/dlls/propsys/propstore.c index 9c848fc..3f028e9 100644 --- a/dlls/propsys/propstore.c +++ b/dlls/propsys/propstore.c @@ -28,6 +28,7 @@ #include "objbase.h" #include "rpcproxy.h" #include "propsys.h" +#include "propvarutil.h" #include "wine/debug.h" #include "wine/unicode.h" #include "wine/list.h" @@ -53,11 +54,20 @@ typedef struct { DWORD count; } propstore_format;
+/* FIXME: We should really do something clever, like using a hashtable */ +typedef struct { + struct list entry; + PROPVARIANT propvar; + WCHAR name[1]; +} propstore_named_value; + typedef struct { IPropertyStoreCache IPropertyStoreCache_iface; + INamedPropertyStore INamedPropertyStore_iface; LONG ref; CRITICAL_SECTION lock; struct list formats; /* list of struct propstore_format */ + struct list named; /* list of struct propstore_named_value */ } PropertyStore;
static inline PropertyStore *impl_from_IPropertyStoreCache(IPropertyStoreCache *iface) @@ -65,12 +75,13 @@ static inline PropertyStore *impl_from_IPropertyStoreCache(IPropertyStoreCache * return CONTAINING_RECORD(iface, PropertyStore, IPropertyStoreCache_iface); }
-static HRESULT WINAPI PropertyStore_QueryInterface(IPropertyStoreCache *iface, REFIID iid, - void **ppv) +static inline PropertyStore *impl_from_INamedPropertyStore(INamedPropertyStore *iface) { - PropertyStore *This = impl_from_IPropertyStoreCache(iface); - TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); + return CONTAINING_RECORD(iface, PropertyStore, INamedPropertyStore_iface); +}
+static HRESULT query_interface(PropertyStore *This, REFIID iid, void **ppv) +{ if (!ppv) return E_INVALIDARG;
if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IPropertyStore, iid) || @@ -78,6 +89,10 @@ static HRESULT WINAPI PropertyStore_QueryInterface(IPropertyStoreCache *iface, R { *ppv = &This->IPropertyStoreCache_iface; } + else if (IsEqualIID(&IID_INamedPropertyStore, iid)) + { + *ppv = &This->INamedPropertyStore_iface; + } else { FIXME("No interface for %s\n", debugstr_guid(iid)); @@ -89,10 +104,45 @@ static HRESULT WINAPI PropertyStore_QueryInterface(IPropertyStoreCache *iface, R return S_OK; }
-static ULONG WINAPI PropertyStore_AddRef(IPropertyStoreCache *iface) +static HRESULT WINAPI PropertyStore_IPropertyStoreCache_QueryInterface( + IPropertyStoreCache *iface, REFIID iid, void **ppv) +{ + PropertyStore *This = impl_from_IPropertyStoreCache(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) +{ + PropertyStore *This = impl_from_INamedPropertyStore(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); +} + +static ULONG WINAPI PropertyStore_IPropertyStoreCache_AddRef(IPropertyStoreCache *iface) { PropertyStore *This = impl_from_IPropertyStoreCache(iface); - ULONG ref = InterlockedIncrement(&This->ref); + 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); + ULONG ref = add_ref(This);
TRACE("(%p) refcount=%u\n", iface, ref);
@@ -110,26 +160,53 @@ static void destroy_format(propstore_format *format) HeapFree(GetProcessHeap(), 0, format); }
-static ULONG WINAPI PropertyStore_Release(IPropertyStoreCache *iface) +static void destroy_named(propstore_named_value *value) { - PropertyStore *This = impl_from_IPropertyStoreCache(iface); - ULONG ref = InterlockedDecrement(&This->ref); + PropVariantClear(&value->propvar); + HeapFree(GetProcessHeap(), 0, value); +}
- TRACE("(%p) refcount=%u\n", iface, ref); +static ULONG WINAPI release(PropertyStore *This) +{ + ULONG ref = InterlockedDecrement(&This->ref);
if (ref == 0) { propstore_format *cursor, *cursor2; + propstore_named_value *cnamed, *cnamed2; + This->lock.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&This->lock); LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &This->formats, propstore_format, entry) destroy_format(cursor); + LIST_FOR_EACH_ENTRY_SAFE(cnamed, cnamed2, &This->named, propstore_named_value, entry) + destroy_named(cnamed); HeapFree(GetProcessHeap(), 0, This); }
return ref; }
+static ULONG WINAPI PropertyStore_IPropertyStoreCache_Release(IPropertyStoreCache *iface) +{ + PropertyStore *This = impl_from_IPropertyStoreCache(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); + ULONG ref = release(This); + + TRACE("(%p) refcount=%u\n", iface, ref); + + return ref; +} + static HRESULT WINAPI PropertyStore_GetCount(IPropertyStoreCache *iface, DWORD *cProps) { @@ -153,6 +230,29 @@ static HRESULT WINAPI PropertyStore_GetCount(IPropertyStoreCache *iface, return S_OK; }
+static HRESULT WINAPI PropertyStore_GetNameCount(INamedPropertyStore *iface, + DWORD *cProps) +{ + PropertyStore *This = impl_from_INamedPropertyStore(iface); + propstore_named_value *value; + + TRACE("%p,%p\n", iface, cProps); + + if (!cProps) + return E_POINTER; + + *cProps = 0; + + EnterCriticalSection(&This->lock); + + LIST_FOR_EACH_ENTRY(value, &This->named, propstore_named_value, entry) + *cProps += 1; + + LeaveCriticalSection(&This->lock); + + return S_OK; +} + static HRESULT WINAPI PropertyStore_GetAt(IPropertyStoreCache *iface, DWORD iProp, PROPERTYKEY *pkey) { @@ -203,6 +303,47 @@ static HRESULT WINAPI PropertyStore_GetAt(IPropertyStoreCache *iface, return hr; }
+static HRESULT WINAPI PropertyStore_GetNameAt(INamedPropertyStore *iface, + DWORD iProp, BSTR *pname) +{ + PropertyStore *This = impl_from_INamedPropertyStore(iface); + propstore_named_value *cursor, *value = NULL; + HRESULT hr; + + TRACE("%p,%d,%p\n", iface, iProp, pname); + + if (!pname) + return E_POINTER; + + EnterCriticalSection(&This->lock); + + LIST_FOR_EACH_ENTRY(cursor, &This->named, propstore_named_value, entry) + { + if (iProp == 0) + { + value = cursor; + break; + } + + iProp -= 1; + } + + if (value) + { + *pname = SysAllocString(value->name); + if (*pname) + hr = S_OK; + else + hr = E_OUTOFMEMORY; + } + else + hr = E_INVALIDARG; + + LeaveCriticalSection(&This->lock); + + return hr; +} + static HRESULT PropertyStore_LookupValue(PropertyStore *This, REFPROPERTYKEY key, BOOL insert, propstore_value **result) { @@ -297,6 +438,42 @@ static HRESULT WINAPI PropertyStore_GetValue(IPropertyStoreCache *iface, return hr; }
+static HRESULT WINAPI PropertyStore_GetNamedValue(INamedPropertyStore *iface, + const WCHAR *name, PROPVARIANT *pv) +{ + PropertyStore *This = impl_from_INamedPropertyStore(iface); + propstore_named_value *cursor, *value = NULL; + + TRACE("%p,%p,%p\n", iface, name, pv); + + if (!name || !pv) + return E_POINTER; + + EnterCriticalSection(&This->lock); + + LIST_FOR_EACH_ENTRY(cursor, &This->named, propstore_named_value, entry) + { + if (0 == lstrcmpW(cursor->name, name)) + { + value = cursor; + break; + } + } + + if (value) + { + PropVariantCopy(pv, &value->propvar); + } + else + { + PropVariantInit(pv); + } + + LeaveCriticalSection(&This->lock); + + return S_OK; +} + static HRESULT WINAPI PropertyStore_SetValue(IPropertyStoreCache *iface, REFPROPERTYKEY key, REFPROPVARIANT propvar) { @@ -325,6 +502,62 @@ static HRESULT WINAPI PropertyStore_SetValue(IPropertyStoreCache *iface, return hr; }
+static HRESULT WINAPI PropertyStore_SetNamedValue(INamedPropertyStore *iface, + const WCHAR *name, REFPROPVARIANT propvar) +{ + PropertyStore *This = impl_from_INamedPropertyStore(iface); + propstore_named_value *cursor, *value = NULL; + HRESULT hr = S_OK; + PROPVARIANT temp; + + TRACE("%p,%p,%p\n", iface, name, propvar); + + hr = PropVariantCopy(&temp, propvar); + if (FAILED(hr)) + return hr; + + EnterCriticalSection(&This->lock); + + LIST_FOR_EACH_ENTRY(cursor, &This->named, propstore_named_value, entry) + { + if (0 == lstrcmpW(name, cursor->name)) + { + value = cursor; + break; + } + } + + if (value) + { + /* replace old value */ + PropVariantClear(&value->propvar); + value->propvar = temp; + } + else + { + /* add new value */ + ULONG namesize = (lstrlenW(name) + 1) * sizeof(WCHAR); + + value = HeapAlloc(GetProcessHeap(), 0, sizeof(propstore_named_value) + namesize); + if (value) + { + value->propvar = temp; + memcpy(value->name, name, namesize); + + list_add_head(&This->named, &value->entry); + } + else + { + PropVariantClear(&temp); + hr = E_OUTOFMEMORY; + } + } + + LeaveCriticalSection(&This->lock); + + return hr; +} + static HRESULT WINAPI PropertyStore_Commit(IPropertyStoreCache *iface) { FIXME("%p: stub\n", iface); @@ -435,10 +668,10 @@ static HRESULT WINAPI PropertyStore_SetValueAndState(IPropertyStoreCache *iface, return hr; }
-static const IPropertyStoreCacheVtbl PropertyStore_Vtbl = { - PropertyStore_QueryInterface, - PropertyStore_AddRef, - PropertyStore_Release, +static const IPropertyStoreCacheVtbl PropertyStore_IPropertyStoreCache_Vtbl = { + PropertyStore_IPropertyStoreCache_QueryInterface, + PropertyStore_IPropertyStoreCache_AddRef, + PropertyStore_IPropertyStoreCache_Release, PropertyStore_GetCount, PropertyStore_GetAt, PropertyStore_GetValue, @@ -450,6 +683,16 @@ static const IPropertyStoreCacheVtbl PropertyStore_Vtbl = { PropertyStore_SetValueAndState };
+static const INamedPropertyStoreVtbl PropertyStore_INamedPropertyStore_Vtbl = { + PropertyStore_INamedPropertyStore_QueryInterface, + PropertyStore_INamedPropertyStore_AddRef, + PropertyStore_INamedPropertyStore_Release, + PropertyStore_GetNamedValue, + PropertyStore_SetNamedValue, + PropertyStore_GetNameCount, + PropertyStore_GetNameAt +}; + HRESULT PropertyStore_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv) { PropertyStore *This; @@ -464,11 +707,13 @@ HRESULT PropertyStore_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv This = HeapAlloc(GetProcessHeap(), 0, sizeof(PropertyStore)); if (!This) return E_OUTOFMEMORY;
- This->IPropertyStoreCache_iface.lpVtbl = &PropertyStore_Vtbl; + This->IPropertyStoreCache_iface.lpVtbl = &PropertyStore_IPropertyStoreCache_Vtbl; + This->INamedPropertyStore_iface.lpVtbl = &PropertyStore_INamedPropertyStore_Vtbl; This->ref = 1; InitializeCriticalSection(&This->lock); This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": PropertyStore.lock"); list_init(&This->formats); + list_init(&This->named);
ret = IPropertyStoreCache_QueryInterface(&This->IPropertyStoreCache_iface, iid, ppv); IPropertyStoreCache_Release(&This->IPropertyStoreCache_iface); diff --git a/dlls/propsys/propsys_classes.idl b/dlls/propsys/propsys_classes.idl index 02555a3..cdbbb77 100644 --- a/dlls/propsys/propsys_classes.idl +++ b/dlls/propsys/propsys_classes.idl @@ -25,4 +25,7 @@ threading(both), uuid(9a02e012-6303-4e1e-b9a1-630f802592c5) ] -coclass InMemoryPropertyStore { interface IPropertyStoreCache; } +coclass InMemoryPropertyStore { + interface IPropertyStoreCache; + interface INamedPropertyStore; +} diff --git a/dlls/propsys/tests/propstore.c b/dlls/propsys/tests/propstore.c index 01500dd..67ab80a 100644 --- a/dlls/propsys/tests/propstore.c +++ b/dlls/propsys/tests/propstore.c @@ -2,6 +2,7 @@ * Unit tests for IPropertyStore and related interfaces * * Copyright 2012 Vincent Povirk + * 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 @@ -30,6 +31,7 @@ #include "objbase.h" #include "propsys.h" #include "wine/test.h" +#include "propvarutil.h"
#include "initguid.h"
@@ -196,6 +198,75 @@ static void test_inmemorystore(void) IPropertyStoreCache_Release(propcache); }
+static void test_namedpropertystore(void) +{ + IPropertyStore *propstore; + INamedPropertyStore *named; + HRESULT hr; + PROPVARIANT propvar; + const WCHAR wcsJava[] = { 'J', 'a', 'v', 'a', 0 }; + const WCHAR wcsBlub[] = { 'B', 'l', 'u', 'b', 0 }; + DWORD count; + BSTR name; + + 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); + + if (FAILED(hr)) + { + skip("IPersistSerializedPropStorage not supported\n"); + return; + } + + InitPropVariantFromUInt32(0xcafebabe, &propvar); + + hr = INamedPropertyStore_SetNamedValue(named, wcsJava, &propvar); + ok(hr == S_OK, "SetNamedValue failed, hr=%x\n", hr); + + hr = INamedPropertyStore_GetNameCount(named, &count); + ok(hr == S_OK, "GetNameCount failed, hr=%x\n", hr); + ok(count == 1, "Expected 1 element, got %u\n", count); + + hr = INamedPropertyStore_GetNameAt(named, 0, &name); + ok(hr == S_OK, "GetNameAt failed, hr=%x\n", hr); + ok(0 == lstrcmpW(name, wcsJava), "Unexpected name %s\n", wine_dbgstr_w(name)); + + SysFreeString(name); + + PropVariantInit(&propvar); + hr = INamedPropertyStore_GetNamedValue(named, wcsJava, &propvar); + ok(hr == S_OK, "GetNamedValue failed, hr=%x\n", hr); + ok(propvar.vt == VT_UI4, "Unexpected vt %d\n", propvar.vt); + ok(U(propvar).ulVal == 0xcafebabe, "Unexpected value %x\n", U(propvar).ulVal); + + InitPropVariantFromInt16(2523, &propvar); + hr = INamedPropertyStore_SetNamedValue(named, wcsBlub, &propvar); + ok(hr == S_OK, "SetNamedValue failed, hr=%x\n", hr); + + hr = INamedPropertyStore_GetNameCount(named, &count); + ok(hr == S_OK, "GetNameCount failed, hr=%x\n", hr); + ok(count == 2, "Expected 2 elements, got %u\n", count); + + InitPropVariantFromUInt32(0xdeadbeef, &propvar); + hr = INamedPropertyStore_SetNamedValue(named, wcsJava, &propvar); + ok(hr == S_OK, "SetNameValue failed, hr=%x\n", hr); + + hr = INamedPropertyStore_GetNameCount(named, &count); + ok(hr == S_OK, "GetNameCount failed, hr=%x\n", hr); + ok(count == 2, "Expected 2 elements, got %u\n", count); + + PropVariantInit(&propvar); + hr = INamedPropertyStore_GetNamedValue(named, wcsJava, &propvar); + ok(hr == S_OK, "GetNamedValue failed, hr=%x\n", hr); + ok(propvar.vt == VT_UI4, "Unexpected vt %d\n", propvar.vt); + ok(U(propvar).ulVal == 0xdeadbeef, "Unexpected value %x\n", U(propvar).ulVal); +} + static void test_persistserialized(void) { IPropertyStore *propstore; @@ -253,6 +324,7 @@ START_TEST(propstore) CoInitialize(NULL);
test_inmemorystore(); + test_namedpropertystore(); test_persistserialized();
CoUninitialize();