2 * Copyright (C) 2012 Alistair Leslie-Hughes
3 * Copyright 2015 Nikolay Sivov for CodeWeavers
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #include "scrrun_private.h"
32 #include "wine/debug.h"
33 #include "wine/list.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(scrrun
);
37 #define BUCKET_COUNT 509
38 #define DICT_HASH_MOD 1201
40 /* Implementation details
42 Dictionary contains one list that links all pairs, this way
43 order in which they were added is preserved. Each bucket has
44 its own list to hold all pairs in this bucket. Initially all
45 bucket lists are zeroed and we init them once we about to add
48 When pair is removed it's unlinked from both lists; if it was
49 a last pair in a bucket list it stays empty in initialized state.
51 Preserving pair order is important for enumeration, so far testing
52 indicates that pairs are not reordered basing on hash value.
66 struct provideclassinfo classinfo
;
67 IDictionary IDictionary_iface
;
73 struct list buckets
[BUCKET_COUNT
];
77 struct dictionary_enum
79 IEnumVARIANT IEnumVARIANT_iface
;
82 struct dictionary
*dict
;
87 static inline struct dictionary
*impl_from_IDictionary(IDictionary
*iface
)
89 return CONTAINING_RECORD(iface
, struct dictionary
, IDictionary_iface
);
92 static inline struct dictionary_enum
*impl_from_IEnumVARIANT(IEnumVARIANT
*iface
)
94 return CONTAINING_RECORD(iface
, struct dictionary_enum
, IEnumVARIANT_iface
);
97 static inline struct list
*get_bucket_head(struct dictionary
*dict
, DWORD hash
)
99 return &dict
->buckets
[hash
% BUCKET_COUNT
];
102 static inline BOOL
is_string_key(const VARIANT
*key
)
104 return V_VT(key
) == VT_BSTR
|| V_VT(key
) == (VT_BSTR
|VT_BYREF
);
107 /* Only for VT_BSTR or VT_BSTR|VT_BYREF types */
108 static inline WCHAR
*get_key_strptr(const VARIANT
*key
)
110 if (V_VT(key
) == VT_BSTR
)
114 return *V_BSTRREF(key
);
119 /* should be used only when both keys are of string type, it's not checked */
120 static inline int strcmp_key(const struct dictionary
*dict
, const VARIANT
*key1
, const VARIANT
*key2
)
122 const WCHAR
*str1
, *str2
;
124 str1
= get_key_strptr(key1
);
125 str2
= get_key_strptr(key2
);
126 return dict
->method
== BinaryCompare
? wcscmp(str1
, str2
) : wcsicmp(str1
, str2
);
129 static BOOL
is_matching_key(const struct dictionary
*dict
, const struct keyitem_pair
*pair
, const VARIANT
*key
, DWORD hash
)
131 if (is_string_key(key
) && is_string_key(&pair
->key
)) {
132 if (hash
!= pair
->hash
)
135 return strcmp_key(dict
, key
, &pair
->key
) == 0;
138 if ((is_string_key(key
) && !is_string_key(&pair
->key
)) ||
139 (!is_string_key(key
) && is_string_key(&pair
->key
)))
142 /* for numeric keys only check hash */
143 return hash
== pair
->hash
;
146 static struct keyitem_pair
*get_keyitem_pair(struct dictionary
*dict
, VARIANT
*key
)
148 struct keyitem_pair
*pair
;
149 struct list
*head
, *entry
;
153 hr
= IDictionary_get_HashVal(&dict
->IDictionary_iface
, key
, &hash
);
157 head
= get_bucket_head(dict
, V_I4(&hash
));
158 if (!head
->next
|| list_empty(head
))
161 entry
= list_head(head
);
163 pair
= LIST_ENTRY(entry
, struct keyitem_pair
, bucket
);
164 if (is_matching_key(dict
, pair
, key
, V_I4(&hash
))) return pair
;
165 } while ((entry
= list_next(head
, entry
)));
170 static HRESULT
add_keyitem_pair(struct dictionary
*dict
, VARIANT
*key
, VARIANT
*item
)
172 struct keyitem_pair
*pair
;
177 hr
= IDictionary_get_HashVal(&dict
->IDictionary_iface
, key
, &hash
);
181 if (!(pair
= malloc(sizeof(*pair
))))
182 return E_OUTOFMEMORY
;
184 pair
->hash
= V_I4(&hash
);
185 VariantInit(&pair
->key
);
186 VariantInit(&pair
->item
);
188 hr
= VariantCopyInd(&pair
->key
, key
);
192 hr
= VariantCopyInd(&pair
->item
, item
);
196 head
= get_bucket_head(dict
, pair
->hash
);
198 /* this only happens once per bucket */
201 /* link to bucket list and to full list */
202 list_add_tail(head
, &pair
->bucket
);
203 list_add_tail(&dict
->pairs
, &pair
->entry
);
208 VariantClear(&pair
->key
);
209 VariantClear(&pair
->item
);
214 static void free_keyitem_pair(struct keyitem_pair
*pair
)
216 VariantClear(&pair
->key
);
217 VariantClear(&pair
->item
);
221 static HRESULT WINAPI
dict_enum_QueryInterface(IEnumVARIANT
*iface
, REFIID riid
, void **obj
)
223 struct dictionary_enum
*This
= impl_from_IEnumVARIANT(iface
);
225 TRACE("(%p)->(%s, %p)\n", This
, debugstr_guid(riid
), obj
);
227 if (IsEqualIID(riid
, &IID_IEnumVARIANT
) || IsEqualIID(riid
, &IID_IUnknown
)) {
229 IEnumVARIANT_AddRef(iface
);
233 WARN("interface not supported %s\n", debugstr_guid(riid
));
235 return E_NOINTERFACE
;
239 static ULONG WINAPI
dict_enum_AddRef(IEnumVARIANT
*iface
)
241 struct dictionary_enum
*This
= impl_from_IEnumVARIANT(iface
);
242 ULONG ref
= InterlockedIncrement(&This
->ref
);
243 TRACE("%p, refcount %lu.\n", iface
, ref
);
247 static ULONG WINAPI
dict_enum_Release(IEnumVARIANT
*iface
)
249 struct dictionary_enum
*This
= impl_from_IEnumVARIANT(iface
);
250 LONG ref
= InterlockedDecrement(&This
->ref
);
252 TRACE("%p, refcount %lu.\n", iface
, ref
);
256 list_remove(&This
->notify
);
257 IDictionary_Release(&This
->dict
->IDictionary_iface
);
264 static HRESULT WINAPI
dict_enum_Next(IEnumVARIANT
*iface
, ULONG count
, VARIANT
*keys
, ULONG
*fetched
)
266 struct dictionary_enum
*This
= impl_from_IEnumVARIANT(iface
);
267 struct keyitem_pair
*pair
;
270 TRACE("%p, %lu, %p, %p.\n", iface
, count
, keys
, fetched
);
278 while (This
->cur
&& i
< count
) {
279 pair
= LIST_ENTRY(This
->cur
, struct keyitem_pair
, entry
);
280 VariantCopy(&keys
[i
], &pair
->key
);
281 This
->cur
= list_next(&This
->dict
->pairs
, This
->cur
);
288 return i
< count
? S_FALSE
: S_OK
;
291 static HRESULT WINAPI
dict_enum_Skip(IEnumVARIANT
*iface
, ULONG count
)
293 struct dictionary_enum
*This
= impl_from_IEnumVARIANT(iface
);
295 TRACE("%p, %lu.\n", iface
, count
);
304 This
->cur
= list_next(&This
->dict
->pairs
, This
->cur
);
305 if (!This
->cur
) break;
308 return count
== 0 ? S_OK
: S_FALSE
;
311 static HRESULT WINAPI
dict_enum_Reset(IEnumVARIANT
*iface
)
313 struct dictionary_enum
*This
= impl_from_IEnumVARIANT(iface
);
315 TRACE("(%p)\n", This
);
317 This
->cur
= list_head(&This
->dict
->pairs
);
321 static HRESULT
create_dict_enum(struct dictionary
*, IUnknown
**);
323 static HRESULT WINAPI
dict_enum_Clone(IEnumVARIANT
*iface
, IEnumVARIANT
**cloned
)
325 struct dictionary_enum
*This
= impl_from_IEnumVARIANT(iface
);
326 TRACE("(%p)->(%p)\n", This
, cloned
);
327 return create_dict_enum(This
->dict
, (IUnknown
**)cloned
);
330 static const IEnumVARIANTVtbl dictenumvtbl
= {
331 dict_enum_QueryInterface
,
340 static HRESULT
create_dict_enum(struct dictionary
*dict
, IUnknown
**ret
)
342 struct dictionary_enum
*object
;
346 if (!(object
= calloc(1, sizeof(*object
))))
347 return E_OUTOFMEMORY
;
349 object
->IEnumVARIANT_iface
.lpVtbl
= &dictenumvtbl
;
351 object
->cur
= list_head(&dict
->pairs
);
352 list_add_tail(&dict
->notifier
, &object
->notify
);
354 IDictionary_AddRef(&dict
->IDictionary_iface
);
356 *ret
= (IUnknown
*)&object
->IEnumVARIANT_iface
;
361 static void notify_remove_pair(struct list
*notifier
, struct list
*pair
)
363 struct dictionary_enum
*dict_enum
;
366 LIST_FOR_EACH(cur
, notifier
) {
367 dict_enum
= LIST_ENTRY(cur
, struct dictionary_enum
, notify
);
369 dict_enum
->cur
= list_head(&dict_enum
->dict
->pairs
);
370 else if (dict_enum
->cur
== pair
) {
371 dict_enum
->cur
= list_next(&dict_enum
->dict
->pairs
, dict_enum
->cur
);
376 static HRESULT WINAPI
dictionary_QueryInterface(IDictionary
*iface
, REFIID riid
, void **obj
)
378 struct dictionary
*dictionary
= impl_from_IDictionary(iface
);
380 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
384 if(IsEqualIID(riid
, &IID_IUnknown
) ||
385 IsEqualIID(riid
, &IID_IDispatch
) ||
386 IsEqualIID(riid
, &IID_IDictionary
))
388 *obj
= &dictionary
->IDictionary_iface
;
390 else if (IsEqualIID(riid
, &IID_IProvideClassInfo
))
392 *obj
= &dictionary
->classinfo
.IProvideClassInfo_iface
;
394 else if ( IsEqualGUID( riid
, &IID_IDispatchEx
))
396 TRACE("Interface IDispatchEx not supported - returning NULL\n");
398 return E_NOINTERFACE
;
400 else if ( IsEqualGUID( riid
, &IID_IObjectWithSite
))
402 TRACE("Interface IObjectWithSite not supported - returning NULL\n");
404 return E_NOINTERFACE
;
408 WARN("interface %s not implemented\n", debugstr_guid(riid
));
409 return E_NOINTERFACE
;
412 IUnknown_AddRef((IUnknown
*)*obj
);
416 static ULONG WINAPI
dictionary_AddRef(IDictionary
*iface
)
418 struct dictionary
*dictionary
= impl_from_IDictionary(iface
);
419 ULONG ref
= InterlockedIncrement(&dictionary
->ref
);
421 TRACE("%p, refcount %lu.\n", iface
, ref
);
426 static ULONG WINAPI
dictionary_Release(IDictionary
*iface
)
428 struct dictionary
*dictionary
= impl_from_IDictionary(iface
);
429 ULONG ref
= InterlockedDecrement(&dictionary
->ref
);
431 TRACE("%p, refcount %lu.\n", iface
, ref
);
435 IDictionary_RemoveAll(iface
);
442 static HRESULT WINAPI
dictionary_GetTypeInfoCount(IDictionary
*iface
, UINT
*pctinfo
)
444 TRACE("%p, %p.\n", iface
, pctinfo
);
450 static HRESULT WINAPI
dictionary_GetTypeInfo(IDictionary
*iface
, UINT iTInfo
, LCID lcid
, ITypeInfo
**ppTInfo
)
452 TRACE("%p, %u, %lx, %p.\n", iface
, iTInfo
, lcid
, ppTInfo
);
454 return get_typeinfo(IDictionary_tid
, ppTInfo
);
457 static HRESULT WINAPI
dictionary_GetIDsOfNames(IDictionary
*iface
, REFIID riid
, LPOLESTR
*rgszNames
,
458 UINT cNames
, LCID lcid
, DISPID
*rgDispId
)
463 TRACE("%p, %s, %p, %u, %lx, %p.\n", iface
, debugstr_guid(riid
), rgszNames
, cNames
, lcid
, rgDispId
);
465 hr
= get_typeinfo(IDictionary_tid
, &typeinfo
);
468 hr
= ITypeInfo_GetIDsOfNames(typeinfo
, rgszNames
, cNames
, rgDispId
);
469 ITypeInfo_Release(typeinfo
);
475 static HRESULT WINAPI
dictionary_Invoke(IDictionary
*iface
, DISPID dispIdMember
, REFIID riid
,
476 LCID lcid
, WORD wFlags
, DISPPARAMS
*pDispParams
, VARIANT
*pVarResult
,
477 EXCEPINFO
*pExcepInfo
, UINT
*puArgErr
)
482 TRACE("%p, %ld, %s, %lx, %d, %p, %p, %p, %p.\n", iface
, dispIdMember
, debugstr_guid(riid
),
483 lcid
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
485 hr
= get_typeinfo(IDictionary_tid
, &typeinfo
);
488 hr
= ITypeInfo_Invoke(typeinfo
, iface
, dispIdMember
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
489 ITypeInfo_Release(typeinfo
);
495 static HRESULT WINAPI
dictionary_putref_Item(IDictionary
*iface
, VARIANT
*Key
, VARIANT
*pRetItem
)
497 FIXME("%p, %p, %p stub\n", iface
, Key
, pRetItem
);
502 static HRESULT WINAPI
dictionary_put_Item(IDictionary
*iface
, VARIANT
*key
, VARIANT
*item
)
504 struct dictionary
*dictionary
= impl_from_IDictionary(iface
);
505 struct keyitem_pair
*pair
;
507 TRACE("%p, %s, %s.\n", iface
, debugstr_variant(key
), debugstr_variant(item
));
509 if ((pair
= get_keyitem_pair(dictionary
, key
)))
510 return VariantCopyInd(&pair
->item
, item
);
512 return IDictionary_Add(iface
, key
, item
);
515 static HRESULT WINAPI
dictionary_get_Item(IDictionary
*iface
, VARIANT
*key
, VARIANT
*item
)
517 struct dictionary
*dictionary
= impl_from_IDictionary(iface
);
518 struct keyitem_pair
*pair
;
520 TRACE("%p, %s, %p.\n", iface
, debugstr_variant(key
), item
);
522 if ((pair
= get_keyitem_pair(dictionary
, key
)))
523 VariantCopy(item
, &pair
->item
);
526 return IDictionary_Add(iface
, key
, item
);
532 static HRESULT WINAPI
dictionary_Add(IDictionary
*iface
, VARIANT
*key
, VARIANT
*item
)
534 struct dictionary
*dictionary
= impl_from_IDictionary(iface
);
536 TRACE("%p, %s, %s.\n", iface
, debugstr_variant(key
), debugstr_variant(item
));
538 if (get_keyitem_pair(dictionary
, key
))
539 return CTL_E_KEY_ALREADY_EXISTS
;
541 return add_keyitem_pair(dictionary
, key
, item
);
544 static HRESULT WINAPI
dictionary_get_Count(IDictionary
*iface
, LONG
*count
)
546 struct dictionary
*dictionary
= impl_from_IDictionary(iface
);
548 TRACE("%p, %p.\n", iface
, count
);
550 *count
= dictionary
->count
;
554 static HRESULT WINAPI
dictionary_Exists(IDictionary
*iface
, VARIANT
*key
, VARIANT_BOOL
*exists
)
556 struct dictionary
*dictionary
= impl_from_IDictionary(iface
);
558 TRACE("%p, %s, %p.\n", iface
, debugstr_variant(key
), exists
);
561 return CTL_E_ILLEGALFUNCTIONCALL
;
563 *exists
= get_keyitem_pair(dictionary
, key
) != NULL
? VARIANT_TRUE
: VARIANT_FALSE
;
567 static HRESULT WINAPI
dictionary_Items(IDictionary
*iface
, VARIANT
*items
)
569 struct dictionary
*dictionary
= impl_from_IDictionary(iface
);
570 struct keyitem_pair
*pair
;
571 SAFEARRAYBOUND bound
;
577 TRACE("%p, %p.\n", iface
, items
);
583 bound
.cElements
= dictionary
->count
;
584 sa
= SafeArrayCreate(VT_VARIANT
, 1, &bound
);
586 return E_OUTOFMEMORY
;
588 hr
= SafeArrayAccessData(sa
, (void**)&v
);
590 SafeArrayDestroy(sa
);
595 LIST_FOR_EACH_ENTRY(pair
, &dictionary
->pairs
, struct keyitem_pair
, entry
)
597 VariantCopy(&v
[i
], &pair
->item
);
600 SafeArrayUnaccessData(sa
);
602 V_VT(items
) = VT_ARRAY
|VT_VARIANT
;
607 static HRESULT WINAPI
dictionary_put_Key(IDictionary
*iface
, VARIANT
*key
, VARIANT
*newkey
)
609 struct dictionary
*dictionary
= impl_from_IDictionary(iface
);
610 struct keyitem_pair
*pair
;
614 TRACE("%p, %s, %s.\n", iface
, debugstr_variant(key
), debugstr_variant(newkey
));
616 if ((pair
= get_keyitem_pair(dictionary
, key
)))
618 /* found existing pair for a key, add new pair with new key
619 and old item and remove old pair after that */
621 hr
= IDictionary_Add(iface
, newkey
, &pair
->item
);
625 return IDictionary_Remove(iface
, key
);
629 return IDictionary_Add(iface
, newkey
, &empty
);
632 static HRESULT WINAPI
dictionary_Keys(IDictionary
*iface
, VARIANT
*keys
)
634 struct dictionary
*dictionary
= impl_from_IDictionary(iface
);
635 struct keyitem_pair
*pair
;
636 SAFEARRAYBOUND bound
;
642 TRACE("%p, %p.\n", iface
, keys
);
648 bound
.cElements
= dictionary
->count
;
649 sa
= SafeArrayCreate(VT_VARIANT
, 1, &bound
);
651 return E_OUTOFMEMORY
;
653 hr
= SafeArrayAccessData(sa
, (void**)&v
);
655 SafeArrayDestroy(sa
);
660 LIST_FOR_EACH_ENTRY(pair
, &dictionary
->pairs
, struct keyitem_pair
, entry
)
662 VariantCopy(&v
[i
], &pair
->key
);
665 SafeArrayUnaccessData(sa
);
667 V_VT(keys
) = VT_ARRAY
|VT_VARIANT
;
672 static HRESULT WINAPI
dictionary_Remove(IDictionary
*iface
, VARIANT
*key
)
674 struct dictionary
*dictionary
= impl_from_IDictionary(iface
);
675 struct keyitem_pair
*pair
;
677 TRACE("%p, %s.\n", iface
, debugstr_variant(key
));
679 if (!(pair
= get_keyitem_pair(dictionary
, key
)))
680 return CTL_E_ELEMENT_NOT_FOUND
;
682 notify_remove_pair(&dictionary
->notifier
, &pair
->entry
);
683 list_remove(&pair
->entry
);
684 list_remove(&pair
->bucket
);
687 free_keyitem_pair(pair
);
691 static HRESULT WINAPI
dictionary_RemoveAll(IDictionary
*iface
)
693 struct dictionary
*dictionary
= impl_from_IDictionary(iface
);
694 struct keyitem_pair
*pair
, *pair2
;
696 TRACE("%p.\n", iface
);
698 if (!dictionary
->count
)
701 notify_remove_pair(&dictionary
->notifier
, NULL
);
702 LIST_FOR_EACH_ENTRY_SAFE(pair
, pair2
, &dictionary
->pairs
, struct keyitem_pair
, entry
)
704 list_remove(&pair
->entry
);
705 list_remove(&pair
->bucket
);
706 free_keyitem_pair(pair
);
708 dictionary
->count
= 0;
713 static HRESULT WINAPI
dictionary_put_CompareMode(IDictionary
*iface
, CompareMethod method
)
715 struct dictionary
*dictionary
= impl_from_IDictionary(iface
);
717 TRACE("%p, %d.\n", iface
, method
);
719 if (dictionary
->count
)
720 return CTL_E_ILLEGALFUNCTIONCALL
;
722 dictionary
->method
= method
;
726 static HRESULT WINAPI
dictionary_get_CompareMode(IDictionary
*iface
, CompareMethod
*method
)
728 struct dictionary
*dictionary
= impl_from_IDictionary(iface
);
730 TRACE("%p, %p.\n", iface
, method
);
732 *method
= dictionary
->method
;
736 static HRESULT WINAPI
dictionary__NewEnum(IDictionary
*iface
, IUnknown
**ret
)
738 struct dictionary
*dictionary
= impl_from_IDictionary(iface
);
740 TRACE("%p, %p.\n", iface
, ret
);
742 return create_dict_enum(dictionary
, ret
);
745 static DWORD
get_str_hash(const WCHAR
*str
, CompareMethod method
)
753 ch
= (method
== TextCompare
|| method
== DatabaseCompare
) ? towlower(*str
) : *str
;
755 hash
+= (hash
<< 4) + ch
;
760 return hash
% DICT_HASH_MOD
;
763 static DWORD
get_num_hash(FLOAT num
)
765 return (*((DWORD
*)&num
)) % DICT_HASH_MOD
;
768 static HRESULT
get_flt_hash(FLOAT flt
, LONG
*hash
)
774 else if (!isnan(flt
)) {
775 *hash
= get_num_hash(flt
);
781 return CTL_E_ILLEGALFUNCTIONCALL
;
784 static DWORD
get_ptr_hash(void *ptr
)
786 return PtrToUlong(ptr
) % DICT_HASH_MOD
;
789 static HRESULT WINAPI
dictionary_get_HashVal(IDictionary
*iface
, VARIANT
*key
, VARIANT
*hash
)
791 struct dictionary
*dictionary
= impl_from_IDictionary(iface
);
793 TRACE("%p, %s, %p.\n", iface
, debugstr_variant(key
), hash
);
798 case VT_BSTR
|VT_BYREF
:
800 V_I4(hash
) = get_str_hash(get_key_strptr(key
), dictionary
->method
);
802 case VT_UI1
|VT_BYREF
:
804 V_I4(hash
) = get_num_hash(V_VT(key
) & VT_BYREF
? *V_UI1REF(key
) : V_UI1(key
));
808 V_I4(hash
) = get_num_hash(V_VT(key
) & VT_BYREF
? *V_I2REF(key
) : V_I2(key
));
812 V_I4(hash
) = get_num_hash(V_VT(key
) & VT_BYREF
? *V_I4REF(key
) : V_I4(key
));
814 case VT_UNKNOWN
|VT_BYREF
:
815 case VT_DISPATCH
|VT_BYREF
:
819 IUnknown
*src
= (V_VT(key
) & VT_BYREF
) ? *V_UNKNOWNREF(key
) : V_UNKNOWN(key
);
820 IUnknown
*unk
= NULL
;
827 IUnknown_QueryInterface(src
, &IID_IUnknown
, (void**)&unk
);
830 return CTL_E_ILLEGALFUNCTIONCALL
;
832 V_I4(hash
) = get_ptr_hash(unk
);
833 IUnknown_Release(unk
);
836 case VT_DATE
|VT_BYREF
:
838 return get_flt_hash(V_VT(key
) & VT_BYREF
? *V_DATEREF(key
) : V_DATE(key
), &V_I4(hash
));
841 return get_flt_hash(V_VT(key
) & VT_BYREF
? *V_R4REF(key
) : V_R4(key
), &V_I4(hash
));
844 return get_flt_hash(V_VT(key
) & VT_BYREF
? *V_R8REF(key
) : V_R8(key
), &V_I4(hash
));
852 return CTL_E_ILLEGALFUNCTIONCALL
;
854 FIXME("not implemented for type %d\n", V_VT(key
));
861 static const struct IDictionaryVtbl dictionary_vtbl
=
863 dictionary_QueryInterface
,
866 dictionary_GetTypeInfoCount
,
867 dictionary_GetTypeInfo
,
868 dictionary_GetIDsOfNames
,
870 dictionary_putref_Item
,
874 dictionary_get_Count
,
880 dictionary_RemoveAll
,
881 dictionary_put_CompareMode
,
882 dictionary_get_CompareMode
,
884 dictionary_get_HashVal
887 HRESULT WINAPI
Dictionary_CreateInstance(IClassFactory
*factory
, IUnknown
*outer
, REFIID riid
, void **ret
)
889 struct dictionary
*object
;
891 TRACE("(%p, %p, %s, %p)\n", factory
, outer
, debugstr_guid(riid
), ret
);
895 if (!(object
= calloc(1, sizeof(*object
))))
896 return E_OUTOFMEMORY
;
898 object
->IDictionary_iface
.lpVtbl
= &dictionary_vtbl
;
900 object
->method
= BinaryCompare
;
901 list_init(&object
->pairs
);
902 list_init(&object
->notifier
);
904 init_classinfo(&CLSID_Dictionary
, (IUnknown
*)&object
->IDictionary_iface
, &object
->classinfo
);
906 *ret
= &object
->IDictionary_iface
;