[PATCH v2 06/15] propsys: Implement named properties on the in-memory property store
Jonas Kümmerlin
rgcjonas at gmail.com
Sat Jul 18 11:26:45 CDT 2015
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();
--
2.4.3
More information about the wine-devel
mailing list