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/heap.h"
37 #include "wine/list.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(scrrun
);
41 #define BUCKET_COUNT 509
42 #define DICT_HASH_MOD 1201
44 /* Implementation details
46 Dictionary contains one list that links all pairs, this way
47 order in which they were added is preserved. Each bucket has
48 its own list to hold all pairs in this bucket. Initially all
49 bucket lists are zeroed and we init them once we about to add
52 When pair is removed it's unlinked from both lists; if it was
53 a last pair in a bucket list it stays empty in initialized state.
55 Preserving pair order is important for enumeration, so far testing
56 indicates that pairs are not reordered basing on hash value.
69 struct provideclassinfo classinfo
;
70 IDictionary IDictionary_iface
;
76 struct list buckets
[BUCKET_COUNT
];
80 struct dictionary_enum
{
81 IEnumVARIANT IEnumVARIANT_iface
;
89 static inline dictionary
*impl_from_IDictionary(IDictionary
*iface
)
91 return CONTAINING_RECORD(iface
, dictionary
, IDictionary_iface
);
94 static inline struct dictionary_enum
*impl_from_IEnumVARIANT(IEnumVARIANT
*iface
)
96 return CONTAINING_RECORD(iface
, struct dictionary_enum
, IEnumVARIANT_iface
);
99 static inline struct list
*get_bucket_head(dictionary
*dict
, DWORD hash
)
101 return &dict
->buckets
[hash
% BUCKET_COUNT
];
104 static inline BOOL
is_string_key(const VARIANT
*key
)
106 return V_VT(key
) == VT_BSTR
|| V_VT(key
) == (VT_BSTR
|VT_BYREF
);
109 /* Only for VT_BSTR or VT_BSTR|VT_BYREF types */
110 static inline WCHAR
*get_key_strptr(const VARIANT
*key
)
112 if (V_VT(key
) == VT_BSTR
)
116 return *V_BSTRREF(key
);
121 /* should be used only when both keys are of string type, it's not checked */
122 static inline int strcmp_key(const dictionary
*dict
, const VARIANT
*key1
, const VARIANT
*key2
)
124 const WCHAR
*str1
, *str2
;
126 str1
= get_key_strptr(key1
);
127 str2
= get_key_strptr(key2
);
128 return dict
->method
== BinaryCompare
? strcmpW(str1
, str2
) : strcmpiW(str1
, str2
);
131 static BOOL
is_matching_key(const dictionary
*dict
, const struct keyitem_pair
*pair
, const VARIANT
*key
, DWORD hash
)
133 if (is_string_key(key
) && is_string_key(&pair
->key
)) {
134 if (hash
!= pair
->hash
)
137 return strcmp_key(dict
, key
, &pair
->key
) == 0;
140 if ((is_string_key(key
) && !is_string_key(&pair
->key
)) ||
141 (!is_string_key(key
) && is_string_key(&pair
->key
)))
144 /* for numeric keys only check hash */
145 return hash
== pair
->hash
;
148 static struct keyitem_pair
*get_keyitem_pair(dictionary
*dict
, VARIANT
*key
)
150 struct keyitem_pair
*pair
;
151 struct list
*head
, *entry
;
155 hr
= IDictionary_get_HashVal(&dict
->IDictionary_iface
, key
, &hash
);
159 head
= get_bucket_head(dict
, V_I4(&hash
));
160 if (!head
->next
|| list_empty(head
))
163 entry
= list_head(head
);
165 pair
= LIST_ENTRY(entry
, struct keyitem_pair
, bucket
);
166 if (is_matching_key(dict
, pair
, key
, V_I4(&hash
))) return pair
;
167 } while ((entry
= list_next(head
, entry
)));
172 static HRESULT
add_keyitem_pair(dictionary
*dict
, VARIANT
*key
, VARIANT
*item
)
174 struct keyitem_pair
*pair
;
179 hr
= IDictionary_get_HashVal(&dict
->IDictionary_iface
, key
, &hash
);
183 pair
= heap_alloc(sizeof(*pair
));
185 return E_OUTOFMEMORY
;
187 pair
->hash
= V_I4(&hash
);
188 VariantInit(&pair
->key
);
189 VariantInit(&pair
->item
);
191 hr
= VariantCopyInd(&pair
->key
, key
);
195 hr
= VariantCopyInd(&pair
->item
, item
);
199 head
= get_bucket_head(dict
, pair
->hash
);
201 /* this only happens once per bucket */
204 /* link to bucket list and to full list */
205 list_add_tail(head
, &pair
->bucket
);
206 list_add_tail(&dict
->pairs
, &pair
->entry
);
211 VariantClear(&pair
->key
);
212 VariantClear(&pair
->item
);
217 static void free_keyitem_pair(struct keyitem_pair
*pair
)
219 VariantClear(&pair
->key
);
220 VariantClear(&pair
->item
);
224 static HRESULT WINAPI
dict_enum_QueryInterface(IEnumVARIANT
*iface
, REFIID riid
, void **obj
)
226 struct dictionary_enum
*This
= impl_from_IEnumVARIANT(iface
);
228 TRACE("(%p)->(%s, %p)\n", This
, debugstr_guid(riid
), obj
);
230 if (IsEqualIID(riid
, &IID_IEnumVARIANT
) || IsEqualIID(riid
, &IID_IUnknown
)) {
232 IEnumVARIANT_AddRef(iface
);
236 WARN("interface not supported %s\n", debugstr_guid(riid
));
238 return E_NOINTERFACE
;
242 static ULONG WINAPI
dict_enum_AddRef(IEnumVARIANT
*iface
)
244 struct dictionary_enum
*This
= impl_from_IEnumVARIANT(iface
);
245 ULONG ref
= InterlockedIncrement(&This
->ref
);
246 TRACE("(%p)->(%u)\n", This
, ref
);
250 static ULONG WINAPI
dict_enum_Release(IEnumVARIANT
*iface
)
252 struct dictionary_enum
*This
= impl_from_IEnumVARIANT(iface
);
253 LONG ref
= InterlockedDecrement(&This
->ref
);
255 TRACE("(%p)->(%u)\n", This
, ref
);
258 list_remove(&This
->notify
);
259 IDictionary_Release(&This
->dict
->IDictionary_iface
);
266 static HRESULT WINAPI
dict_enum_Next(IEnumVARIANT
*iface
, ULONG count
, VARIANT
*keys
, ULONG
*fetched
)
268 struct dictionary_enum
*This
= impl_from_IEnumVARIANT(iface
);
269 struct keyitem_pair
*pair
;
272 TRACE("(%p)->(%u %p %p)\n", This
, count
, keys
, fetched
);
280 while (This
->cur
&& i
< count
) {
281 pair
= LIST_ENTRY(This
->cur
, struct keyitem_pair
, entry
);
282 VariantCopy(&keys
[i
], &pair
->key
);
283 This
->cur
= list_next(&This
->dict
->pairs
, This
->cur
);
290 return i
< count
? S_FALSE
: S_OK
;
293 static HRESULT WINAPI
dict_enum_Skip(IEnumVARIANT
*iface
, ULONG count
)
295 struct dictionary_enum
*This
= impl_from_IEnumVARIANT(iface
);
297 TRACE("(%p)->(%u)\n", This
, count
);
306 This
->cur
= list_next(&This
->dict
->pairs
, This
->cur
);
307 if (!This
->cur
) break;
310 return count
== 0 ? S_OK
: S_FALSE
;
313 static HRESULT WINAPI
dict_enum_Reset(IEnumVARIANT
*iface
)
315 struct dictionary_enum
*This
= impl_from_IEnumVARIANT(iface
);
317 TRACE("(%p)\n", This
);
319 This
->cur
= list_head(&This
->dict
->pairs
);
323 static HRESULT
create_dict_enum(dictionary
*, IUnknown
**);
325 static HRESULT WINAPI
dict_enum_Clone(IEnumVARIANT
*iface
, IEnumVARIANT
**cloned
)
327 struct dictionary_enum
*This
= impl_from_IEnumVARIANT(iface
);
328 TRACE("(%p)->(%p)\n", This
, cloned
);
329 return create_dict_enum(This
->dict
, (IUnknown
**)cloned
);
332 static const IEnumVARIANTVtbl dictenumvtbl
= {
333 dict_enum_QueryInterface
,
342 static HRESULT
create_dict_enum(dictionary
*dict
, IUnknown
**ret
)
344 struct dictionary_enum
*This
;
348 This
= heap_alloc(sizeof(*This
));
350 return E_OUTOFMEMORY
;
352 This
->IEnumVARIANT_iface
.lpVtbl
= &dictenumvtbl
;
354 This
->cur
= list_head(&dict
->pairs
);
355 list_add_tail(&dict
->notifier
, &This
->notify
);
357 IDictionary_AddRef(&dict
->IDictionary_iface
);
359 *ret
= (IUnknown
*)&This
->IEnumVARIANT_iface
;
363 static void notify_remove_pair(struct list
*notifier
, struct list
*pair
)
365 struct dictionary_enum
*dict_enum
;
368 LIST_FOR_EACH(cur
, notifier
) {
369 dict_enum
= LIST_ENTRY(cur
, struct dictionary_enum
, notify
);
371 dict_enum
->cur
= list_head(&dict_enum
->dict
->pairs
);
372 else if (dict_enum
->cur
== pair
) {
373 dict_enum
->cur
= list_next(&dict_enum
->dict
->pairs
, dict_enum
->cur
);
378 static HRESULT WINAPI
dictionary_QueryInterface(IDictionary
*iface
, REFIID riid
, void **obj
)
380 dictionary
*This
= impl_from_IDictionary(iface
);
381 TRACE("(%p)->(%s, %p)\n", This
, debugstr_guid(riid
), obj
);
385 if(IsEqualIID(riid
, &IID_IUnknown
) ||
386 IsEqualIID(riid
, &IID_IDispatch
) ||
387 IsEqualIID(riid
, &IID_IDictionary
))
389 *obj
= &This
->IDictionary_iface
;
391 else if (IsEqualIID(riid
, &IID_IProvideClassInfo
))
393 *obj
= &This
->classinfo
.IProvideClassInfo_iface
;
395 else if ( IsEqualGUID( riid
, &IID_IDispatchEx
))
397 TRACE("Interface IDispatchEx not supported - returning NULL\n");
399 return E_NOINTERFACE
;
401 else if ( IsEqualGUID( riid
, &IID_IObjectWithSite
))
403 TRACE("Interface IObjectWithSite not supported - returning NULL\n");
405 return E_NOINTERFACE
;
409 WARN("interface %s not implemented\n", debugstr_guid(riid
));
410 return E_NOINTERFACE
;
413 IUnknown_AddRef((IUnknown
*)*obj
);
417 static ULONG WINAPI
dictionary_AddRef(IDictionary
*iface
)
419 dictionary
*This
= impl_from_IDictionary(iface
);
420 ULONG ref
= InterlockedIncrement(&This
->ref
);
422 TRACE("(%p)->(%u)\n", This
, ref
);
427 static ULONG WINAPI
dictionary_Release(IDictionary
*iface
)
429 dictionary
*This
= impl_from_IDictionary(iface
);
430 ULONG ref
= InterlockedDecrement(&This
->ref
);
432 TRACE("(%p)->(%u)\n", This
, ref
);
435 IDictionary_RemoveAll(iface
);
442 static HRESULT WINAPI
dictionary_GetTypeInfoCount(IDictionary
*iface
, UINT
*pctinfo
)
444 dictionary
*This
= impl_from_IDictionary(iface
);
446 TRACE("(%p)->(%p)\n", This
, pctinfo
);
452 static HRESULT WINAPI
dictionary_GetTypeInfo(IDictionary
*iface
, UINT iTInfo
, LCID lcid
, ITypeInfo
**ppTInfo
)
454 dictionary
*This
= impl_from_IDictionary(iface
);
456 TRACE("(%p)->(%u %u %p)\n", This
, iTInfo
, lcid
, ppTInfo
);
457 return get_typeinfo(IDictionary_tid
, ppTInfo
);
460 static HRESULT WINAPI
dictionary_GetIDsOfNames(IDictionary
*iface
, REFIID riid
, LPOLESTR
*rgszNames
,
461 UINT cNames
, LCID lcid
, DISPID
*rgDispId
)
463 dictionary
*This
= impl_from_IDictionary(iface
);
467 TRACE("(%p)->(%s %p %u %u %p)\n", This
, debugstr_guid(riid
), rgszNames
, cNames
, lcid
, rgDispId
);
469 hr
= get_typeinfo(IDictionary_tid
, &typeinfo
);
472 hr
= ITypeInfo_GetIDsOfNames(typeinfo
, rgszNames
, cNames
, rgDispId
);
473 ITypeInfo_Release(typeinfo
);
479 static HRESULT WINAPI
dictionary_Invoke(IDictionary
*iface
, DISPID dispIdMember
, REFIID riid
,
480 LCID lcid
, WORD wFlags
, DISPPARAMS
*pDispParams
, VARIANT
*pVarResult
,
481 EXCEPINFO
*pExcepInfo
, UINT
*puArgErr
)
483 dictionary
*This
= impl_from_IDictionary(iface
);
487 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This
, dispIdMember
, debugstr_guid(riid
),
488 lcid
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
490 hr
= get_typeinfo(IDictionary_tid
, &typeinfo
);
493 hr
= ITypeInfo_Invoke(typeinfo
, &This
->IDictionary_iface
, dispIdMember
, wFlags
,
494 pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
495 ITypeInfo_Release(typeinfo
);
501 static HRESULT WINAPI
dictionary_putref_Item(IDictionary
*iface
, VARIANT
*Key
, VARIANT
*pRetItem
)
503 dictionary
*This
= impl_from_IDictionary(iface
);
505 FIXME("(%p)->(%p %p)\n", This
, Key
, pRetItem
);
510 static HRESULT WINAPI
dictionary_put_Item(IDictionary
*iface
, VARIANT
*key
, VARIANT
*item
)
512 dictionary
*This
= impl_from_IDictionary(iface
);
513 struct keyitem_pair
*pair
;
515 TRACE("(%p)->(%s %s)\n", This
, debugstr_variant(key
), debugstr_variant(item
));
517 if ((pair
= get_keyitem_pair(This
, key
)))
518 return VariantCopyInd(&pair
->item
, item
);
520 return IDictionary_Add(iface
, key
, item
);
523 static HRESULT WINAPI
dictionary_get_Item(IDictionary
*iface
, VARIANT
*key
, VARIANT
*item
)
525 dictionary
*This
= impl_from_IDictionary(iface
);
526 struct keyitem_pair
*pair
;
528 TRACE("(%p)->(%s %p)\n", This
, debugstr_variant(key
), item
);
530 if ((pair
= get_keyitem_pair(This
, key
)))
531 VariantCopy(item
, &pair
->item
);
534 return IDictionary_Add(iface
, key
, item
);
540 static HRESULT WINAPI
dictionary_Add(IDictionary
*iface
, VARIANT
*key
, VARIANT
*item
)
542 dictionary
*This
= impl_from_IDictionary(iface
);
544 TRACE("(%p)->(%s %s)\n", This
, debugstr_variant(key
), debugstr_variant(item
));
546 if (get_keyitem_pair(This
, key
))
547 return CTL_E_KEY_ALREADY_EXISTS
;
549 return add_keyitem_pair(This
, key
, item
);
552 static HRESULT WINAPI
dictionary_get_Count(IDictionary
*iface
, LONG
*count
)
554 dictionary
*This
= impl_from_IDictionary(iface
);
556 TRACE("(%p)->(%p)\n", This
, count
);
558 *count
= This
->count
;
562 static HRESULT WINAPI
dictionary_Exists(IDictionary
*iface
, VARIANT
*key
, VARIANT_BOOL
*exists
)
564 dictionary
*This
= impl_from_IDictionary(iface
);
566 TRACE("(%p)->(%s %p)\n", This
, debugstr_variant(key
), exists
);
569 return CTL_E_ILLEGALFUNCTIONCALL
;
571 *exists
= get_keyitem_pair(This
, key
) != NULL
? VARIANT_TRUE
: VARIANT_FALSE
;
575 static HRESULT WINAPI
dictionary_Items(IDictionary
*iface
, VARIANT
*items
)
577 dictionary
*This
= impl_from_IDictionary(iface
);
578 struct keyitem_pair
*pair
;
579 SAFEARRAYBOUND bound
;
585 TRACE("(%p)->(%p)\n", This
, items
);
591 bound
.cElements
= This
->count
;
592 sa
= SafeArrayCreate(VT_VARIANT
, 1, &bound
);
594 return E_OUTOFMEMORY
;
596 hr
= SafeArrayAccessData(sa
, (void**)&v
);
598 SafeArrayDestroy(sa
);
603 LIST_FOR_EACH_ENTRY(pair
, &This
->pairs
, struct keyitem_pair
, entry
) {
604 VariantCopy(&v
[i
], &pair
->item
);
607 SafeArrayUnaccessData(sa
);
609 V_VT(items
) = VT_ARRAY
|VT_VARIANT
;
614 static HRESULT WINAPI
dictionary_put_Key(IDictionary
*iface
, VARIANT
*key
, VARIANT
*newkey
)
616 dictionary
*This
= impl_from_IDictionary(iface
);
617 struct keyitem_pair
*pair
;
621 TRACE("(%p)->(%s %s)\n", This
, debugstr_variant(key
), debugstr_variant(newkey
));
623 if ((pair
= get_keyitem_pair(This
, key
))) {
624 /* found existing pair for a key, add new pair with new key
625 and old item and remove old pair after that */
627 hr
= IDictionary_Add(iface
, newkey
, &pair
->item
);
631 return IDictionary_Remove(iface
, key
);
635 return IDictionary_Add(iface
, newkey
, &empty
);
638 static HRESULT WINAPI
dictionary_Keys(IDictionary
*iface
, VARIANT
*keys
)
640 dictionary
*This
= impl_from_IDictionary(iface
);
641 struct keyitem_pair
*pair
;
642 SAFEARRAYBOUND bound
;
648 TRACE("(%p)->(%p)\n", This
, keys
);
654 bound
.cElements
= This
->count
;
655 sa
= SafeArrayCreate(VT_VARIANT
, 1, &bound
);
657 return E_OUTOFMEMORY
;
659 hr
= SafeArrayAccessData(sa
, (void**)&v
);
661 SafeArrayDestroy(sa
);
666 LIST_FOR_EACH_ENTRY(pair
, &This
->pairs
, struct keyitem_pair
, entry
) {
667 VariantCopy(&v
[i
], &pair
->key
);
670 SafeArrayUnaccessData(sa
);
672 V_VT(keys
) = VT_ARRAY
|VT_VARIANT
;
677 static HRESULT WINAPI
dictionary_Remove(IDictionary
*iface
, VARIANT
*key
)
679 dictionary
*This
= impl_from_IDictionary(iface
);
680 struct keyitem_pair
*pair
;
682 TRACE("(%p)->(%s)\n", This
, debugstr_variant(key
));
684 if (!(pair
= get_keyitem_pair(This
, key
)))
685 return CTL_E_ELEMENT_NOT_FOUND
;
687 notify_remove_pair(&This
->notifier
, &pair
->entry
);
688 list_remove(&pair
->entry
);
689 list_remove(&pair
->bucket
);
692 free_keyitem_pair(pair
);
696 static HRESULT WINAPI
dictionary_RemoveAll(IDictionary
*iface
)
698 dictionary
*This
= impl_from_IDictionary(iface
);
699 struct keyitem_pair
*pair
, *pair2
;
701 TRACE("(%p)\n", This
);
703 if (This
->count
== 0)
706 notify_remove_pair(&This
->notifier
, NULL
);
707 LIST_FOR_EACH_ENTRY_SAFE(pair
, pair2
, &This
->pairs
, struct keyitem_pair
, entry
) {
708 list_remove(&pair
->entry
);
709 list_remove(&pair
->bucket
);
710 free_keyitem_pair(pair
);
717 static HRESULT WINAPI
dictionary_put_CompareMode(IDictionary
*iface
, CompareMethod method
)
719 dictionary
*This
= impl_from_IDictionary(iface
);
721 TRACE("(%p)->(%d)\n", This
, method
);
724 return CTL_E_ILLEGALFUNCTIONCALL
;
726 This
->method
= method
;
730 static HRESULT WINAPI
dictionary_get_CompareMode(IDictionary
*iface
, CompareMethod
*method
)
732 dictionary
*This
= impl_from_IDictionary(iface
);
734 TRACE("(%p)->(%p)\n", This
, method
);
736 *method
= This
->method
;
740 static HRESULT WINAPI
dictionary__NewEnum(IDictionary
*iface
, IUnknown
**ret
)
742 dictionary
*This
= impl_from_IDictionary(iface
);
744 TRACE("(%p)->(%p)\n", This
, ret
);
746 return create_dict_enum(This
, ret
);
749 static DWORD
get_str_hash(const WCHAR
*str
, CompareMethod method
)
757 ch
= (method
== TextCompare
|| method
== DatabaseCompare
) ? tolowerW(*str
) : *str
;
759 hash
+= (hash
<< 4) + ch
;
764 return hash
% DICT_HASH_MOD
;
767 static DWORD
get_num_hash(FLOAT num
)
769 return (*((DWORD
*)&num
)) % DICT_HASH_MOD
;
772 static HRESULT
get_flt_hash(FLOAT flt
, LONG
*hash
)
778 else if (!isnan(flt
)) {
779 *hash
= get_num_hash(flt
);
785 return CTL_E_ILLEGALFUNCTIONCALL
;
788 static DWORD
get_ptr_hash(void *ptr
)
790 return PtrToUlong(ptr
) % DICT_HASH_MOD
;
793 static HRESULT WINAPI
dictionary_get_HashVal(IDictionary
*iface
, VARIANT
*key
, VARIANT
*hash
)
795 dictionary
*This
= impl_from_IDictionary(iface
);
797 TRACE("(%p)->(%s %p)\n", This
, debugstr_variant(key
), hash
);
802 case VT_BSTR
|VT_BYREF
:
804 V_I4(hash
) = get_str_hash(get_key_strptr(key
), This
->method
);
806 case VT_UI1
|VT_BYREF
:
808 V_I4(hash
) = get_num_hash(V_VT(key
) & VT_BYREF
? *V_UI1REF(key
) : V_UI1(key
));
812 V_I4(hash
) = get_num_hash(V_VT(key
) & VT_BYREF
? *V_I2REF(key
) : V_I2(key
));
816 V_I4(hash
) = get_num_hash(V_VT(key
) & VT_BYREF
? *V_I4REF(key
) : V_I4(key
));
818 case VT_UNKNOWN
|VT_BYREF
:
819 case VT_DISPATCH
|VT_BYREF
:
823 IUnknown
*src
= (V_VT(key
) & VT_BYREF
) ? *V_UNKNOWNREF(key
) : V_UNKNOWN(key
);
824 IUnknown
*unk
= NULL
;
831 IUnknown_QueryInterface(src
, &IID_IUnknown
, (void**)&unk
);
834 return CTL_E_ILLEGALFUNCTIONCALL
;
836 V_I4(hash
) = get_ptr_hash(unk
);
837 IUnknown_Release(unk
);
840 case VT_DATE
|VT_BYREF
:
842 return get_flt_hash(V_VT(key
) & VT_BYREF
? *V_DATEREF(key
) : V_DATE(key
), &V_I4(hash
));
845 return get_flt_hash(V_VT(key
) & VT_BYREF
? *V_R4REF(key
) : V_R4(key
), &V_I4(hash
));
848 return get_flt_hash(V_VT(key
) & VT_BYREF
? *V_R8REF(key
) : V_R8(key
), &V_I4(hash
));
856 return CTL_E_ILLEGALFUNCTIONCALL
;
858 FIXME("not implemented for type %d\n", V_VT(key
));
865 static const struct IDictionaryVtbl dictionary_vtbl
=
867 dictionary_QueryInterface
,
870 dictionary_GetTypeInfoCount
,
871 dictionary_GetTypeInfo
,
872 dictionary_GetIDsOfNames
,
874 dictionary_putref_Item
,
878 dictionary_get_Count
,
884 dictionary_RemoveAll
,
885 dictionary_put_CompareMode
,
886 dictionary_get_CompareMode
,
888 dictionary_get_HashVal
891 HRESULT WINAPI
Dictionary_CreateInstance(IClassFactory
*factory
,IUnknown
*outer
,REFIID riid
, void **obj
)
895 TRACE("(%p, %p, %s, %p)\n", factory
, outer
, debugstr_guid(riid
), obj
);
899 This
= heap_alloc(sizeof(*This
));
900 if(!This
) return E_OUTOFMEMORY
;
902 This
->IDictionary_iface
.lpVtbl
= &dictionary_vtbl
;
904 This
->method
= BinaryCompare
;
906 list_init(&This
->pairs
);
907 list_init(&This
->notifier
);
908 memset(This
->buckets
, 0, sizeof(This
->buckets
));
910 init_classinfo(&CLSID_Dictionary
, (IUnknown
*)&This
->IDictionary_iface
, &This
->classinfo
);
911 *obj
= &This
->IDictionary_iface
;