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.
65 struct provideclassinfo classinfo
;
66 IDictionary IDictionary_iface
;
72 struct list buckets
[BUCKET_COUNT
];
76 struct dictionary_enum
{
77 IEnumVARIANT IEnumVARIANT_iface
;
85 static inline dictionary
*impl_from_IDictionary(IDictionary
*iface
)
87 return CONTAINING_RECORD(iface
, dictionary
, IDictionary_iface
);
90 static inline struct dictionary_enum
*impl_from_IEnumVARIANT(IEnumVARIANT
*iface
)
92 return CONTAINING_RECORD(iface
, struct dictionary_enum
, IEnumVARIANT_iface
);
95 static inline struct list
*get_bucket_head(dictionary
*dict
, DWORD hash
)
97 return &dict
->buckets
[hash
% BUCKET_COUNT
];
100 static inline BOOL
is_string_key(const VARIANT
*key
)
102 return V_VT(key
) == VT_BSTR
|| V_VT(key
) == (VT_BSTR
|VT_BYREF
);
105 /* Only for VT_BSTR or VT_BSTR|VT_BYREF types */
106 static inline WCHAR
*get_key_strptr(const VARIANT
*key
)
108 if (V_VT(key
) == VT_BSTR
)
112 return *V_BSTRREF(key
);
117 /* should be used only when both keys are of string type, it's not checked */
118 static inline int strcmp_key(const dictionary
*dict
, const VARIANT
*key1
, const VARIANT
*key2
)
120 const WCHAR
*str1
, *str2
;
122 str1
= get_key_strptr(key1
);
123 str2
= get_key_strptr(key2
);
124 return dict
->method
== BinaryCompare
? wcscmp(str1
, str2
) : wcsicmp(str1
, str2
);
127 static BOOL
is_matching_key(const dictionary
*dict
, const struct keyitem_pair
*pair
, const VARIANT
*key
, DWORD hash
)
129 if (is_string_key(key
) && is_string_key(&pair
->key
)) {
130 if (hash
!= pair
->hash
)
133 return strcmp_key(dict
, key
, &pair
->key
) == 0;
136 if ((is_string_key(key
) && !is_string_key(&pair
->key
)) ||
137 (!is_string_key(key
) && is_string_key(&pair
->key
)))
140 /* for numeric keys only check hash */
141 return hash
== pair
->hash
;
144 static struct keyitem_pair
*get_keyitem_pair(dictionary
*dict
, VARIANT
*key
)
146 struct keyitem_pair
*pair
;
147 struct list
*head
, *entry
;
151 hr
= IDictionary_get_HashVal(&dict
->IDictionary_iface
, key
, &hash
);
155 head
= get_bucket_head(dict
, V_I4(&hash
));
156 if (!head
->next
|| list_empty(head
))
159 entry
= list_head(head
);
161 pair
= LIST_ENTRY(entry
, struct keyitem_pair
, bucket
);
162 if (is_matching_key(dict
, pair
, key
, V_I4(&hash
))) return pair
;
163 } while ((entry
= list_next(head
, entry
)));
168 static HRESULT
add_keyitem_pair(dictionary
*dict
, VARIANT
*key
, VARIANT
*item
)
170 struct keyitem_pair
*pair
;
175 hr
= IDictionary_get_HashVal(&dict
->IDictionary_iface
, key
, &hash
);
179 if (!(pair
= malloc(sizeof(*pair
))))
180 return E_OUTOFMEMORY
;
182 pair
->hash
= V_I4(&hash
);
183 VariantInit(&pair
->key
);
184 VariantInit(&pair
->item
);
186 hr
= VariantCopyInd(&pair
->key
, key
);
190 hr
= VariantCopyInd(&pair
->item
, item
);
194 head
= get_bucket_head(dict
, pair
->hash
);
196 /* this only happens once per bucket */
199 /* link to bucket list and to full list */
200 list_add_tail(head
, &pair
->bucket
);
201 list_add_tail(&dict
->pairs
, &pair
->entry
);
206 VariantClear(&pair
->key
);
207 VariantClear(&pair
->item
);
212 static void free_keyitem_pair(struct keyitem_pair
*pair
)
214 VariantClear(&pair
->key
);
215 VariantClear(&pair
->item
);
219 static HRESULT WINAPI
dict_enum_QueryInterface(IEnumVARIANT
*iface
, REFIID riid
, void **obj
)
221 struct dictionary_enum
*This
= impl_from_IEnumVARIANT(iface
);
223 TRACE("(%p)->(%s, %p)\n", This
, debugstr_guid(riid
), obj
);
225 if (IsEqualIID(riid
, &IID_IEnumVARIANT
) || IsEqualIID(riid
, &IID_IUnknown
)) {
227 IEnumVARIANT_AddRef(iface
);
231 WARN("interface not supported %s\n", debugstr_guid(riid
));
233 return E_NOINTERFACE
;
237 static ULONG WINAPI
dict_enum_AddRef(IEnumVARIANT
*iface
)
239 struct dictionary_enum
*This
= impl_from_IEnumVARIANT(iface
);
240 ULONG ref
= InterlockedIncrement(&This
->ref
);
241 TRACE("(%p)->(%u)\n", This
, ref
);
245 static ULONG WINAPI
dict_enum_Release(IEnumVARIANT
*iface
)
247 struct dictionary_enum
*This
= impl_from_IEnumVARIANT(iface
);
248 LONG ref
= InterlockedDecrement(&This
->ref
);
250 TRACE("(%p)->(%u)\n", This
, ref
);
254 list_remove(&This
->notify
);
255 IDictionary_Release(&This
->dict
->IDictionary_iface
);
262 static HRESULT WINAPI
dict_enum_Next(IEnumVARIANT
*iface
, ULONG count
, VARIANT
*keys
, ULONG
*fetched
)
264 struct dictionary_enum
*This
= impl_from_IEnumVARIANT(iface
);
265 struct keyitem_pair
*pair
;
268 TRACE("(%p)->(%u %p %p)\n", This
, count
, keys
, fetched
);
276 while (This
->cur
&& i
< count
) {
277 pair
= LIST_ENTRY(This
->cur
, struct keyitem_pair
, entry
);
278 VariantCopy(&keys
[i
], &pair
->key
);
279 This
->cur
= list_next(&This
->dict
->pairs
, This
->cur
);
286 return i
< count
? S_FALSE
: S_OK
;
289 static HRESULT WINAPI
dict_enum_Skip(IEnumVARIANT
*iface
, ULONG count
)
291 struct dictionary_enum
*This
= impl_from_IEnumVARIANT(iface
);
293 TRACE("(%p)->(%u)\n", This
, count
);
302 This
->cur
= list_next(&This
->dict
->pairs
, This
->cur
);
303 if (!This
->cur
) break;
306 return count
== 0 ? S_OK
: S_FALSE
;
309 static HRESULT WINAPI
dict_enum_Reset(IEnumVARIANT
*iface
)
311 struct dictionary_enum
*This
= impl_from_IEnumVARIANT(iface
);
313 TRACE("(%p)\n", This
);
315 This
->cur
= list_head(&This
->dict
->pairs
);
319 static HRESULT
create_dict_enum(dictionary
*, IUnknown
**);
321 static HRESULT WINAPI
dict_enum_Clone(IEnumVARIANT
*iface
, IEnumVARIANT
**cloned
)
323 struct dictionary_enum
*This
= impl_from_IEnumVARIANT(iface
);
324 TRACE("(%p)->(%p)\n", This
, cloned
);
325 return create_dict_enum(This
->dict
, (IUnknown
**)cloned
);
328 static const IEnumVARIANTVtbl dictenumvtbl
= {
329 dict_enum_QueryInterface
,
338 static HRESULT
create_dict_enum(dictionary
*dict
, IUnknown
**ret
)
340 struct dictionary_enum
*object
;
344 if (!(object
= calloc(1, sizeof(*object
))))
345 return E_OUTOFMEMORY
;
347 object
->IEnumVARIANT_iface
.lpVtbl
= &dictenumvtbl
;
349 object
->cur
= list_head(&dict
->pairs
);
350 list_add_tail(&dict
->notifier
, &object
->notify
);
352 IDictionary_AddRef(&dict
->IDictionary_iface
);
354 *ret
= (IUnknown
*)&object
->IEnumVARIANT_iface
;
359 static void notify_remove_pair(struct list
*notifier
, struct list
*pair
)
361 struct dictionary_enum
*dict_enum
;
364 LIST_FOR_EACH(cur
, notifier
) {
365 dict_enum
= LIST_ENTRY(cur
, struct dictionary_enum
, notify
);
367 dict_enum
->cur
= list_head(&dict_enum
->dict
->pairs
);
368 else if (dict_enum
->cur
== pair
) {
369 dict_enum
->cur
= list_next(&dict_enum
->dict
->pairs
, dict_enum
->cur
);
374 static HRESULT WINAPI
dictionary_QueryInterface(IDictionary
*iface
, REFIID riid
, void **obj
)
376 dictionary
*This
= impl_from_IDictionary(iface
);
377 TRACE("(%p)->(%s, %p)\n", This
, debugstr_guid(riid
), obj
);
381 if(IsEqualIID(riid
, &IID_IUnknown
) ||
382 IsEqualIID(riid
, &IID_IDispatch
) ||
383 IsEqualIID(riid
, &IID_IDictionary
))
385 *obj
= &This
->IDictionary_iface
;
387 else if (IsEqualIID(riid
, &IID_IProvideClassInfo
))
389 *obj
= &This
->classinfo
.IProvideClassInfo_iface
;
391 else if ( IsEqualGUID( riid
, &IID_IDispatchEx
))
393 TRACE("Interface IDispatchEx not supported - returning NULL\n");
395 return E_NOINTERFACE
;
397 else if ( IsEqualGUID( riid
, &IID_IObjectWithSite
))
399 TRACE("Interface IObjectWithSite not supported - returning NULL\n");
401 return E_NOINTERFACE
;
405 WARN("interface %s not implemented\n", debugstr_guid(riid
));
406 return E_NOINTERFACE
;
409 IUnknown_AddRef((IUnknown
*)*obj
);
413 static ULONG WINAPI
dictionary_AddRef(IDictionary
*iface
)
415 dictionary
*This
= impl_from_IDictionary(iface
);
416 ULONG ref
= InterlockedIncrement(&This
->ref
);
418 TRACE("(%p)->(%u)\n", This
, ref
);
423 static ULONG WINAPI
dictionary_Release(IDictionary
*iface
)
425 dictionary
*dictionary
= impl_from_IDictionary(iface
);
426 ULONG ref
= InterlockedDecrement(&dictionary
->ref
);
428 TRACE("%p, refcount %u.\n", iface
, 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 **ret
)
892 TRACE("(%p, %p, %s, %p)\n", factory
, outer
, debugstr_guid(riid
), ret
);
896 if (!(object
= calloc(1, sizeof(*object
))))
897 return E_OUTOFMEMORY
;
899 object
->IDictionary_iface
.lpVtbl
= &dictionary_vtbl
;
901 object
->method
= BinaryCompare
;
902 list_init(&object
->pairs
);
903 list_init(&object
->notifier
);
905 init_classinfo(&CLSID_Dictionary
, (IUnknown
*)&object
->IDictionary_iface
, &object
->classinfo
);
907 *ret
= &object
->IDictionary_iface
;