scrrun: Use CRT allocation functions.
[wine.git] / dlls / scrrun / dictionary.c
blobb946d8ad25b8c44dab6cb57dc8078ec01ba367e4
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 <stdarg.h>
22 #include <math.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "ole2.h"
27 #include "olectl.h"
28 #include "dispex.h"
29 #include "scrrun.h"
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
46 first pair.
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.
55 struct keyitem_pair {
56 struct list entry;
57 struct list bucket;
58 DWORD hash;
59 VARIANT key;
60 VARIANT item;
63 typedef struct
65 struct provideclassinfo classinfo;
66 IDictionary IDictionary_iface;
67 LONG ref;
69 CompareMethod method;
70 LONG count;
71 struct list pairs;
72 struct list buckets[BUCKET_COUNT];
73 struct list notifier;
74 } dictionary;
76 struct dictionary_enum {
77 IEnumVARIANT IEnumVARIANT_iface;
78 LONG ref;
80 dictionary *dict;
81 struct list *cur;
82 struct list notify;
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)
109 return V_BSTR(key);
111 if (V_BSTRREF(key))
112 return *V_BSTRREF(key);
114 return NULL;
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)
131 return FALSE;
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)))
138 return FALSE;
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;
148 VARIANT hash;
149 HRESULT hr;
151 hr = IDictionary_get_HashVal(&dict->IDictionary_iface, key, &hash);
152 if (FAILED(hr))
153 return NULL;
155 head = get_bucket_head(dict, V_I4(&hash));
156 if (!head->next || list_empty(head))
157 return NULL;
159 entry = list_head(head);
160 do {
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)));
165 return NULL;
168 static HRESULT add_keyitem_pair(dictionary *dict, VARIANT *key, VARIANT *item)
170 struct keyitem_pair *pair;
171 struct list *head;
172 VARIANT hash;
173 HRESULT hr;
175 hr = IDictionary_get_HashVal(&dict->IDictionary_iface, key, &hash);
176 if (FAILED(hr))
177 return hr;
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);
187 if (FAILED(hr))
188 goto failed;
190 hr = VariantCopyInd(&pair->item, item);
191 if (FAILED(hr))
192 goto failed;
194 head = get_bucket_head(dict, pair->hash);
195 if (!head->next)
196 /* this only happens once per bucket */
197 list_init(head);
199 /* link to bucket list and to full list */
200 list_add_tail(head, &pair->bucket);
201 list_add_tail(&dict->pairs, &pair->entry);
202 dict->count++;
203 return S_OK;
205 failed:
206 VariantClear(&pair->key);
207 VariantClear(&pair->item);
208 free(pair);
209 return hr;
212 static void free_keyitem_pair(struct keyitem_pair *pair)
214 VariantClear(&pair->key);
215 VariantClear(&pair->item);
216 free(pair);
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)) {
226 *obj = iface;
227 IEnumVARIANT_AddRef(iface);
228 return S_OK;
230 else {
231 WARN("interface not supported %s\n", debugstr_guid(riid));
232 *obj = NULL;
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);
242 return 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);
252 if (!ref)
254 list_remove(&This->notify);
255 IDictionary_Release(&This->dict->IDictionary_iface);
256 free(This);
259 return ref;
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;
266 ULONG i = 0;
268 TRACE("(%p)->(%u %p %p)\n", This, count, keys, fetched);
270 if (fetched)
271 *fetched = 0;
273 if (!count)
274 return S_OK;
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);
280 i++;
283 if (fetched)
284 *fetched = i;
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);
295 if (!count)
296 return S_OK;
298 if (!This->cur)
299 return S_FALSE;
301 while (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);
316 return S_OK;
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,
330 dict_enum_AddRef,
331 dict_enum_Release,
332 dict_enum_Next,
333 dict_enum_Skip,
334 dict_enum_Reset,
335 dict_enum_Clone
338 static HRESULT create_dict_enum(dictionary *dict, IUnknown **ret)
340 struct dictionary_enum *object;
342 *ret = NULL;
344 if (!(object = calloc(1, sizeof(*object))))
345 return E_OUTOFMEMORY;
347 object->IEnumVARIANT_iface.lpVtbl = &dictenumvtbl;
348 object->ref = 1;
349 object->cur = list_head(&dict->pairs);
350 list_add_tail(&dict->notifier, &object->notify);
351 object->dict = dict;
352 IDictionary_AddRef(&dict->IDictionary_iface);
354 *ret = (IUnknown *)&object->IEnumVARIANT_iface;
356 return S_OK;
359 static void notify_remove_pair(struct list *notifier, struct list *pair)
361 struct dictionary_enum *dict_enum;
362 struct list *cur;
364 LIST_FOR_EACH(cur, notifier) {
365 dict_enum = LIST_ENTRY(cur, struct dictionary_enum, notify);
366 if (!pair)
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);
379 *obj = NULL;
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");
394 *obj = NULL;
395 return E_NOINTERFACE;
397 else if ( IsEqualGUID( riid, &IID_IObjectWithSite ))
399 TRACE("Interface IObjectWithSite not supported - returning NULL\n");
400 *obj = NULL;
401 return E_NOINTERFACE;
403 else
405 WARN("interface %s not implemented\n", debugstr_guid(riid));
406 return E_NOINTERFACE;
409 IUnknown_AddRef((IUnknown*)*obj);
410 return S_OK;
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);
420 return 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);
430 if (!ref)
432 IDictionary_RemoveAll(iface);
433 free(dictionary);
436 return ref;
439 static HRESULT WINAPI dictionary_GetTypeInfoCount(IDictionary *iface, UINT *pctinfo)
441 dictionary *This = impl_from_IDictionary(iface);
443 TRACE("(%p)->(%p)\n", This, pctinfo);
445 *pctinfo = 1;
446 return S_OK;
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);
461 ITypeInfo *typeinfo;
462 HRESULT hr;
464 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
466 hr = get_typeinfo(IDictionary_tid, &typeinfo);
467 if(SUCCEEDED(hr))
469 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
470 ITypeInfo_Release(typeinfo);
473 return hr;
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);
481 ITypeInfo *typeinfo;
482 HRESULT hr;
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);
488 if(SUCCEEDED(hr))
490 hr = ITypeInfo_Invoke(typeinfo, &This->IDictionary_iface, dispIdMember, wFlags,
491 pDispParams, pVarResult, pExcepInfo, puArgErr);
492 ITypeInfo_Release(typeinfo);
495 return hr;
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);
504 return E_NOTIMPL;
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);
529 else {
530 VariantInit(item);
531 return IDictionary_Add(iface, key, item);
534 return S_OK;
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;
556 return S_OK;
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);
565 if (!exists)
566 return CTL_E_ILLEGALFUNCTIONCALL;
568 *exists = get_keyitem_pair(This, key) != NULL ? VARIANT_TRUE : VARIANT_FALSE;
569 return S_OK;
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;
577 SAFEARRAY *sa;
578 VARIANT *v;
579 HRESULT hr;
580 LONG i;
582 TRACE("(%p)->(%p)\n", This, items);
584 if (!items)
585 return S_OK;
587 bound.lLbound = 0;
588 bound.cElements = This->count;
589 sa = SafeArrayCreate(VT_VARIANT, 1, &bound);
590 if (!sa)
591 return E_OUTOFMEMORY;
593 hr = SafeArrayAccessData(sa, (void**)&v);
594 if (FAILED(hr)) {
595 SafeArrayDestroy(sa);
596 return hr;
599 i = 0;
600 LIST_FOR_EACH_ENTRY(pair, &This->pairs, struct keyitem_pair, entry) {
601 VariantCopy(&v[i], &pair->item);
602 i++;
604 SafeArrayUnaccessData(sa);
606 V_VT(items) = VT_ARRAY|VT_VARIANT;
607 V_ARRAY(items) = sa;
608 return S_OK;
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;
615 VARIANT empty;
616 HRESULT hr;
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);
625 if (FAILED(hr))
626 return hr;
628 return IDictionary_Remove(iface, key);
631 VariantInit(&empty);
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;
640 SAFEARRAY *sa;
641 VARIANT *v;
642 HRESULT hr;
643 LONG i;
645 TRACE("(%p)->(%p)\n", This, keys);
647 if (!keys)
648 return S_OK;
650 bound.lLbound = 0;
651 bound.cElements = This->count;
652 sa = SafeArrayCreate(VT_VARIANT, 1, &bound);
653 if (!sa)
654 return E_OUTOFMEMORY;
656 hr = SafeArrayAccessData(sa, (void**)&v);
657 if (FAILED(hr)) {
658 SafeArrayDestroy(sa);
659 return hr;
662 i = 0;
663 LIST_FOR_EACH_ENTRY(pair, &This->pairs, struct keyitem_pair, entry) {
664 VariantCopy(&v[i], &pair->key);
665 i++;
667 SafeArrayUnaccessData(sa);
669 V_VT(keys) = VT_ARRAY|VT_VARIANT;
670 V_ARRAY(keys) = sa;
671 return S_OK;
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);
687 This->count--;
689 free_keyitem_pair(pair);
690 return S_OK;
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)
701 return S_OK;
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);
709 This->count = 0;
711 return S_OK;
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);
720 if (This->count)
721 return CTL_E_ILLEGALFUNCTIONCALL;
723 This->method = method;
724 return S_OK;
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;
734 return S_OK;
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)
748 DWORD hash = 0;
750 if (str) {
751 while (*str) {
752 WCHAR ch;
754 ch = (method == TextCompare || method == DatabaseCompare) ? towlower(*str) : *str;
756 hash += (hash << 4) + ch;
757 str++;
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)
771 if (isinf(flt)) {
772 *hash = 0;
773 return S_OK;
775 else if (!isnan(flt)) {
776 *hash = get_num_hash(flt);
777 return S_OK;
780 /* NaN case */
781 *hash = ~0u;
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);
796 V_VT(hash) = VT_I4;
797 switch (V_VT(key))
799 case VT_BSTR|VT_BYREF:
800 case VT_BSTR:
801 V_I4(hash) = get_str_hash(get_key_strptr(key), This->method);
802 break;
803 case VT_UI1|VT_BYREF:
804 case VT_UI1:
805 V_I4(hash) = get_num_hash(V_VT(key) & VT_BYREF ? *V_UI1REF(key) : V_UI1(key));
806 break;
807 case VT_I2|VT_BYREF:
808 case VT_I2:
809 V_I4(hash) = get_num_hash(V_VT(key) & VT_BYREF ? *V_I2REF(key) : V_I2(key));
810 break;
811 case VT_I4|VT_BYREF:
812 case VT_I4:
813 V_I4(hash) = get_num_hash(V_VT(key) & VT_BYREF ? *V_I4REF(key) : V_I4(key));
814 break;
815 case VT_UNKNOWN|VT_BYREF:
816 case VT_DISPATCH|VT_BYREF:
817 case VT_UNKNOWN:
818 case VT_DISPATCH:
820 IUnknown *src = (V_VT(key) & VT_BYREF) ? *V_UNKNOWNREF(key) : V_UNKNOWN(key);
821 IUnknown *unk = NULL;
823 if (!src) {
824 V_I4(hash) = 0;
825 return S_OK;
828 IUnknown_QueryInterface(src, &IID_IUnknown, (void**)&unk);
829 if (!unk) {
830 V_I4(hash) = ~0u;
831 return CTL_E_ILLEGALFUNCTIONCALL;
833 V_I4(hash) = get_ptr_hash(unk);
834 IUnknown_Release(unk);
835 break;
837 case VT_DATE|VT_BYREF:
838 case VT_DATE:
839 return get_flt_hash(V_VT(key) & VT_BYREF ? *V_DATEREF(key) : V_DATE(key), &V_I4(hash));
840 case VT_R4|VT_BYREF:
841 case VT_R4:
842 return get_flt_hash(V_VT(key) & VT_BYREF ? *V_R4REF(key) : V_R4(key), &V_I4(hash));
843 case VT_R8|VT_BYREF:
844 case VT_R8:
845 return get_flt_hash(V_VT(key) & VT_BYREF ? *V_R8REF(key) : V_R8(key), &V_I4(hash));
846 case VT_INT:
847 case VT_UINT:
848 case VT_I1:
849 case VT_I8:
850 case VT_UI2:
851 case VT_UI4:
852 V_I4(hash) = ~0u;
853 return CTL_E_ILLEGALFUNCTIONCALL;
854 default:
855 FIXME("not implemented for type %d\n", V_VT(key));
856 return E_NOTIMPL;
859 return S_OK;
862 static const struct IDictionaryVtbl dictionary_vtbl =
864 dictionary_QueryInterface,
865 dictionary_AddRef,
866 dictionary_Release,
867 dictionary_GetTypeInfoCount,
868 dictionary_GetTypeInfo,
869 dictionary_GetIDsOfNames,
870 dictionary_Invoke,
871 dictionary_putref_Item,
872 dictionary_put_Item,
873 dictionary_get_Item,
874 dictionary_Add,
875 dictionary_get_Count,
876 dictionary_Exists,
877 dictionary_Items,
878 dictionary_put_Key,
879 dictionary_Keys,
880 dictionary_Remove,
881 dictionary_RemoveAll,
882 dictionary_put_CompareMode,
883 dictionary_get_CompareMode,
884 dictionary__NewEnum,
885 dictionary_get_HashVal
888 HRESULT WINAPI Dictionary_CreateInstance(IClassFactory *factory, IUnknown *outer, REFIID riid, void **ret)
890 dictionary *object;
892 TRACE("(%p, %p, %s, %p)\n", factory, outer, debugstr_guid(riid), ret);
894 *ret = NULL;
896 if (!(object = calloc(1, sizeof(*object))))
897 return E_OUTOFMEMORY;
899 object->IDictionary_iface.lpVtbl = &dictionary_vtbl;
900 object->ref = 1;
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;
909 return S_OK;