scrrun: Implement IEnumVARIANT support for dictionary.
This commit is contained in:
parent
77432ac45d
commit
ba48217429
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue