comctl32/tooltips: Reset window subclass data when removing tools.
[wine.git] / dlls / scrrun / dictionary.c
blob7ebf4a4f872dd121bcda22ef0665c9c339015d3f
1 /*
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
19 #define COBJMACROS
21 #include "config.h"
22 #include "wine/port.h"
24 #include <stdarg.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "ole2.h"
29 #include "olectl.h"
30 #include "dispex.h"
31 #include "scrrun.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
49 first pair.
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.
58 struct keyitem_pair {
59 struct list entry;
60 struct list bucket;
61 DWORD hash;
62 VARIANT key;
63 VARIANT item;
66 typedef struct
68 struct provideclassinfo classinfo;
69 IDictionary IDictionary_iface;
70 LONG ref;
72 CompareMethod method;
73 LONG count;
74 struct list pairs;
75 struct list buckets[BUCKET_COUNT];
76 struct list notifier;
77 } dictionary;
79 struct dictionary_enum {
80 IEnumVARIANT IEnumVARIANT_iface;
81 LONG ref;
83 dictionary *dict;
84 struct list *cur;
85 struct list notify;
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)
112 return V_BSTR(key);
114 if (V_BSTRREF(key))
115 return *V_BSTRREF(key);
117 return NULL;
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)
134 return FALSE;
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)))
141 return FALSE;
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;
151 VARIANT hash;
152 HRESULT hr;
154 hr = IDictionary_get_HashVal(&dict->IDictionary_iface, key, &hash);
155 if (FAILED(hr))
156 return NULL;
158 head = get_bucket_head(dict, V_I4(&hash));
159 if (!head->next || list_empty(head))
160 return NULL;
162 entry = list_head(head);
163 do {
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)));
168 return NULL;
171 static HRESULT add_keyitem_pair(dictionary *dict, VARIANT *key, VARIANT *item)
173 struct keyitem_pair *pair;
174 struct list *head;
175 VARIANT hash;
176 HRESULT hr;
178 hr = IDictionary_get_HashVal(&dict->IDictionary_iface, key, &hash);
179 if (FAILED(hr))
180 return hr;
182 pair = heap_alloc(sizeof(*pair));
183 if (!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);
191 if (FAILED(hr))
192 goto failed;
194 hr = VariantCopyInd(&pair->item, item);
195 if (FAILED(hr))
196 goto failed;
198 head = get_bucket_head(dict, pair->hash);
199 if (!head->next)
200 /* this only happens once per bucket */
201 list_init(head);
203 /* link to bucket list and to full list */
204 list_add_tail(head, &pair->bucket);
205 list_add_tail(&dict->pairs, &pair->entry);
206 dict->count++;
207 return S_OK;
209 failed:
210 VariantClear(&pair->key);
211 VariantClear(&pair->item);
212 heap_free(pair);
213 return hr;
216 static void free_keyitem_pair(struct keyitem_pair *pair)
218 VariantClear(&pair->key);
219 VariantClear(&pair->item);
220 heap_free(pair);
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)) {
230 *obj = iface;
231 IEnumVARIANT_AddRef(iface);
232 return S_OK;
234 else {
235 WARN("interface not supported %s\n", debugstr_guid(riid));
236 *obj = NULL;
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);
246 return 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);
256 if (!ref) {
257 list_remove(&This->notify);
258 IDictionary_Release(&This->dict->IDictionary_iface);
259 heap_free(This);
262 return ref;
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;
269 ULONG i = 0;
271 TRACE("(%p)->(%u %p %p)\n", This, count, keys, fetched);
273 if (fetched)
274 *fetched = 0;
276 if (!count)
277 return S_OK;
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);
283 i++;
286 if (fetched)
287 *fetched = i;
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);
298 if (!count)
299 return S_OK;
301 if (!This->cur)
302 return S_FALSE;
304 while (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);
319 return S_OK;
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,
333 dict_enum_AddRef,
334 dict_enum_Release,
335 dict_enum_Next,
336 dict_enum_Skip,
337 dict_enum_Reset,
338 dict_enum_Clone
341 static HRESULT create_dict_enum(dictionary *dict, IUnknown **ret)
343 struct dictionary_enum *This;
345 *ret = NULL;
347 This = heap_alloc(sizeof(*This));
348 if (!This)
349 return E_OUTOFMEMORY;
351 This->IEnumVARIANT_iface.lpVtbl = &dictenumvtbl;
352 This->ref = 1;
353 This->cur = list_head(&dict->pairs);
354 list_add_tail(&dict->notifier, &This->notify);
355 This->dict = dict;
356 IDictionary_AddRef(&dict->IDictionary_iface);
358 *ret = (IUnknown*)&This->IEnumVARIANT_iface;
359 return S_OK;
362 static void notify_remove_pair(struct list *notifier, struct list *pair)
364 struct dictionary_enum *dict_enum;
365 struct list *cur;
367 LIST_FOR_EACH(cur, notifier) {
368 dict_enum = LIST_ENTRY(cur, struct dictionary_enum, notify);
369 if (!pair)
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);
382 *obj = NULL;
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");
397 *obj = NULL;
398 return E_NOINTERFACE;
400 else if ( IsEqualGUID( riid, &IID_IObjectWithSite ))
402 TRACE("Interface IObjectWithSite not supported - returning NULL\n");
403 *obj = NULL;
404 return E_NOINTERFACE;
406 else
408 WARN("interface %s not implemented\n", debugstr_guid(riid));
409 return E_NOINTERFACE;
412 IUnknown_AddRef((IUnknown*)*obj);
413 return S_OK;
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);
423 return 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);
433 if (!ref) {
434 IDictionary_RemoveAll(iface);
435 heap_free(This);
438 return ref;
441 static HRESULT WINAPI dictionary_GetTypeInfoCount(IDictionary *iface, UINT *pctinfo)
443 dictionary *This = impl_from_IDictionary(iface);
445 TRACE("(%p)->(%p)\n", This, pctinfo);
447 *pctinfo = 1;
448 return S_OK;
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);
463 ITypeInfo *typeinfo;
464 HRESULT hr;
466 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
468 hr = get_typeinfo(IDictionary_tid, &typeinfo);
469 if(SUCCEEDED(hr))
471 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
472 ITypeInfo_Release(typeinfo);
475 return hr;
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);
483 ITypeInfo *typeinfo;
484 HRESULT hr;
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);
490 if(SUCCEEDED(hr))
492 hr = ITypeInfo_Invoke(typeinfo, &This->IDictionary_iface, dispIdMember, wFlags,
493 pDispParams, pVarResult, pExcepInfo, puArgErr);
494 ITypeInfo_Release(typeinfo);
497 return hr;
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);
506 return E_NOTIMPL;
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);
531 else {
532 VariantInit(item);
533 return IDictionary_Add(iface, key, item);
536 return S_OK;
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;
558 return S_OK;
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);
567 if (!exists)
568 return CTL_E_ILLEGALFUNCTIONCALL;
570 *exists = get_keyitem_pair(This, key) != NULL ? VARIANT_TRUE : VARIANT_FALSE;
571 return S_OK;
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;
579 SAFEARRAY *sa;
580 VARIANT *v;
581 HRESULT hr;
582 LONG i;
584 TRACE("(%p)->(%p)\n", This, items);
586 if (!items)
587 return S_OK;
589 bound.lLbound = 0;
590 bound.cElements = This->count;
591 sa = SafeArrayCreate(VT_VARIANT, 1, &bound);
592 if (!sa)
593 return E_OUTOFMEMORY;
595 hr = SafeArrayAccessData(sa, (void**)&v);
596 if (FAILED(hr)) {
597 SafeArrayDestroy(sa);
598 return hr;
601 i = 0;
602 LIST_FOR_EACH_ENTRY(pair, &This->pairs, struct keyitem_pair, entry) {
603 VariantCopy(&v[i], &pair->item);
604 i++;
606 SafeArrayUnaccessData(sa);
608 V_VT(items) = VT_ARRAY|VT_VARIANT;
609 V_ARRAY(items) = sa;
610 return S_OK;
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;
617 VARIANT empty;
618 HRESULT hr;
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);
627 if (FAILED(hr))
628 return hr;
630 return IDictionary_Remove(iface, key);
633 VariantInit(&empty);
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;
642 SAFEARRAY *sa;
643 VARIANT *v;
644 HRESULT hr;
645 LONG i;
647 TRACE("(%p)->(%p)\n", This, keys);
649 if (!keys)
650 return S_OK;
652 bound.lLbound = 0;
653 bound.cElements = This->count;
654 sa = SafeArrayCreate(VT_VARIANT, 1, &bound);
655 if (!sa)
656 return E_OUTOFMEMORY;
658 hr = SafeArrayAccessData(sa, (void**)&v);
659 if (FAILED(hr)) {
660 SafeArrayDestroy(sa);
661 return hr;
664 i = 0;
665 LIST_FOR_EACH_ENTRY(pair, &This->pairs, struct keyitem_pair, entry) {
666 VariantCopy(&v[i], &pair->key);
667 i++;
669 SafeArrayUnaccessData(sa);
671 V_VT(keys) = VT_ARRAY|VT_VARIANT;
672 V_ARRAY(keys) = sa;
673 return S_OK;
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);
689 This->count--;
691 free_keyitem_pair(pair);
692 return S_OK;
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)
703 return S_OK;
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);
711 This->count = 0;
713 return S_OK;
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);
722 if (This->count)
723 return CTL_E_ILLEGALFUNCTIONCALL;
725 This->method = method;
726 return S_OK;
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;
736 return S_OK;
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)
750 DWORD hash = 0;
752 if (str) {
753 while (*str) {
754 WCHAR ch;
756 ch = (method == TextCompare || method == DatabaseCompare) ? tolowerW(*str) : *str;
758 hash += (hash << 4) + ch;
759 str++;
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)
773 if (isinf(flt)) {
774 *hash = 0;
775 return S_OK;
777 else if (!isnan(flt)) {
778 *hash = get_num_hash(flt);
779 return S_OK;
782 /* NaN case */
783 *hash = ~0u;
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);
798 V_VT(hash) = VT_I4;
799 switch (V_VT(key))
801 case VT_BSTR|VT_BYREF:
802 case VT_BSTR:
803 V_I4(hash) = get_str_hash(get_key_strptr(key), This->method);
804 break;
805 case VT_UI1|VT_BYREF:
806 case VT_UI1:
807 V_I4(hash) = get_num_hash(V_VT(key) & VT_BYREF ? *V_UI1REF(key) : V_UI1(key));
808 break;
809 case VT_I2|VT_BYREF:
810 case VT_I2:
811 V_I4(hash) = get_num_hash(V_VT(key) & VT_BYREF ? *V_I2REF(key) : V_I2(key));
812 break;
813 case VT_I4|VT_BYREF:
814 case VT_I4:
815 V_I4(hash) = get_num_hash(V_VT(key) & VT_BYREF ? *V_I4REF(key) : V_I4(key));
816 break;
817 case VT_UNKNOWN|VT_BYREF:
818 case VT_DISPATCH|VT_BYREF:
819 case VT_UNKNOWN:
820 case VT_DISPATCH:
822 IUnknown *src = (V_VT(key) & VT_BYREF) ? *V_UNKNOWNREF(key) : V_UNKNOWN(key);
823 IUnknown *unk = NULL;
825 if (!src) {
826 V_I4(hash) = 0;
827 return S_OK;
830 IUnknown_QueryInterface(src, &IID_IUnknown, (void**)&unk);
831 if (!unk) {
832 V_I4(hash) = ~0u;
833 return CTL_E_ILLEGALFUNCTIONCALL;
835 V_I4(hash) = get_ptr_hash(unk);
836 IUnknown_Release(unk);
837 break;
839 case VT_DATE|VT_BYREF:
840 case VT_DATE:
841 return get_flt_hash(V_VT(key) & VT_BYREF ? *V_DATEREF(key) : V_DATE(key), &V_I4(hash));
842 case VT_R4|VT_BYREF:
843 case VT_R4:
844 return get_flt_hash(V_VT(key) & VT_BYREF ? *V_R4REF(key) : V_R4(key), &V_I4(hash));
845 case VT_R8|VT_BYREF:
846 case VT_R8:
847 return get_flt_hash(V_VT(key) & VT_BYREF ? *V_R8REF(key) : V_R8(key), &V_I4(hash));
848 case VT_INT:
849 case VT_UINT:
850 case VT_I1:
851 case VT_I8:
852 case VT_UI2:
853 case VT_UI4:
854 V_I4(hash) = ~0u;
855 return CTL_E_ILLEGALFUNCTIONCALL;
856 default:
857 FIXME("not implemented for type %d\n", V_VT(key));
858 return E_NOTIMPL;
861 return S_OK;
864 static const struct IDictionaryVtbl dictionary_vtbl =
866 dictionary_QueryInterface,
867 dictionary_AddRef,
868 dictionary_Release,
869 dictionary_GetTypeInfoCount,
870 dictionary_GetTypeInfo,
871 dictionary_GetIDsOfNames,
872 dictionary_Invoke,
873 dictionary_putref_Item,
874 dictionary_put_Item,
875 dictionary_get_Item,
876 dictionary_Add,
877 dictionary_get_Count,
878 dictionary_Exists,
879 dictionary_Items,
880 dictionary_put_Key,
881 dictionary_Keys,
882 dictionary_Remove,
883 dictionary_RemoveAll,
884 dictionary_put_CompareMode,
885 dictionary_get_CompareMode,
886 dictionary__NewEnum,
887 dictionary_get_HashVal
890 HRESULT WINAPI Dictionary_CreateInstance(IClassFactory *factory,IUnknown *outer,REFIID riid, void **obj)
892 dictionary *This;
894 TRACE("(%p, %p, %s, %p)\n", factory, outer, debugstr_guid(riid), obj);
896 *obj = NULL;
898 This = heap_alloc(sizeof(*This));
899 if(!This) return E_OUTOFMEMORY;
901 This->IDictionary_iface.lpVtbl = &dictionary_vtbl;
902 This->ref = 1;
903 This->method = BinaryCompare;
904 This->count = 0;
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;
912 return S_OK;