Nikolay Sivov : scrrun: Implement IEnumVARIANT support for dictionary.

Alexandre Julliard julliard at wine.codeweavers.com
Thu Mar 19 09:59:02 CDT 2015


Module: wine
Branch: master
Commit: ba482174299ff165c49e4d7d226f9799a2d8c5f3
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=ba482174299ff165c49e4d7d226f9799a2d8c5f3

Author: Nikolay Sivov <nsivov at codeweavers.com>
Date:   Wed Mar 18 15:11:32 2015 +0300

scrrun: Implement IEnumVARIANT support for dictionary.

---

 dlls/scrrun/dictionary.c       |  78 ++++++++++++++++++++++++---
 dlls/scrrun/tests/dictionary.c | 118 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 188 insertions(+), 8 deletions(-)

diff --git a/dlls/scrrun/dictionary.c b/dlls/scrrun/dictionary.c
index b74f2a7..5c770b6 100644
--- a/dlls/scrrun/dictionary.c
+++ b/dlls/scrrun/dictionary.c
@@ -71,6 +71,7 @@ typedef struct
     LONG count;
     struct list pairs;
     struct list buckets[BUCKET_COUNT];
+    struct list notifier;
 } dictionary;
 
 struct dictionary_enum {
@@ -78,6 +79,8 @@ struct dictionary_enum {
     LONG ref;
 
     dictionary *dict;
+    struct list *cur;
+    struct list notify;
 };
 
 static inline dictionary *impl_from_IDictionary(IDictionary *iface)
@@ -248,6 +251,7 @@ static ULONG WINAPI dict_enum_Release(IEnumVARIANT *iface)
 
     ref = InterlockedDecrement(&This->ref);
     if(ref == 0) {
+        list_remove(&This->notify);
         IDictionary_Release(&This->dict->IDictionary_iface);
         heap_free(This);
     }
@@ -258,29 +262,67 @@ static ULONG WINAPI dict_enum_Release(IEnumVARIANT *iface)
 static HRESULT WINAPI dict_enum_Next(IEnumVARIANT *iface, ULONG count, VARIANT *keys, ULONG *fetched)
 {
     struct dictionary_enum *This = impl_from_IEnumVARIANT(iface);
-    FIXME("(%p)->(%u %p %p): stub\n", This, count, keys, fetched);
-    return E_NOTIMPL;
+    struct keyitem_pair *pair;
+    ULONG i = 0;
+
+    TRACE("(%p)->(%u %p %p)\n", This, count, keys, fetched);
+
+    if (fetched)
+        *fetched = 0;
+
+    if (!count)
+        return S_OK;
+
+    while (This->cur && i < count) {
+        pair = LIST_ENTRY(This->cur, struct keyitem_pair, entry);
+        VariantCopy(&keys[i], &pair->key);
+        This->cur = list_next(&This->dict->pairs, This->cur);
+        i++;
+    }
+
+    if (fetched)
+        *fetched = i;
+
+    return i < count ? S_FALSE : S_OK;
 }
 
 static HRESULT WINAPI dict_enum_Skip(IEnumVARIANT *iface, ULONG count)
 {
     struct dictionary_enum *This = impl_from_IEnumVARIANT(iface);
-    FIXME("(%p)->(%u): stub\n", This, count);
-    return E_NOTIMPL;
+
+    TRACE("(%p)->(%u)\n", This, count);
+
+    if (!count)
+        return S_OK;
+
+    if (!This->cur)
+        return S_FALSE;
+
+    while (count--) {
+        This->cur = list_next(&This->dict->pairs, This->cur);
+        if (!This->cur) break;
+    }
+
+    return count == 0 ? S_OK : S_FALSE;
 }
 
 static HRESULT WINAPI dict_enum_Reset(IEnumVARIANT *iface)
 {
     struct dictionary_enum *This = impl_from_IEnumVARIANT(iface);
-    FIXME("(%p): stub\n", This);
-    return E_NOTIMPL;
+
+    TRACE("(%p)\n", This);
+
+    This->cur = list_head(&This->dict->pairs);
+    return S_OK;
 }
 
+static HRESULT create_dict_enum(dictionary*, IUnknown**);
+
 static HRESULT WINAPI dict_enum_Clone(IEnumVARIANT *iface, IEnumVARIANT **cloned)
 {
     struct dictionary_enum *This = impl_from_IEnumVARIANT(iface);
-    FIXME("(%p)->(%p): stub\n", This, cloned);
-    return E_NOTIMPL;
+    TRACE("(%p)->(%p)\n", This, cloned);
+    return create_dict_enum(This->dict, (IUnknown**)cloned);
 }
 
 static const IEnumVARIANTVtbl dictenumvtbl = {
@@ -305,6 +347,8 @@ static HRESULT create_dict_enum(dictionary *dict, IUnknown **ret)
 
     This->IEnumVARIANT_iface.lpVtbl = &dictenumvtbl;
     This->ref = 1;
+    This->cur = list_head(&dict->pairs);
+    list_add_tail(&dict->notifier, &This->notify);
     This->dict = dict;
     IDictionary_AddRef(&dict->IDictionary_iface);
 
@@ -312,6 +356,21 @@ static HRESULT create_dict_enum(dictionary *dict, IUnknown **ret)
     return S_OK;
 }
 
+static void notify_remove_pair(struct list *notifier, struct list *pair)
+{
+    struct dictionary_enum *dict_enum;
+    struct list *cur;
+
+    LIST_FOR_EACH(cur, notifier) {
+        dict_enum = LIST_ENTRY(cur, struct dictionary_enum, notify);
+        if (!pair)
+            dict_enum->cur = list_head(&dict_enum->dict->pairs);
+        else if (dict_enum->cur == pair) {
+            dict_enum->cur = list_next(&dict_enum->dict->pairs, dict_enum->cur);
+        }
+    }
+}
+
 static HRESULT WINAPI dictionary_QueryInterface(IDictionary *iface, REFIID riid, void **obj)
 {
     dictionary *This = impl_from_IDictionary(iface);
@@ -616,6 +675,7 @@ static HRESULT WINAPI dictionary_Remove(IDictionary *iface, VARIANT *key)
     if (!(pair = get_keyitem_pair(This, key)))
         return CTL_E_ELEMENT_NOT_FOUND;
 
+    notify_remove_pair(&This->notifier, &pair->entry);
     list_remove(&pair->entry);
     list_remove(&pair->bucket);
     This->count--;
@@ -634,6 +694,7 @@ static HRESULT WINAPI dictionary_RemoveAll(IDictionary *iface)
     if (This->count == 0)
         return S_OK;
 
+    notify_remove_pair(&This->notifier, NULL);
     LIST_FOR_EACH_ENTRY_SAFE(pair, pair2, &This->pairs, struct keyitem_pair, entry) {
         list_remove(&pair->entry);
         list_remove(&pair->bucket);
@@ -796,6 +857,7 @@ HRESULT WINAPI Dictionary_CreateInstance(IClassFactory *factory,IUnknown *outer,
     This->method = BinaryCompare;
     This->count = 0;
     list_init(&This->pairs);
+    list_init(&This->notifier);
     memset(This->buckets, 0, sizeof(This->buckets));
 
     *obj = &This->IDictionary_iface;
diff --git a/dlls/scrrun/tests/dictionary.c b/dlls/scrrun/tests/dictionary.c
index 927ac05..1869861 100644
--- a/dlls/scrrun/tests/dictionary.c
+++ b/dlls/scrrun/tests/dictionary.c
@@ -618,6 +618,123 @@ static void test_Add(void)
     IDictionary_Release(dict);
 }
 
+static void test_IEnumVARIANT(void)
+{
+    IUnknown *enum1, *enum2;
+    IEnumVARIANT *enumvar;
+    VARIANT key, item;
+    IDictionary *dict;
+    ULONG fetched;
+    HRESULT hr;
+
+    hr = CoCreateInstance(&CLSID_Dictionary, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
+            &IID_IDictionary, (void**)&dict);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+if (0) /* crashes on native */
+    hr = IDictionary__NewEnum(dict, NULL);
+
+    hr = IDictionary__NewEnum(dict, &enum1);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    hr = IDictionary__NewEnum(dict, &enum2);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    ok(enum1 != enum2, "got %p, %p\n", enum2, enum1);
+    IUnknown_Release(enum2);
+
+    hr = IUnknown_QueryInterface(enum1, &IID_IEnumVARIANT, (void**)&enumvar);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    IUnknown_Release(enum1);
+
+    /* dictionary is empty */
+    hr = IEnumVARIANT_Skip(enumvar, 1);
+    ok(hr == S_FALSE, "got 0x%08x\n", hr);
+
+    hr = IEnumVARIANT_Skip(enumvar, 0);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    V_VT(&key) = VT_I2;
+    V_I2(&key) = 1;
+    V_VT(&item) = VT_I4;
+    V_I4(&item) = 100;
+    hr = IDictionary_Add(dict, &key, &item);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    hr = IEnumVARIANT_Skip(enumvar, 0);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    hr = IEnumVARIANT_Reset(enumvar);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    hr = IEnumVARIANT_Skip(enumvar, 1);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    hr = IEnumVARIANT_Skip(enumvar, 1);
+    ok(hr == S_FALSE, "got 0x%08x\n", hr);
+
+    V_VT(&key) = VT_I2;
+    V_I2(&key) = 4000;
+    V_VT(&item) = VT_I4;
+    V_I4(&item) = 200;
+    hr = IDictionary_Add(dict, &key, &item);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    V_VT(&key) = VT_I2;
+    V_I2(&key) = 0;
+    V_VT(&item) = VT_I4;
+    V_I4(&item) = 300;
+    hr = IDictionary_Add(dict, &key, &item);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    hr = IEnumVARIANT_Reset(enumvar);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    VariantInit(&key);
+    hr = IEnumVARIANT_Next(enumvar, 1, &key, &fetched);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    ok(V_VT(&key) == VT_I2, "got %d\n", V_VT(&key));
+    ok(V_I2(&key) == 1, "got %d\n", V_I2(&key));
+    ok(fetched == 1, "got %u\n", fetched);
+
+    hr = IEnumVARIANT_Reset(enumvar);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    hr = IDictionary_Remove(dict, &key);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    VariantInit(&key);
+    hr = IEnumVARIANT_Next(enumvar, 1, &key, &fetched);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    ok(V_VT(&key) == VT_I2, "got %d\n", V_VT(&key));
+    ok(V_I2(&key) == 4000, "got %d\n", V_I2(&key));
+    ok(fetched == 1, "got %u\n", fetched);
+
+    VariantInit(&key);
+    hr = IEnumVARIANT_Next(enumvar, 1, &key, &fetched);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    ok(V_VT(&key) == VT_I2, "got %d\n", V_VT(&key));
+    ok(V_I2(&key) == 0, "got %d\n", V_I2(&key));
+    ok(fetched == 1, "got %u\n", fetched);
+
+    /* enumeration reached the bottom, add one more pair */
+    VariantInit(&key);
+    hr = IEnumVARIANT_Next(enumvar, 1, &key, &fetched);
+    ok(hr == S_FALSE, "got 0x%08x\n", hr);
+
+    V_VT(&key) = VT_I2;
+    V_I2(&key) = 13;
+    V_VT(&item) = VT_I4;
+    V_I4(&item) = 350;
+    hr = IDictionary_Add(dict, &key, &item);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    /* still doesn't work until Reset() */
+    VariantInit(&key);
+    hr = IEnumVARIANT_Next(enumvar, 1, &key, &fetched);
+    ok(hr == S_FALSE, "got 0x%08x\n", hr);
+
+    IEnumVARIANT_Release(enumvar);
+    IDictionary_Release(dict);
+}
+
 START_TEST(dictionary)
 {
     IDispatch *disp;
@@ -642,6 +759,7 @@ START_TEST(dictionary)
     test_Remove();
     test_Item();
     test_Add();
+    test_IEnumVARIANT();
 
     CoUninitialize();
 }




More information about the wine-cvs mailing list