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/heap.h"
34 #include "wine/list.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(scrrun
);
38 #define BUCKET_COUNT 509
39 #define DICT_HASH_MOD 1201
41 /* Implementation details
43 Dictionary contains one list that links all pairs, this way
44 order in which they were added is preserved. Each bucket has
45 its own list to hold all pairs in this bucket. Initially all
46 bucket lists are zeroed and we init them once we about to add
49 When pair is removed it's unlinked from both lists; if it was
50 a last pair in a bucket list it stays empty in initialized state.
52 Preserving pair order is important for enumeration, so far testing
53 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
{
78 IEnumVARIANT IEnumVARIANT_iface
;
86 static inline dictionary
*impl_from_IDictionary(IDictionary
*iface
)
88 return CONTAINING_RECORD(iface
, dictionary
, IDictionary_iface
);
91 static inline struct dictionary_enum
*impl_from_IEnumVARIANT(IEnumVARIANT
*iface
)
93 return CONTAINING_RECORD(iface
, struct dictionary_enum
, IEnumVARIANT_iface
);
96 static inline struct list
*get_bucket_head(dictionary
*dict
, DWORD hash
)
98 return &dict
->buckets
[hash
% BUCKET_COUNT
];
101 static inline BOOL
is_string_key(const VARIANT
*key
)
103 return V_VT(key
) == VT_BSTR
|| V_VT(key
) == (VT_BSTR
|VT_BYREF
);
106 /* Only for VT_BSTR or VT_BSTR|VT_BYREF types */
107 static inline WCHAR
*get_key_strptr(const VARIANT
*key
)
109 if (V_VT(key
) == VT_BSTR
)
113 return *V_BSTRREF(key
);
118 /* should be used only when both keys are of string type, it's not checked */
119 static inline int strcmp_key(const dictionary
*dict
, const VARIANT
*key1
, const VARIANT
*key2
)
121 const WCHAR
*str1
, *str2
;
123 str1
= get_key_strptr(key1
);
124 str2
= get_key_strptr(key2
);
125 return dict
->method
== BinaryCompare
? wcscmp(str1
, str2
) : wcsicmp(str1
, str2
);
128 static BOOL
is_matching_key(const dictionary
*dict
, const struct keyitem_pair
*pair
, const VARIANT
*key
, DWORD hash
)
130 if (is_string_key(key
) && is_string_key(&pair
->key
)) {
131 if (hash
!= pair
->hash
)
134 return strcmp_key(dict
, key
, &pair
->key
) == 0;
137 if ((is_string_key(key
) && !is_string_key(&pair
->key
)) ||
138 (!is_string_key(key
) && is_string_key(&pair
->key
)))
141 /* for numeric keys only check hash */
142 return hash
== pair
->hash
;
145 static struct keyitem_pair
*get_keyitem_pair(dictionary
*dict
, VARIANT
*key
)
147 struct keyitem_pair
*pair
;
148 struct list
*head
, *entry
;
152 hr
= IDictionary_get_HashVal(&dict
->IDictionary_iface
, key
, &hash
);
156 head
= get_bucket_head(dict
, V_I4(&hash
));
157 if (!head
->next
|| list_empty(head
))
160 entry
= list_head(head
);
162 pair
= LIST_ENTRY(entry
, struct keyitem_pair
, bucket
);
163 if (is_matching_key(dict
, pair
, key
, V_I4(&hash
))) return pair
;
164 } while ((entry
= list_next(head
, entry
)));
169 static HRESULT
add_keyitem_pair(dictionary
*dict
, VARIANT
*key
, VARIANT
*item
)
171 struct keyitem_pair
*pair
;
176 hr
= IDictionary_get_HashVal(&dict
->IDictionary_iface
, key
, &hash
);
180 pair
= heap_alloc(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)->(%u)\n", This
, 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)->(%u)\n", This
, ref
);
255 list_remove(&This
->notify
);
256 IDictionary_Release(&This
->dict
->IDictionary_iface
);
263 static HRESULT WINAPI
dict_enum_Next(IEnumVARIANT
*iface
, ULONG count
, VARIANT
*keys
, ULONG
*fetched
)
265 struct dictionary_enum
*This
= impl_from_IEnumVARIANT(iface
);
266 struct keyitem_pair
*pair
;
269 TRACE("(%p)->(%u %p %p)\n", This
, count
, keys
, fetched
);
277 while (This
->cur
&& i
< count
) {
278 pair
= LIST_ENTRY(This
->cur
, struct keyitem_pair
, entry
);
279 VariantCopy(&keys
[i
], &pair
->key
);
280 This
->cur
= list_next(&This
->dict
->pairs
, This
->cur
);
287 return i
< count
? S_FALSE
: S_OK
;
290 static HRESULT WINAPI
dict_enum_Skip(IEnumVARIANT
*iface
, ULONG count
)
292 struct dictionary_enum
*This
= impl_from_IEnumVARIANT(iface
);
294 TRACE("(%p)->(%u)\n", This
, count
);
303 This
->cur
= list_next(&This
->dict
->pairs
, This
->cur
);
304 if (!This
->cur
) break;
307 return count
== 0 ? S_OK
: S_FALSE
;
310 static HRESULT WINAPI
dict_enum_Reset(IEnumVARIANT
*iface
)
312 struct dictionary_enum
*This
= impl_from_IEnumVARIANT(iface
);
314 TRACE("(%p)\n", This
);
316 This
->cur
= list_head(&This
->dict
->pairs
);
320 static HRESULT
create_dict_enum(dictionary
*, IUnknown
**);
322 static HRESULT WINAPI
dict_enum_Clone(IEnumVARIANT
*iface
, IEnumVARIANT
**cloned
)
324 struct dictionary_enum
*This
= impl_from_IEnumVARIANT(iface
);
325 TRACE("(%p)->(%p)\n", This
, cloned
);
326 return create_dict_enum(This
->dict
, (IUnknown
**)cloned
);
329 static const IEnumVARIANTVtbl dictenumvtbl
= {
330 dict_enum_QueryInterface
,
339 static HRESULT
create_dict_enum(dictionary
*dict
, IUnknown
**ret
)
341 struct dictionary_enum
*This
;
345 This
= heap_alloc(sizeof(*This
));
347 return E_OUTOFMEMORY
;
349 This
->IEnumVARIANT_iface
.lpVtbl
= &dictenumvtbl
;
351 This
->cur
= list_head(&dict
->pairs
);
352 list_add_tail(&dict
->notifier
, &This
->notify
);
354 IDictionary_AddRef(&dict
->IDictionary_iface
);
356 *ret
= (IUnknown
*)&This
->IEnumVARIANT_iface
;
360 static void notify_remove_pair(struct list
*notifier
, struct list
*pair
)
362 struct dictionary_enum
*dict_enum
;
365 LIST_FOR_EACH(cur
, notifier
) {
366 dict_enum
= LIST_ENTRY(cur
, struct dictionary_enum
, notify
);
368 dict_enum
->cur
= list_head(&dict_enum
->dict
->pairs
);
369 else if (dict_enum
->cur
== pair
) {
370 dict_enum
->cur
= list_next(&dict_enum
->dict
->pairs
, dict_enum
->cur
);
375 static HRESULT WINAPI
dictionary_QueryInterface(IDictionary
*iface
, REFIID riid
, void **obj
)
377 dictionary
*This
= impl_from_IDictionary(iface
);
378 TRACE("(%p)->(%s, %p)\n", This
, debugstr_guid(riid
), obj
);
382 if(IsEqualIID(riid
, &IID_IUnknown
) ||
383 IsEqualIID(riid
, &IID_IDispatch
) ||
384 IsEqualIID(riid
, &IID_IDictionary
))
386 *obj
= &This
->IDictionary_iface
;
388 else if (IsEqualIID(riid
, &IID_IProvideClassInfo
))
390 *obj
= &This
->classinfo
.IProvideClassInfo_iface
;
392 else if ( IsEqualGUID( riid
, &IID_IDispatchEx
))
394 TRACE("Interface IDispatchEx not supported - returning NULL\n");
396 return E_NOINTERFACE
;
398 else if ( IsEqualGUID( riid
, &IID_IObjectWithSite
))
400 TRACE("Interface IObjectWithSite not supported - returning NULL\n");
402 return E_NOINTERFACE
;
406 WARN("interface %s not implemented\n", debugstr_guid(riid
));
407 return E_NOINTERFACE
;
410 IUnknown_AddRef((IUnknown
*)*obj
);
414 static ULONG WINAPI
dictionary_AddRef(IDictionary
*iface
)
416 dictionary
*This
= impl_from_IDictionary(iface
);
417 ULONG ref
= InterlockedIncrement(&This
->ref
);
419 TRACE("(%p)->(%u)\n", This
, ref
);
424 static ULONG WINAPI
dictionary_Release(IDictionary
*iface
)
426 dictionary
*This
= impl_from_IDictionary(iface
);
427 ULONG ref
= InterlockedDecrement(&This
->ref
);
429 TRACE("(%p)->(%u)\n", This
, ref
);
432 IDictionary_RemoveAll(iface
);
439 static HRESULT WINAPI
dictionary_GetTypeInfoCount(IDictionary
*iface
, UINT
*pctinfo
)
441 dictionary
*This
= impl_from_IDictionary(iface
);
443 TRACE("(%p)->(%p)\n", This
, pctinfo
);
449 static HRESULT WINAPI
dictionary_GetTypeInfo(IDictionary
*iface
, UINT iTInfo
, LCID lcid
, ITypeInfo
**ppTInfo
)
451 dictionary
*This
= impl_from_IDictionary(iface
);
453 TRACE("(%p)->(%u %u %p)\n", This
, 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
)
460 dictionary
*This
= impl_from_IDictionary(iface
);
464 TRACE("(%p)->(%s %p %u %u %p)\n", This
, debugstr_guid(riid
), rgszNames
, cNames
, lcid
, rgDispId
);
466 hr
= get_typeinfo(IDictionary_tid
, &typeinfo
);
469 hr
= ITypeInfo_GetIDsOfNames(typeinfo
, rgszNames
, cNames
, rgDispId
);
470 ITypeInfo_Release(typeinfo
);
476 static HRESULT WINAPI
dictionary_Invoke(IDictionary
*iface
, DISPID dispIdMember
, REFIID riid
,
477 LCID lcid
, WORD wFlags
, DISPPARAMS
*pDispParams
, VARIANT
*pVarResult
,
478 EXCEPINFO
*pExcepInfo
, UINT
*puArgErr
)
480 dictionary
*This
= impl_from_IDictionary(iface
);
484 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This
, dispIdMember
, debugstr_guid(riid
),
485 lcid
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
487 hr
= get_typeinfo(IDictionary_tid
, &typeinfo
);
490 hr
= ITypeInfo_Invoke(typeinfo
, &This
->IDictionary_iface
, dispIdMember
, wFlags
,
491 pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
492 ITypeInfo_Release(typeinfo
);
498 static HRESULT WINAPI
dictionary_putref_Item(IDictionary
*iface
, VARIANT
*Key
, VARIANT
*pRetItem
)
500 dictionary
*This
= impl_from_IDictionary(iface
);
502 FIXME("(%p)->(%p %p)\n", This
, Key
, pRetItem
);
507 static HRESULT WINAPI
dictionary_put_Item(IDictionary
*iface
, VARIANT
*key
, VARIANT
*item
)
509 dictionary
*This
= impl_from_IDictionary(iface
);
510 struct keyitem_pair
*pair
;
512 TRACE("(%p)->(%s %s)\n", This
, debugstr_variant(key
), debugstr_variant(item
));
514 if ((pair
= get_keyitem_pair(This
, key
)))
515 return VariantCopyInd(&pair
->item
, item
);
517 return IDictionary_Add(iface
, key
, item
);
520 static HRESULT WINAPI
dictionary_get_Item(IDictionary
*iface
, VARIANT
*key
, VARIANT
*item
)
522 dictionary
*This
= impl_from_IDictionary(iface
);
523 struct keyitem_pair
*pair
;
525 TRACE("(%p)->(%s %p)\n", This
, debugstr_variant(key
), item
);
527 if ((pair
= get_keyitem_pair(This
, key
)))
528 VariantCopy(item
, &pair
->item
);
531 return IDictionary_Add(iface
, key
, item
);
537 static HRESULT WINAPI
dictionary_Add(IDictionary
*iface
, VARIANT
*key
, VARIANT
*item
)
539 dictionary
*This
= impl_from_IDictionary(iface
);
541 TRACE("(%p)->(%s %s)\n", This
, debugstr_variant(key
), debugstr_variant(item
));
543 if (get_keyitem_pair(This
, key
))
544 return CTL_E_KEY_ALREADY_EXISTS
;
546 return add_keyitem_pair(This
, key
, item
);
549 static HRESULT WINAPI
dictionary_get_Count(IDictionary
*iface
, LONG
*count
)
551 dictionary
*This
= impl_from_IDictionary(iface
);
553 TRACE("(%p)->(%p)\n", This
, count
);
555 *count
= This
->count
;
559 static HRESULT WINAPI
dictionary_Exists(IDictionary
*iface
, VARIANT
*key
, VARIANT_BOOL
*exists
)
561 dictionary
*This
= impl_from_IDictionary(iface
);
563 TRACE("(%p)->(%s %p)\n", This
, debugstr_variant(key
), exists
);
566 return CTL_E_ILLEGALFUNCTIONCALL
;
568 *exists
= get_keyitem_pair(This
, key
) != NULL
? VARIANT_TRUE
: VARIANT_FALSE
;
572 static HRESULT WINAPI
dictionary_Items(IDictionary
*iface
, VARIANT
*items
)
574 dictionary
*This
= impl_from_IDictionary(iface
);
575 struct keyitem_pair
*pair
;
576 SAFEARRAYBOUND bound
;
582 TRACE("(%p)->(%p)\n", This
, items
);
588 bound
.cElements
= This
->count
;
589 sa
= SafeArrayCreate(VT_VARIANT
, 1, &bound
);
591 return E_OUTOFMEMORY
;
593 hr
= SafeArrayAccessData(sa
, (void**)&v
);
595 SafeArrayDestroy(sa
);
600 LIST_FOR_EACH_ENTRY(pair
, &This
->pairs
, struct keyitem_pair
, entry
) {
601 VariantCopy(&v
[i
], &pair
->item
);
604 SafeArrayUnaccessData(sa
);
606 V_VT(items
) = VT_ARRAY
|VT_VARIANT
;
611 static HRESULT WINAPI
dictionary_put_Key(IDictionary
*iface
, VARIANT
*key
, VARIANT
*newkey
)
613 dictionary
*This
= impl_from_IDictionary(iface
);
614 struct keyitem_pair
*pair
;
618 TRACE("(%p)->(%s %s)\n", This
, debugstr_variant(key
), debugstr_variant(newkey
));
620 if ((pair
= get_keyitem_pair(This
, key
))) {
621 /* found existing pair for a key, add new pair with new key
622 and old item and remove old pair after that */
624 hr
= IDictionary_Add(iface
, newkey
, &pair
->item
);
628 return IDictionary_Remove(iface
, key
);
632 return IDictionary_Add(iface
, newkey
, &empty
);
635 static HRESULT WINAPI
dictionary_Keys(IDictionary
*iface
, VARIANT
*keys
)
637 dictionary
*This
= impl_from_IDictionary(iface
);
638 struct keyitem_pair
*pair
;
639 SAFEARRAYBOUND bound
;
645 TRACE("(%p)->(%p)\n", This
, keys
);
651 bound
.cElements
= This
->count
;
652 sa
= SafeArrayCreate(VT_VARIANT
, 1, &bound
);
654 return E_OUTOFMEMORY
;
656 hr
= SafeArrayAccessData(sa
, (void**)&v
);
658 SafeArrayDestroy(sa
);
663 LIST_FOR_EACH_ENTRY(pair
, &This
->pairs
, struct keyitem_pair
, entry
) {
664 VariantCopy(&v
[i
], &pair
->key
);
667 SafeArrayUnaccessData(sa
);
669 V_VT(keys
) = VT_ARRAY
|VT_VARIANT
;
674 static HRESULT WINAPI
dictionary_Remove(IDictionary
*iface
, VARIANT
*key
)
676 dictionary
*This
= impl_from_IDictionary(iface
);
677 struct keyitem_pair
*pair
;
679 TRACE("(%p)->(%s)\n", This
, debugstr_variant(key
));
681 if (!(pair
= get_keyitem_pair(This
, key
)))
682 return CTL_E_ELEMENT_NOT_FOUND
;
684 notify_remove_pair(&This
->notifier
, &pair
->entry
);
685 list_remove(&pair
->entry
);
686 list_remove(&pair
->bucket
);
689 free_keyitem_pair(pair
);
693 static HRESULT WINAPI
dictionary_RemoveAll(IDictionary
*iface
)
695 dictionary
*This
= impl_from_IDictionary(iface
);
696 struct keyitem_pair
*pair
, *pair2
;
698 TRACE("(%p)\n", This
);
700 if (This
->count
== 0)
703 notify_remove_pair(&This
->notifier
, NULL
);
704 LIST_FOR_EACH_ENTRY_SAFE(pair
, pair2
, &This
->pairs
, struct keyitem_pair
, entry
) {
705 list_remove(&pair
->entry
);
706 list_remove(&pair
->bucket
);
707 free_keyitem_pair(pair
);
714 static HRESULT WINAPI
dictionary_put_CompareMode(IDictionary
*iface
, CompareMethod method
)
716 dictionary
*This
= impl_from_IDictionary(iface
);
718 TRACE("(%p)->(%d)\n", This
, method
);
721 return CTL_E_ILLEGALFUNCTIONCALL
;
723 This
->method
= method
;
727 static HRESULT WINAPI
dictionary_get_CompareMode(IDictionary
*iface
, CompareMethod
*method
)
729 dictionary
*This
= impl_from_IDictionary(iface
);
731 TRACE("(%p)->(%p)\n", This
, method
);
733 *method
= This
->method
;
737 static HRESULT WINAPI
dictionary__NewEnum(IDictionary
*iface
, IUnknown
**ret
)
739 dictionary
*This
= impl_from_IDictionary(iface
);
741 TRACE("(%p)->(%p)\n", This
, ret
);
743 return create_dict_enum(This
, ret
);
746 static DWORD
get_str_hash(const WCHAR
*str
, CompareMethod method
)
754 ch
= (method
== TextCompare
|| method
== DatabaseCompare
) ? towlower(*str
) : *str
;
756 hash
+= (hash
<< 4) + ch
;
761 return hash
% DICT_HASH_MOD
;
764 static DWORD
get_num_hash(FLOAT num
)
766 return (*((DWORD
*)&num
)) % DICT_HASH_MOD
;
769 static HRESULT
get_flt_hash(FLOAT flt
, LONG
*hash
)
775 else if (!isnan(flt
)) {
776 *hash
= get_num_hash(flt
);
782 return CTL_E_ILLEGALFUNCTIONCALL
;
785 static DWORD
get_ptr_hash(void *ptr
)
787 return PtrToUlong(ptr
) % DICT_HASH_MOD
;
790 static HRESULT WINAPI
dictionary_get_HashVal(IDictionary
*iface
, VARIANT
*key
, VARIANT
*hash
)
792 dictionary
*This
= impl_from_IDictionary(iface
);
794 TRACE("(%p)->(%s %p)\n", This
, debugstr_variant(key
), hash
);
799 case VT_BSTR
|VT_BYREF
:
801 V_I4(hash
) = get_str_hash(get_key_strptr(key
), This
->method
);
803 case VT_UI1
|VT_BYREF
:
805 V_I4(hash
) = get_num_hash(V_VT(key
) & VT_BYREF
? *V_UI1REF(key
) : V_UI1(key
));
809 V_I4(hash
) = get_num_hash(V_VT(key
) & VT_BYREF
? *V_I2REF(key
) : V_I2(key
));
813 V_I4(hash
) = get_num_hash(V_VT(key
) & VT_BYREF
? *V_I4REF(key
) : V_I4(key
));
815 case VT_UNKNOWN
|VT_BYREF
:
816 case VT_DISPATCH
|VT_BYREF
:
820 IUnknown
*src
= (V_VT(key
) & VT_BYREF
) ? *V_UNKNOWNREF(key
) : V_UNKNOWN(key
);
821 IUnknown
*unk
= NULL
;
828 IUnknown_QueryInterface(src
, &IID_IUnknown
, (void**)&unk
);
831 return CTL_E_ILLEGALFUNCTIONCALL
;
833 V_I4(hash
) = get_ptr_hash(unk
);
834 IUnknown_Release(unk
);
837 case VT_DATE
|VT_BYREF
:
839 return get_flt_hash(V_VT(key
) & VT_BYREF
? *V_DATEREF(key
) : V_DATE(key
), &V_I4(hash
));
842 return get_flt_hash(V_VT(key
) & VT_BYREF
? *V_R4REF(key
) : V_R4(key
), &V_I4(hash
));
845 return get_flt_hash(V_VT(key
) & VT_BYREF
? *V_R8REF(key
) : V_R8(key
), &V_I4(hash
));
853 return CTL_E_ILLEGALFUNCTIONCALL
;
855 FIXME("not implemented for type %d\n", V_VT(key
));
862 static const struct IDictionaryVtbl dictionary_vtbl
=
864 dictionary_QueryInterface
,
867 dictionary_GetTypeInfoCount
,
868 dictionary_GetTypeInfo
,
869 dictionary_GetIDsOfNames
,
871 dictionary_putref_Item
,
875 dictionary_get_Count
,
881 dictionary_RemoveAll
,
882 dictionary_put_CompareMode
,
883 dictionary_get_CompareMode
,
885 dictionary_get_HashVal
888 HRESULT WINAPI
Dictionary_CreateInstance(IClassFactory
*factory
,IUnknown
*outer
,REFIID riid
, void **obj
)
892 TRACE("(%p, %p, %s, %p)\n", factory
, outer
, debugstr_guid(riid
), obj
);
896 This
= heap_alloc(sizeof(*This
));
897 if(!This
) return E_OUTOFMEMORY
;
899 This
->IDictionary_iface
.lpVtbl
= &dictionary_vtbl
;
901 This
->method
= BinaryCompare
;
903 list_init(&This
->pairs
);
904 list_init(&This
->notifier
);
905 memset(This
->buckets
, 0, sizeof(This
->buckets
));
907 init_classinfo(&CLSID_Dictionary
, (IUnknown
*)&This
->IDictionary_iface
, &This
->classinfo
);
908 *obj
= &This
->IDictionary_iface
;