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
22 #include "wine/port.h"
32 #include "scrrun_private.h"
34 #include "wine/debug.h"
35 #include "wine/unicode.h"
36 #include "wine/list.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(scrrun
);
40 #define BUCKET_COUNT 509
41 #define DICT_HASH_MOD 1201
43 /* Implementation details
45 Dictionary contains one list that links all pairs, this way
46 order in which they were added is preserved. Each bucket has
47 its own list to hold all pairs in this bucket. Initially all
48 bucket lists are zeroed and we init them once we about to add
51 When pair is removed it's unlinked from both lists; if it was
52 a last pair in a bucket list it stays empty in initialized state.
54 Preserving pair order is important for enumeration, so far testing
55 indicates that pairs are not reordered basing on hash value.
68 struct provideclassinfo classinfo
;
69 IDictionary IDictionary_iface
;
75 struct list buckets
[BUCKET_COUNT
];
79 struct dictionary_enum
{
80 IEnumVARIANT IEnumVARIANT_iface
;
88 static inline dictionary
*impl_from_IDictionary(IDictionary
*iface
)
90 return CONTAINING_RECORD(iface
, dictionary
, IDictionary_iface
);
93 static inline struct dictionary_enum
*impl_from_IEnumVARIANT(IEnumVARIANT
*iface
)
95 return CONTAINING_RECORD(iface
, struct dictionary_enum
, IEnumVARIANT_iface
);
98 static inline struct list
*get_bucket_head(dictionary
*dict
, DWORD hash
)
100 return &dict
->buckets
[hash
% BUCKET_COUNT
];
103 static inline BOOL
is_string_key(const VARIANT
*key
)
105 return V_VT(key
) == VT_BSTR
|| V_VT(key
) == (VT_BSTR
|VT_BYREF
);
108 /* Only for VT_BSTR or VT_BSTR|VT_BYREF types */
109 static inline WCHAR
*get_key_strptr(const VARIANT
*key
)
111 if (V_VT(key
) == VT_BSTR
)
115 return *V_BSTRREF(key
);
120 /* should be used only when both keys are of string type, it's not checked */
121 static inline int strcmp_key(const dictionary
*dict
, const VARIANT
*key1
, const VARIANT
*key2
)
123 const WCHAR
*str1
, *str2
;
125 str1
= get_key_strptr(key1
);
126 str2
= get_key_strptr(key2
);
127 return dict
->method
== BinaryCompare
? strcmpW(str1
, str2
) : strcmpiW(str1
, str2
);
130 static BOOL
is_matching_key(const dictionary
*dict
, const struct keyitem_pair
*pair
, const VARIANT
*key
, DWORD hash
)
132 if (is_string_key(key
) && is_string_key(&pair
->key
)) {
133 if (hash
!= pair
->hash
)
136 return strcmp_key(dict
, key
, &pair
->key
) == 0;
139 if ((is_string_key(key
) && !is_string_key(&pair
->key
)) ||
140 (!is_string_key(key
) && is_string_key(&pair
->key
)))
143 /* for numeric keys only check hash */
144 return hash
== pair
->hash
;
147 static struct keyitem_pair
*get_keyitem_pair(dictionary
*dict
, VARIANT
*key
)
149 struct keyitem_pair
*pair
;
150 struct list
*head
, *entry
;
154 hr
= IDictionary_get_HashVal(&dict
->IDictionary_iface
, key
, &hash
);
158 head
= get_bucket_head(dict
, V_I4(&hash
));
159 if (!head
->next
|| list_empty(head
))
162 entry
= list_head(head
);
164 pair
= LIST_ENTRY(entry
, struct keyitem_pair
, bucket
);
165 if (is_matching_key(dict
, pair
, key
, V_I4(&hash
))) return pair
;
166 } while ((entry
= list_next(head
, entry
)));
171 static HRESULT
add_keyitem_pair(dictionary
*dict
, VARIANT
*key
, VARIANT
*item
)
173 struct keyitem_pair
*pair
;
178 hr
= IDictionary_get_HashVal(&dict
->IDictionary_iface
, key
, &hash
);
182 pair
= heap_alloc(sizeof(*pair
));
184 return E_OUTOFMEMORY
;
186 pair
->hash
= V_I4(&hash
);
187 VariantInit(&pair
->key
);
188 VariantInit(&pair
->item
);
190 hr
= VariantCopyInd(&pair
->key
, key
);
194 hr
= VariantCopyInd(&pair
->item
, item
);
198 head
= get_bucket_head(dict
, pair
->hash
);
200 /* this only happens once per bucket */
203 /* link to bucket list and to full list */
204 list_add_tail(head
, &pair
->bucket
);
205 list_add_tail(&dict
->pairs
, &pair
->entry
);
210 VariantClear(&pair
->key
);
211 VariantClear(&pair
->item
);
216 static void free_keyitem_pair(struct keyitem_pair
*pair
)
218 VariantClear(&pair
->key
);
219 VariantClear(&pair
->item
);
223 static HRESULT WINAPI
dict_enum_QueryInterface(IEnumVARIANT
*iface
, REFIID riid
, void **obj
)
225 struct dictionary_enum
*This
= impl_from_IEnumVARIANT(iface
);
227 TRACE("(%p)->(%s, %p)\n", This
, debugstr_guid(riid
), obj
);
229 if (IsEqualIID(riid
, &IID_IEnumVARIANT
) || IsEqualIID(riid
, &IID_IUnknown
)) {
231 IEnumVARIANT_AddRef(iface
);
235 WARN("interface not supported %s\n", debugstr_guid(riid
));
237 return E_NOINTERFACE
;
241 static ULONG WINAPI
dict_enum_AddRef(IEnumVARIANT
*iface
)
243 struct dictionary_enum
*This
= impl_from_IEnumVARIANT(iface
);
244 ULONG ref
= InterlockedIncrement(&This
->ref
);
245 TRACE("(%p)->(%u)\n", This
, ref
);
249 static ULONG WINAPI
dict_enum_Release(IEnumVARIANT
*iface
)
251 struct dictionary_enum
*This
= impl_from_IEnumVARIANT(iface
);
252 LONG ref
= InterlockedDecrement(&This
->ref
);
254 TRACE("(%p)->(%u)\n", This
, ref
);
257 list_remove(&This
->notify
);
258 IDictionary_Release(&This
->dict
->IDictionary_iface
);
265 static HRESULT WINAPI
dict_enum_Next(IEnumVARIANT
*iface
, ULONG count
, VARIANT
*keys
, ULONG
*fetched
)
267 struct dictionary_enum
*This
= impl_from_IEnumVARIANT(iface
);
268 struct keyitem_pair
*pair
;
271 TRACE("(%p)->(%u %p %p)\n", This
, count
, keys
, fetched
);
279 while (This
->cur
&& i
< count
) {
280 pair
= LIST_ENTRY(This
->cur
, struct keyitem_pair
, entry
);
281 VariantCopy(&keys
[i
], &pair
->key
);
282 This
->cur
= list_next(&This
->dict
->pairs
, This
->cur
);
289 return i
< count
? S_FALSE
: S_OK
;
292 static HRESULT WINAPI
dict_enum_Skip(IEnumVARIANT
*iface
, ULONG count
)
294 struct dictionary_enum
*This
= impl_from_IEnumVARIANT(iface
);
296 TRACE("(%p)->(%u)\n", This
, count
);
305 This
->cur
= list_next(&This
->dict
->pairs
, This
->cur
);
306 if (!This
->cur
) break;
309 return count
== 0 ? S_OK
: S_FALSE
;
312 static HRESULT WINAPI
dict_enum_Reset(IEnumVARIANT
*iface
)
314 struct dictionary_enum
*This
= impl_from_IEnumVARIANT(iface
);
316 TRACE("(%p)\n", This
);
318 This
->cur
= list_head(&This
->dict
->pairs
);
322 static HRESULT
create_dict_enum(dictionary
*, IUnknown
**);
324 static HRESULT WINAPI
dict_enum_Clone(IEnumVARIANT
*iface
, IEnumVARIANT
**cloned
)
326 struct dictionary_enum
*This
= impl_from_IEnumVARIANT(iface
);
327 TRACE("(%p)->(%p)\n", This
, cloned
);
328 return create_dict_enum(This
->dict
, (IUnknown
**)cloned
);
331 static const IEnumVARIANTVtbl dictenumvtbl
= {
332 dict_enum_QueryInterface
,
341 static HRESULT
create_dict_enum(dictionary
*dict
, IUnknown
**ret
)
343 struct dictionary_enum
*This
;
347 This
= heap_alloc(sizeof(*This
));
349 return E_OUTOFMEMORY
;
351 This
->IEnumVARIANT_iface
.lpVtbl
= &dictenumvtbl
;
353 This
->cur
= list_head(&dict
->pairs
);
354 list_add_tail(&dict
->notifier
, &This
->notify
);
356 IDictionary_AddRef(&dict
->IDictionary_iface
);
358 *ret
= (IUnknown
*)&This
->IEnumVARIANT_iface
;
362 static void notify_remove_pair(struct list
*notifier
, struct list
*pair
)
364 struct dictionary_enum
*dict_enum
;
367 LIST_FOR_EACH(cur
, notifier
) {
368 dict_enum
= LIST_ENTRY(cur
, struct dictionary_enum
, notify
);
370 dict_enum
->cur
= list_head(&dict_enum
->dict
->pairs
);
371 else if (dict_enum
->cur
== pair
) {
372 dict_enum
->cur
= list_next(&dict_enum
->dict
->pairs
, dict_enum
->cur
);
377 static HRESULT WINAPI
dictionary_QueryInterface(IDictionary
*iface
, REFIID riid
, void **obj
)
379 dictionary
*This
= impl_from_IDictionary(iface
);
380 TRACE("(%p)->(%s, %p)\n", This
, debugstr_guid(riid
), obj
);
384 if(IsEqualIID(riid
, &IID_IUnknown
) ||
385 IsEqualIID(riid
, &IID_IDispatch
) ||
386 IsEqualIID(riid
, &IID_IDictionary
))
388 *obj
= &This
->IDictionary_iface
;
390 else if (IsEqualIID(riid
, &IID_IProvideClassInfo
))
392 *obj
= &This
->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 dictionary
*This
= impl_from_IDictionary(iface
);
419 ULONG ref
= InterlockedIncrement(&This
->ref
);
421 TRACE("(%p)->(%u)\n", This
, ref
);
426 static ULONG WINAPI
dictionary_Release(IDictionary
*iface
)
428 dictionary
*This
= impl_from_IDictionary(iface
);
429 ULONG ref
= InterlockedDecrement(&This
->ref
);
431 TRACE("(%p)->(%u)\n", This
, ref
);
434 IDictionary_RemoveAll(iface
);
441 static HRESULT WINAPI
dictionary_GetTypeInfoCount(IDictionary
*iface
, UINT
*pctinfo
)
443 dictionary
*This
= impl_from_IDictionary(iface
);
445 TRACE("(%p)->(%p)\n", This
, pctinfo
);
451 static HRESULT WINAPI
dictionary_GetTypeInfo(IDictionary
*iface
, UINT iTInfo
, LCID lcid
, ITypeInfo
**ppTInfo
)
453 dictionary
*This
= impl_from_IDictionary(iface
);
455 TRACE("(%p)->(%u %u %p)\n", This
, iTInfo
, lcid
, ppTInfo
);
456 return get_typeinfo(IDictionary_tid
, ppTInfo
);
459 static HRESULT WINAPI
dictionary_GetIDsOfNames(IDictionary
*iface
, REFIID riid
, LPOLESTR
*rgszNames
,
460 UINT cNames
, LCID lcid
, DISPID
*rgDispId
)
462 dictionary
*This
= impl_from_IDictionary(iface
);
466 TRACE("(%p)->(%s %p %u %u %p)\n", This
, debugstr_guid(riid
), rgszNames
, cNames
, lcid
, rgDispId
);
468 hr
= get_typeinfo(IDictionary_tid
, &typeinfo
);
471 hr
= ITypeInfo_GetIDsOfNames(typeinfo
, rgszNames
, cNames
, rgDispId
);
472 ITypeInfo_Release(typeinfo
);
478 static HRESULT WINAPI
dictionary_Invoke(IDictionary
*iface
, DISPID dispIdMember
, REFIID riid
,
479 LCID lcid
, WORD wFlags
, DISPPARAMS
*pDispParams
, VARIANT
*pVarResult
,
480 EXCEPINFO
*pExcepInfo
, UINT
*puArgErr
)
482 dictionary
*This
= impl_from_IDictionary(iface
);
486 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This
, dispIdMember
, debugstr_guid(riid
),
487 lcid
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
489 hr
= get_typeinfo(IDictionary_tid
, &typeinfo
);
492 hr
= ITypeInfo_Invoke(typeinfo
, &This
->IDictionary_iface
, dispIdMember
, wFlags
,
493 pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
494 ITypeInfo_Release(typeinfo
);
500 static HRESULT WINAPI
dictionary_putref_Item(IDictionary
*iface
, VARIANT
*Key
, VARIANT
*pRetItem
)
502 dictionary
*This
= impl_from_IDictionary(iface
);
504 FIXME("(%p)->(%p %p)\n", This
, Key
, pRetItem
);
509 static HRESULT WINAPI
dictionary_put_Item(IDictionary
*iface
, VARIANT
*key
, VARIANT
*item
)
511 dictionary
*This
= impl_from_IDictionary(iface
);
512 struct keyitem_pair
*pair
;
514 TRACE("(%p)->(%s %s)\n", This
, debugstr_variant(key
), debugstr_variant(item
));
516 if ((pair
= get_keyitem_pair(This
, key
)))
517 return VariantCopyInd(&pair
->item
, item
);
519 return IDictionary_Add(iface
, key
, item
);
522 static HRESULT WINAPI
dictionary_get_Item(IDictionary
*iface
, VARIANT
*key
, VARIANT
*item
)
524 dictionary
*This
= impl_from_IDictionary(iface
);
525 struct keyitem_pair
*pair
;
527 TRACE("(%p)->(%s %p)\n", This
, debugstr_variant(key
), item
);
529 if ((pair
= get_keyitem_pair(This
, key
)))
530 VariantCopy(item
, &pair
->item
);
533 return IDictionary_Add(iface
, key
, item
);
539 static HRESULT WINAPI
dictionary_Add(IDictionary
*iface
, VARIANT
*key
, VARIANT
*item
)
541 dictionary
*This
= impl_from_IDictionary(iface
);
543 TRACE("(%p)->(%s %s)\n", This
, debugstr_variant(key
), debugstr_variant(item
));
545 if (get_keyitem_pair(This
, key
))
546 return CTL_E_KEY_ALREADY_EXISTS
;
548 return add_keyitem_pair(This
, key
, item
);
551 static HRESULT WINAPI
dictionary_get_Count(IDictionary
*iface
, LONG
*count
)
553 dictionary
*This
= impl_from_IDictionary(iface
);
555 TRACE("(%p)->(%p)\n", This
, count
);
557 *count
= This
->count
;
561 static HRESULT WINAPI
dictionary_Exists(IDictionary
*iface
, VARIANT
*key
, VARIANT_BOOL
*exists
)
563 dictionary
*This
= impl_from_IDictionary(iface
);
565 TRACE("(%p)->(%s %p)\n", This
, debugstr_variant(key
), exists
);
568 return CTL_E_ILLEGALFUNCTIONCALL
;
570 *exists
= get_keyitem_pair(This
, key
) != NULL
? VARIANT_TRUE
: VARIANT_FALSE
;
574 static HRESULT WINAPI
dictionary_Items(IDictionary
*iface
, VARIANT
*items
)
576 dictionary
*This
= impl_from_IDictionary(iface
);
577 struct keyitem_pair
*pair
;
578 SAFEARRAYBOUND bound
;
584 TRACE("(%p)->(%p)\n", This
, items
);
590 bound
.cElements
= This
->count
;
591 sa
= SafeArrayCreate(VT_VARIANT
, 1, &bound
);
593 return E_OUTOFMEMORY
;
595 hr
= SafeArrayAccessData(sa
, (void**)&v
);
597 SafeArrayDestroy(sa
);
602 LIST_FOR_EACH_ENTRY(pair
, &This
->pairs
, struct keyitem_pair
, entry
) {
603 VariantCopy(&v
[i
], &pair
->item
);
606 SafeArrayUnaccessData(sa
);
608 V_VT(items
) = VT_ARRAY
|VT_VARIANT
;
613 static HRESULT WINAPI
dictionary_put_Key(IDictionary
*iface
, VARIANT
*key
, VARIANT
*newkey
)
615 dictionary
*This
= impl_from_IDictionary(iface
);
616 struct keyitem_pair
*pair
;
620 TRACE("(%p)->(%s %s)\n", This
, debugstr_variant(key
), debugstr_variant(newkey
));
622 if ((pair
= get_keyitem_pair(This
, key
))) {
623 /* found existing pair for a key, add new pair with new key
624 and old item and remove old pair after that */
626 hr
= IDictionary_Add(iface
, newkey
, &pair
->item
);
630 return IDictionary_Remove(iface
, key
);
634 return IDictionary_Add(iface
, newkey
, &empty
);
637 static HRESULT WINAPI
dictionary_Keys(IDictionary
*iface
, VARIANT
*keys
)
639 dictionary
*This
= impl_from_IDictionary(iface
);
640 struct keyitem_pair
*pair
;
641 SAFEARRAYBOUND bound
;
647 TRACE("(%p)->(%p)\n", This
, keys
);
653 bound
.cElements
= This
->count
;
654 sa
= SafeArrayCreate(VT_VARIANT
, 1, &bound
);
656 return E_OUTOFMEMORY
;
658 hr
= SafeArrayAccessData(sa
, (void**)&v
);
660 SafeArrayDestroy(sa
);
665 LIST_FOR_EACH_ENTRY(pair
, &This
->pairs
, struct keyitem_pair
, entry
) {
666 VariantCopy(&v
[i
], &pair
->key
);
669 SafeArrayUnaccessData(sa
);
671 V_VT(keys
) = VT_ARRAY
|VT_VARIANT
;
676 static HRESULT WINAPI
dictionary_Remove(IDictionary
*iface
, VARIANT
*key
)
678 dictionary
*This
= impl_from_IDictionary(iface
);
679 struct keyitem_pair
*pair
;
681 TRACE("(%p)->(%s)\n", This
, debugstr_variant(key
));
683 if (!(pair
= get_keyitem_pair(This
, key
)))
684 return CTL_E_ELEMENT_NOT_FOUND
;
686 notify_remove_pair(&This
->notifier
, &pair
->entry
);
687 list_remove(&pair
->entry
);
688 list_remove(&pair
->bucket
);
691 free_keyitem_pair(pair
);
695 static HRESULT WINAPI
dictionary_RemoveAll(IDictionary
*iface
)
697 dictionary
*This
= impl_from_IDictionary(iface
);
698 struct keyitem_pair
*pair
, *pair2
;
700 TRACE("(%p)\n", This
);
702 if (This
->count
== 0)
705 notify_remove_pair(&This
->notifier
, NULL
);
706 LIST_FOR_EACH_ENTRY_SAFE(pair
, pair2
, &This
->pairs
, struct keyitem_pair
, entry
) {
707 list_remove(&pair
->entry
);
708 list_remove(&pair
->bucket
);
709 free_keyitem_pair(pair
);
716 static HRESULT WINAPI
dictionary_put_CompareMode(IDictionary
*iface
, CompareMethod method
)
718 dictionary
*This
= impl_from_IDictionary(iface
);
720 TRACE("(%p)->(%d)\n", This
, method
);
723 return CTL_E_ILLEGALFUNCTIONCALL
;
725 This
->method
= method
;
729 static HRESULT WINAPI
dictionary_get_CompareMode(IDictionary
*iface
, CompareMethod
*method
)
731 dictionary
*This
= impl_from_IDictionary(iface
);
733 TRACE("(%p)->(%p)\n", This
, method
);
735 *method
= This
->method
;
739 static HRESULT WINAPI
dictionary__NewEnum(IDictionary
*iface
, IUnknown
**ret
)
741 dictionary
*This
= impl_from_IDictionary(iface
);
743 TRACE("(%p)->(%p)\n", This
, ret
);
745 return create_dict_enum(This
, ret
);
748 static DWORD
get_str_hash(const WCHAR
*str
, CompareMethod method
)
756 ch
= (method
== TextCompare
|| method
== DatabaseCompare
) ? tolowerW(*str
) : *str
;
758 hash
+= (hash
<< 4) + ch
;
763 return hash
% DICT_HASH_MOD
;
766 static DWORD
get_num_hash(FLOAT num
)
768 return (*((DWORD
*)&num
)) % DICT_HASH_MOD
;
771 static HRESULT
get_flt_hash(FLOAT flt
, LONG
*hash
)
777 else if (!isnan(flt
)) {
778 *hash
= get_num_hash(flt
);
784 return CTL_E_ILLEGALFUNCTIONCALL
;
787 static DWORD
get_ptr_hash(void *ptr
)
789 return PtrToUlong(ptr
) % DICT_HASH_MOD
;
792 static HRESULT WINAPI
dictionary_get_HashVal(IDictionary
*iface
, VARIANT
*key
, VARIANT
*hash
)
794 dictionary
*This
= impl_from_IDictionary(iface
);
796 TRACE("(%p)->(%s %p)\n", This
, debugstr_variant(key
), hash
);
801 case VT_BSTR
|VT_BYREF
:
803 V_I4(hash
) = get_str_hash(get_key_strptr(key
), This
->method
);
805 case VT_UI1
|VT_BYREF
:
807 V_I4(hash
) = get_num_hash(V_VT(key
) & VT_BYREF
? *V_UI1REF(key
) : V_UI1(key
));
811 V_I4(hash
) = get_num_hash(V_VT(key
) & VT_BYREF
? *V_I2REF(key
) : V_I2(key
));
815 V_I4(hash
) = get_num_hash(V_VT(key
) & VT_BYREF
? *V_I4REF(key
) : V_I4(key
));
817 case VT_UNKNOWN
|VT_BYREF
:
818 case VT_DISPATCH
|VT_BYREF
:
822 IUnknown
*src
= (V_VT(key
) & VT_BYREF
) ? *V_UNKNOWNREF(key
) : V_UNKNOWN(key
);
823 IUnknown
*unk
= NULL
;
830 IUnknown_QueryInterface(src
, &IID_IUnknown
, (void**)&unk
);
833 return CTL_E_ILLEGALFUNCTIONCALL
;
835 V_I4(hash
) = get_ptr_hash(unk
);
836 IUnknown_Release(unk
);
839 case VT_DATE
|VT_BYREF
:
841 return get_flt_hash(V_VT(key
) & VT_BYREF
? *V_DATEREF(key
) : V_DATE(key
), &V_I4(hash
));
844 return get_flt_hash(V_VT(key
) & VT_BYREF
? *V_R4REF(key
) : V_R4(key
), &V_I4(hash
));
847 return get_flt_hash(V_VT(key
) & VT_BYREF
? *V_R8REF(key
) : V_R8(key
), &V_I4(hash
));
855 return CTL_E_ILLEGALFUNCTIONCALL
;
857 FIXME("not implemented for type %d\n", V_VT(key
));
864 static const struct IDictionaryVtbl dictionary_vtbl
=
866 dictionary_QueryInterface
,
869 dictionary_GetTypeInfoCount
,
870 dictionary_GetTypeInfo
,
871 dictionary_GetIDsOfNames
,
873 dictionary_putref_Item
,
877 dictionary_get_Count
,
883 dictionary_RemoveAll
,
884 dictionary_put_CompareMode
,
885 dictionary_get_CompareMode
,
887 dictionary_get_HashVal
890 HRESULT WINAPI
Dictionary_CreateInstance(IClassFactory
*factory
,IUnknown
*outer
,REFIID riid
, void **obj
)
894 TRACE("(%p, %p, %s, %p)\n", factory
, outer
, debugstr_guid(riid
), obj
);
898 This
= heap_alloc(sizeof(*This
));
899 if(!This
) return E_OUTOFMEMORY
;
901 This
->IDictionary_iface
.lpVtbl
= &dictionary_vtbl
;
903 This
->method
= BinaryCompare
;
905 list_init(&This
->pairs
);
906 list_init(&This
->notifier
);
907 memset(This
->buckets
, 0, sizeof(This
->buckets
));
909 init_classinfo(&CLSID_Dictionary
, (IUnknown
*)&This
->IDictionary_iface
, &This
->classinfo
);
910 *obj
= &This
->IDictionary_iface
;