mfplat: Read queue subscriber within the critical section.
[wine/zf.git] / dlls / scrrun / dictionary.c
blob477943f6579763b8aa43942c6e4ae956f5a9fc8f
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/heap.h"
34 #include "wine/list.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(scrrun);
38 #define BUCKET_COUNT 509
39 #define DICT_HASH_MOD 1201
41 /* Implementation details
43 Dictionary contains one list that links all pairs, this way
44 order in which they were added is preserved. Each bucket has
45 its own list to hold all pairs in this bucket. Initially all
46 bucket lists are zeroed and we init them once we about to add
47 first pair.
49 When pair is removed it's unlinked from both lists; if it was
50 a last pair in a bucket list it stays empty in initialized state.
52 Preserving pair order is important for enumeration, so far testing
53 indicates that pairs are not reordered basing on hash value.
56 struct keyitem_pair {
57 struct list entry;
58 struct list bucket;
59 DWORD hash;
60 VARIANT key;
61 VARIANT item;
64 typedef struct
66 struct provideclassinfo classinfo;
67 IDictionary IDictionary_iface;
68 LONG ref;
70 CompareMethod method;
71 LONG count;
72 struct list pairs;
73 struct list buckets[BUCKET_COUNT];
74 struct list notifier;
75 } dictionary;
77 struct dictionary_enum {
78 IEnumVARIANT IEnumVARIANT_iface;
79 LONG ref;
81 dictionary *dict;
82 struct list *cur;
83 struct list notify;
86 static inline dictionary *impl_from_IDictionary(IDictionary *iface)
88 return CONTAINING_RECORD(iface, dictionary, IDictionary_iface);
91 static inline struct dictionary_enum *impl_from_IEnumVARIANT(IEnumVARIANT *iface)
93 return CONTAINING_RECORD(iface, struct dictionary_enum, IEnumVARIANT_iface);
96 static inline struct list *get_bucket_head(dictionary *dict, DWORD hash)
98 return &dict->buckets[hash % BUCKET_COUNT];
101 static inline BOOL is_string_key(const VARIANT *key)
103 return V_VT(key) == VT_BSTR || V_VT(key) == (VT_BSTR|VT_BYREF);
106 /* Only for VT_BSTR or VT_BSTR|VT_BYREF types */
107 static inline WCHAR *get_key_strptr(const VARIANT *key)
109 if (V_VT(key) == VT_BSTR)
110 return V_BSTR(key);
112 if (V_BSTRREF(key))
113 return *V_BSTRREF(key);
115 return NULL;
118 /* should be used only when both keys are of string type, it's not checked */
119 static inline int strcmp_key(const dictionary *dict, const VARIANT *key1, const VARIANT *key2)
121 const WCHAR *str1, *str2;
123 str1 = get_key_strptr(key1);
124 str2 = get_key_strptr(key2);
125 return dict->method == BinaryCompare ? wcscmp(str1, str2) : wcsicmp(str1, str2);
128 static BOOL is_matching_key(const dictionary *dict, const struct keyitem_pair *pair, const VARIANT *key, DWORD hash)
130 if (is_string_key(key) && is_string_key(&pair->key)) {
131 if (hash != pair->hash)
132 return FALSE;
134 return strcmp_key(dict, key, &pair->key) == 0;
137 if ((is_string_key(key) && !is_string_key(&pair->key)) ||
138 (!is_string_key(key) && is_string_key(&pair->key)))
139 return FALSE;
141 /* for numeric keys only check hash */
142 return hash == pair->hash;
145 static struct keyitem_pair *get_keyitem_pair(dictionary *dict, VARIANT *key)
147 struct keyitem_pair *pair;
148 struct list *head, *entry;
149 VARIANT hash;
150 HRESULT hr;
152 hr = IDictionary_get_HashVal(&dict->IDictionary_iface, key, &hash);
153 if (FAILED(hr))
154 return NULL;
156 head = get_bucket_head(dict, V_I4(&hash));
157 if (!head->next || list_empty(head))
158 return NULL;
160 entry = list_head(head);
161 do {
162 pair = LIST_ENTRY(entry, struct keyitem_pair, bucket);
163 if (is_matching_key(dict, pair, key, V_I4(&hash))) return pair;
164 } while ((entry = list_next(head, entry)));
166 return NULL;
169 static HRESULT add_keyitem_pair(dictionary *dict, VARIANT *key, VARIANT *item)
171 struct keyitem_pair *pair;
172 struct list *head;
173 VARIANT hash;
174 HRESULT hr;
176 hr = IDictionary_get_HashVal(&dict->IDictionary_iface, key, &hash);
177 if (FAILED(hr))
178 return hr;
180 pair = heap_alloc(sizeof(*pair));
181 if (!pair)
182 return E_OUTOFMEMORY;
184 pair->hash = V_I4(&hash);
185 VariantInit(&pair->key);
186 VariantInit(&pair->item);
188 hr = VariantCopyInd(&pair->key, key);
189 if (FAILED(hr))
190 goto failed;
192 hr = VariantCopyInd(&pair->item, item);
193 if (FAILED(hr))
194 goto failed;
196 head = get_bucket_head(dict, pair->hash);
197 if (!head->next)
198 /* this only happens once per bucket */
199 list_init(head);
201 /* link to bucket list and to full list */
202 list_add_tail(head, &pair->bucket);
203 list_add_tail(&dict->pairs, &pair->entry);
204 dict->count++;
205 return S_OK;
207 failed:
208 VariantClear(&pair->key);
209 VariantClear(&pair->item);
210 heap_free(pair);
211 return hr;
214 static void free_keyitem_pair(struct keyitem_pair *pair)
216 VariantClear(&pair->key);
217 VariantClear(&pair->item);
218 heap_free(pair);
221 static HRESULT WINAPI dict_enum_QueryInterface(IEnumVARIANT *iface, REFIID riid, void **obj)
223 struct dictionary_enum *This = impl_from_IEnumVARIANT(iface);
225 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), obj);
227 if (IsEqualIID(riid, &IID_IEnumVARIANT) || IsEqualIID(riid, &IID_IUnknown)) {
228 *obj = iface;
229 IEnumVARIANT_AddRef(iface);
230 return S_OK;
232 else {
233 WARN("interface not supported %s\n", debugstr_guid(riid));
234 *obj = NULL;
235 return E_NOINTERFACE;
239 static ULONG WINAPI dict_enum_AddRef(IEnumVARIANT *iface)
241 struct dictionary_enum *This = impl_from_IEnumVARIANT(iface);
242 ULONG ref = InterlockedIncrement(&This->ref);
243 TRACE("(%p)->(%u)\n", This, ref);
244 return ref;
247 static ULONG WINAPI dict_enum_Release(IEnumVARIANT *iface)
249 struct dictionary_enum *This = impl_from_IEnumVARIANT(iface);
250 LONG ref = InterlockedDecrement(&This->ref);
252 TRACE("(%p)->(%u)\n", This, ref);
254 if (!ref) {
255 list_remove(&This->notify);
256 IDictionary_Release(&This->dict->IDictionary_iface);
257 heap_free(This);
260 return ref;
263 static HRESULT WINAPI dict_enum_Next(IEnumVARIANT *iface, ULONG count, VARIANT *keys, ULONG *fetched)
265 struct dictionary_enum *This = impl_from_IEnumVARIANT(iface);
266 struct keyitem_pair *pair;
267 ULONG i = 0;
269 TRACE("(%p)->(%u %p %p)\n", This, count, keys, fetched);
271 if (fetched)
272 *fetched = 0;
274 if (!count)
275 return S_OK;
277 while (This->cur && i < count) {
278 pair = LIST_ENTRY(This->cur, struct keyitem_pair, entry);
279 VariantCopy(&keys[i], &pair->key);
280 This->cur = list_next(&This->dict->pairs, This->cur);
281 i++;
284 if (fetched)
285 *fetched = i;
287 return i < count ? S_FALSE : S_OK;
290 static HRESULT WINAPI dict_enum_Skip(IEnumVARIANT *iface, ULONG count)
292 struct dictionary_enum *This = impl_from_IEnumVARIANT(iface);
294 TRACE("(%p)->(%u)\n", This, count);
296 if (!count)
297 return S_OK;
299 if (!This->cur)
300 return S_FALSE;
302 while (count--) {
303 This->cur = list_next(&This->dict->pairs, This->cur);
304 if (!This->cur) break;
307 return count == 0 ? S_OK : S_FALSE;
310 static HRESULT WINAPI dict_enum_Reset(IEnumVARIANT *iface)
312 struct dictionary_enum *This = impl_from_IEnumVARIANT(iface);
314 TRACE("(%p)\n", This);
316 This->cur = list_head(&This->dict->pairs);
317 return S_OK;
320 static HRESULT create_dict_enum(dictionary*, IUnknown**);
322 static HRESULT WINAPI dict_enum_Clone(IEnumVARIANT *iface, IEnumVARIANT **cloned)
324 struct dictionary_enum *This = impl_from_IEnumVARIANT(iface);
325 TRACE("(%p)->(%p)\n", This, cloned);
326 return create_dict_enum(This->dict, (IUnknown**)cloned);
329 static const IEnumVARIANTVtbl dictenumvtbl = {
330 dict_enum_QueryInterface,
331 dict_enum_AddRef,
332 dict_enum_Release,
333 dict_enum_Next,
334 dict_enum_Skip,
335 dict_enum_Reset,
336 dict_enum_Clone
339 static HRESULT create_dict_enum(dictionary *dict, IUnknown **ret)
341 struct dictionary_enum *This;
343 *ret = NULL;
345 This = heap_alloc(sizeof(*This));
346 if (!This)
347 return E_OUTOFMEMORY;
349 This->IEnumVARIANT_iface.lpVtbl = &dictenumvtbl;
350 This->ref = 1;
351 This->cur = list_head(&dict->pairs);
352 list_add_tail(&dict->notifier, &This->notify);
353 This->dict = dict;
354 IDictionary_AddRef(&dict->IDictionary_iface);
356 *ret = (IUnknown*)&This->IEnumVARIANT_iface;
357 return S_OK;
360 static void notify_remove_pair(struct list *notifier, struct list *pair)
362 struct dictionary_enum *dict_enum;
363 struct list *cur;
365 LIST_FOR_EACH(cur, notifier) {
366 dict_enum = LIST_ENTRY(cur, struct dictionary_enum, notify);
367 if (!pair)
368 dict_enum->cur = list_head(&dict_enum->dict->pairs);
369 else if (dict_enum->cur == pair) {
370 dict_enum->cur = list_next(&dict_enum->dict->pairs, dict_enum->cur);
375 static HRESULT WINAPI dictionary_QueryInterface(IDictionary *iface, REFIID riid, void **obj)
377 dictionary *This = impl_from_IDictionary(iface);
378 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), obj);
380 *obj = NULL;
382 if(IsEqualIID(riid, &IID_IUnknown) ||
383 IsEqualIID(riid, &IID_IDispatch) ||
384 IsEqualIID(riid, &IID_IDictionary))
386 *obj = &This->IDictionary_iface;
388 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
390 *obj = &This->classinfo.IProvideClassInfo_iface;
392 else if ( IsEqualGUID( riid, &IID_IDispatchEx ))
394 TRACE("Interface IDispatchEx not supported - returning NULL\n");
395 *obj = NULL;
396 return E_NOINTERFACE;
398 else if ( IsEqualGUID( riid, &IID_IObjectWithSite ))
400 TRACE("Interface IObjectWithSite not supported - returning NULL\n");
401 *obj = NULL;
402 return E_NOINTERFACE;
404 else
406 WARN("interface %s not implemented\n", debugstr_guid(riid));
407 return E_NOINTERFACE;
410 IUnknown_AddRef((IUnknown*)*obj);
411 return S_OK;
414 static ULONG WINAPI dictionary_AddRef(IDictionary *iface)
416 dictionary *This = impl_from_IDictionary(iface);
417 ULONG ref = InterlockedIncrement(&This->ref);
419 TRACE("(%p)->(%u)\n", This, ref);
421 return ref;
424 static ULONG WINAPI dictionary_Release(IDictionary *iface)
426 dictionary *This = impl_from_IDictionary(iface);
427 ULONG ref = InterlockedDecrement(&This->ref);
429 TRACE("(%p)->(%u)\n", This, ref);
431 if (!ref) {
432 IDictionary_RemoveAll(iface);
433 heap_free(This);
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 **obj)
890 dictionary *This;
892 TRACE("(%p, %p, %s, %p)\n", factory, outer, debugstr_guid(riid), obj);
894 *obj = NULL;
896 This = heap_alloc(sizeof(*This));
897 if(!This) return E_OUTOFMEMORY;
899 This->IDictionary_iface.lpVtbl = &dictionary_vtbl;
900 This->ref = 1;
901 This->method = BinaryCompare;
902 This->count = 0;
903 list_init(&This->pairs);
904 list_init(&This->notifier);
905 memset(This->buckets, 0, sizeof(This->buckets));
907 init_classinfo(&CLSID_Dictionary, (IUnknown *)&This->IDictionary_iface, &This->classinfo);
908 *obj = &This->IDictionary_iface;
910 return S_OK;