[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