gdiplus: Add GdipGetPenCompoundCount implementation.
[wine.git] / dlls / scrrun / dictionary.c
blobbb9c3610d1b3faa01477edb990359a5039390326
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
57 struct list entry;
58 struct list bucket;
59 DWORD hash;
60 VARIANT key;
61 VARIANT item;
64 struct dictionary
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;
77 struct dictionary_enum
79 IEnumVARIANT IEnumVARIANT_iface;
80 LONG ref;
82 struct dictionary *dict;
83 struct list *cur;
84 struct list notify;
87 static inline struct dictionary *impl_from_IDictionary(IDictionary *iface)
89 return CONTAINING_RECORD(iface, struct dictionary, IDictionary_iface);
92 static inline struct dictionary_enum *impl_from_IEnumVARIANT(IEnumVARIANT *iface)
94 return CONTAINING_RECORD(iface, struct dictionary_enum, IEnumVARIANT_iface);
97 static inline struct list *get_bucket_head(struct dictionary *dict, DWORD hash)
99 return &dict->buckets[hash % BUCKET_COUNT];
102 static inline BOOL is_string_key(const VARIANT *key)
104 return V_VT(key) == VT_BSTR || V_VT(key) == (VT_BSTR|VT_BYREF);
107 /* Only for VT_BSTR or VT_BSTR|VT_BYREF types */
108 static inline WCHAR *get_key_strptr(const VARIANT *key)
110 if (V_VT(key) == VT_BSTR)
111 return V_BSTR(key);
113 if (V_BSTRREF(key))
114 return *V_BSTRREF(key);
116 return NULL;
119 /* should be used only when both keys are of string type, it's not checked */
120 static inline int strcmp_key(const struct dictionary *dict, const VARIANT *key1, const VARIANT *key2)
122 const WCHAR *str1, *str2;
124 str1 = get_key_strptr(key1);
125 str2 = get_key_strptr(key2);
126 return dict->method == BinaryCompare ? wcscmp(str1, str2) : wcsicmp(str1, str2);
129 static BOOL is_matching_key(const struct dictionary *dict, const struct keyitem_pair *pair, const VARIANT *key, DWORD hash)
131 if (is_string_key(key) && is_string_key(&pair->key)) {
132 if (hash != pair->hash)
133 return FALSE;
135 return strcmp_key(dict, key, &pair->key) == 0;
138 if ((is_string_key(key) && !is_string_key(&pair->key)) ||
139 (!is_string_key(key) && is_string_key(&pair->key)))
140 return FALSE;
142 /* for numeric keys only check hash */
143 return hash == pair->hash;
146 static struct keyitem_pair *get_keyitem_pair(struct dictionary *dict, VARIANT *key)
148 struct keyitem_pair *pair;
149 struct list *head, *entry;
150 VARIANT hash;
151 HRESULT hr;
153 hr = IDictionary_get_HashVal(&dict->IDictionary_iface, key, &hash);
154 if (FAILED(hr))
155 return NULL;
157 head = get_bucket_head(dict, V_I4(&hash));
158 if (!head->next || list_empty(head))
159 return NULL;
161 entry = list_head(head);
162 do {
163 pair = LIST_ENTRY(entry, struct keyitem_pair, bucket);
164 if (is_matching_key(dict, pair, key, V_I4(&hash))) return pair;
165 } while ((entry = list_next(head, entry)));
167 return NULL;
170 static HRESULT add_keyitem_pair(struct dictionary *dict, VARIANT *key, VARIANT *item)
172 struct keyitem_pair *pair;
173 struct list *head;
174 VARIANT hash;
175 HRESULT hr;
177 hr = IDictionary_get_HashVal(&dict->IDictionary_iface, key, &hash);
178 if (FAILED(hr))
179 return hr;
181 if (!(pair = malloc(sizeof(*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 free(pair);
211 return hr;
214 static void free_keyitem_pair(struct keyitem_pair *pair)
216 VariantClear(&pair->key);
217 VariantClear(&pair->item);
218 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, refcount %lu.\n", iface, 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, refcount %lu.\n", iface, ref);
254 if (!ref)
256 list_remove(&This->notify);
257 IDictionary_Release(&This->dict->IDictionary_iface);
258 free(This);
261 return ref;
264 static HRESULT WINAPI dict_enum_Next(IEnumVARIANT *iface, ULONG count, VARIANT *keys, ULONG *fetched)
266 struct dictionary_enum *This = impl_from_IEnumVARIANT(iface);
267 struct keyitem_pair *pair;
268 ULONG i = 0;
270 TRACE("%p, %lu, %p, %p.\n", iface, count, keys, fetched);
272 if (fetched)
273 *fetched = 0;
275 if (!count)
276 return S_OK;
278 while (This->cur && i < count) {
279 pair = LIST_ENTRY(This->cur, struct keyitem_pair, entry);
280 VariantCopy(&keys[i], &pair->key);
281 This->cur = list_next(&This->dict->pairs, This->cur);
282 i++;
285 if (fetched)
286 *fetched = i;
288 return i < count ? S_FALSE : S_OK;
291 static HRESULT WINAPI dict_enum_Skip(IEnumVARIANT *iface, ULONG count)
293 struct dictionary_enum *This = impl_from_IEnumVARIANT(iface);
295 TRACE("%p, %lu.\n", iface, count);
297 if (!count)
298 return S_OK;
300 if (!This->cur)
301 return S_FALSE;
303 while (count--) {
304 This->cur = list_next(&This->dict->pairs, This->cur);
305 if (!This->cur) break;
308 return count == 0 ? S_OK : S_FALSE;
311 static HRESULT WINAPI dict_enum_Reset(IEnumVARIANT *iface)
313 struct dictionary_enum *This = impl_from_IEnumVARIANT(iface);
315 TRACE("(%p)\n", This);
317 This->cur = list_head(&This->dict->pairs);
318 return S_OK;
321 static HRESULT create_dict_enum(struct dictionary *, IUnknown**);
323 static HRESULT WINAPI dict_enum_Clone(IEnumVARIANT *iface, IEnumVARIANT **cloned)
325 struct dictionary_enum *This = impl_from_IEnumVARIANT(iface);
326 TRACE("(%p)->(%p)\n", This, cloned);
327 return create_dict_enum(This->dict, (IUnknown**)cloned);
330 static const IEnumVARIANTVtbl dictenumvtbl = {
331 dict_enum_QueryInterface,
332 dict_enum_AddRef,
333 dict_enum_Release,
334 dict_enum_Next,
335 dict_enum_Skip,
336 dict_enum_Reset,
337 dict_enum_Clone
340 static HRESULT create_dict_enum(struct dictionary *dict, IUnknown **ret)
342 struct dictionary_enum *object;
344 *ret = NULL;
346 if (!(object = calloc(1, sizeof(*object))))
347 return E_OUTOFMEMORY;
349 object->IEnumVARIANT_iface.lpVtbl = &dictenumvtbl;
350 object->ref = 1;
351 object->cur = list_head(&dict->pairs);
352 list_add_tail(&dict->notifier, &object->notify);
353 object->dict = dict;
354 IDictionary_AddRef(&dict->IDictionary_iface);
356 *ret = (IUnknown *)&object->IEnumVARIANT_iface;
358 return S_OK;
361 static void notify_remove_pair(struct list *notifier, struct list *pair)
363 struct dictionary_enum *dict_enum;
364 struct list *cur;
366 LIST_FOR_EACH(cur, notifier) {
367 dict_enum = LIST_ENTRY(cur, struct dictionary_enum, notify);
368 if (!pair)
369 dict_enum->cur = list_head(&dict_enum->dict->pairs);
370 else if (dict_enum->cur == pair) {
371 dict_enum->cur = list_next(&dict_enum->dict->pairs, dict_enum->cur);
376 static HRESULT WINAPI dictionary_QueryInterface(IDictionary *iface, REFIID riid, void **obj)
378 struct dictionary *dictionary = impl_from_IDictionary(iface);
380 TRACE("%p, %s, %p.\n", iface, 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 = &dictionary->IDictionary_iface;
390 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
392 *obj = &dictionary->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 struct dictionary *dictionary = impl_from_IDictionary(iface);
419 ULONG ref = InterlockedIncrement(&dictionary->ref);
421 TRACE("%p, refcount %lu.\n", iface, ref);
423 return ref;
426 static ULONG WINAPI dictionary_Release(IDictionary *iface)
428 struct dictionary *dictionary = impl_from_IDictionary(iface);
429 ULONG ref = InterlockedDecrement(&dictionary->ref);
431 TRACE("%p, refcount %lu.\n", iface, ref);
433 if (!ref)
435 IDictionary_RemoveAll(iface);
436 free(dictionary);
439 return ref;
442 static HRESULT WINAPI dictionary_GetTypeInfoCount(IDictionary *iface, UINT *pctinfo)
444 TRACE("%p, %p.\n", iface, pctinfo);
446 *pctinfo = 1;
447 return S_OK;
450 static HRESULT WINAPI dictionary_GetTypeInfo(IDictionary *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
452 TRACE("%p, %u, %lx, %p.\n", iface, 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 ITypeInfo *typeinfo;
461 HRESULT hr;
463 TRACE("%p, %s, %p, %u, %lx, %p.\n", iface, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
465 hr = get_typeinfo(IDictionary_tid, &typeinfo);
466 if(SUCCEEDED(hr))
468 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
469 ITypeInfo_Release(typeinfo);
472 return hr;
475 static HRESULT WINAPI dictionary_Invoke(IDictionary *iface, DISPID dispIdMember, REFIID riid,
476 LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult,
477 EXCEPINFO *pExcepInfo, UINT *puArgErr)
479 ITypeInfo *typeinfo;
480 HRESULT hr;
482 TRACE("%p, %ld, %s, %lx, %d, %p, %p, %p, %p.\n", iface, dispIdMember, debugstr_guid(riid),
483 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
485 hr = get_typeinfo(IDictionary_tid, &typeinfo);
486 if(SUCCEEDED(hr))
488 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
489 ITypeInfo_Release(typeinfo);
492 return hr;
495 static HRESULT WINAPI dictionary_putref_Item(IDictionary *iface, VARIANT *Key, VARIANT *pRetItem)
497 FIXME("%p, %p, %p stub\n", iface, Key, pRetItem);
499 return E_NOTIMPL;
502 static HRESULT WINAPI dictionary_put_Item(IDictionary *iface, VARIANT *key, VARIANT *item)
504 struct dictionary *dictionary = impl_from_IDictionary(iface);
505 struct keyitem_pair *pair;
507 TRACE("%p, %s, %s.\n", iface, debugstr_variant(key), debugstr_variant(item));
509 if ((pair = get_keyitem_pair(dictionary, key)))
510 return VariantCopyInd(&pair->item, item);
512 return IDictionary_Add(iface, key, item);
515 static HRESULT WINAPI dictionary_get_Item(IDictionary *iface, VARIANT *key, VARIANT *item)
517 struct dictionary *dictionary = impl_from_IDictionary(iface);
518 struct keyitem_pair *pair;
520 TRACE("%p, %s, %p.\n", iface, debugstr_variant(key), item);
522 if ((pair = get_keyitem_pair(dictionary, key)))
523 VariantCopy(item, &pair->item);
524 else {
525 VariantInit(item);
526 return IDictionary_Add(iface, key, item);
529 return S_OK;
532 static HRESULT WINAPI dictionary_Add(IDictionary *iface, VARIANT *key, VARIANT *item)
534 struct dictionary *dictionary = impl_from_IDictionary(iface);
536 TRACE("%p, %s, %s.\n", iface, debugstr_variant(key), debugstr_variant(item));
538 if (get_keyitem_pair(dictionary, key))
539 return CTL_E_KEY_ALREADY_EXISTS;
541 return add_keyitem_pair(dictionary, key, item);
544 static HRESULT WINAPI dictionary_get_Count(IDictionary *iface, LONG *count)
546 struct dictionary *dictionary = impl_from_IDictionary(iface);
548 TRACE("%p, %p.\n", iface, count);
550 *count = dictionary->count;
551 return S_OK;
554 static HRESULT WINAPI dictionary_Exists(IDictionary *iface, VARIANT *key, VARIANT_BOOL *exists)
556 struct dictionary *dictionary = impl_from_IDictionary(iface);
558 TRACE("%p, %s, %p.\n", iface, debugstr_variant(key), exists);
560 if (!exists)
561 return CTL_E_ILLEGALFUNCTIONCALL;
563 *exists = get_keyitem_pair(dictionary, key) != NULL ? VARIANT_TRUE : VARIANT_FALSE;
564 return S_OK;
567 static HRESULT WINAPI dictionary_Items(IDictionary *iface, VARIANT *items)
569 struct dictionary *dictionary = impl_from_IDictionary(iface);
570 struct keyitem_pair *pair;
571 SAFEARRAYBOUND bound;
572 SAFEARRAY *sa;
573 VARIANT *v;
574 HRESULT hr;
575 LONG i;
577 TRACE("%p, %p.\n", iface, items);
579 if (!items)
580 return S_OK;
582 bound.lLbound = 0;
583 bound.cElements = dictionary->count;
584 sa = SafeArrayCreate(VT_VARIANT, 1, &bound);
585 if (!sa)
586 return E_OUTOFMEMORY;
588 hr = SafeArrayAccessData(sa, (void**)&v);
589 if (FAILED(hr)) {
590 SafeArrayDestroy(sa);
591 return hr;
594 i = 0;
595 LIST_FOR_EACH_ENTRY(pair, &dictionary->pairs, struct keyitem_pair, entry)
597 VariantCopy(&v[i], &pair->item);
598 i++;
600 SafeArrayUnaccessData(sa);
602 V_VT(items) = VT_ARRAY|VT_VARIANT;
603 V_ARRAY(items) = sa;
604 return S_OK;
607 static HRESULT WINAPI dictionary_put_Key(IDictionary *iface, VARIANT *key, VARIANT *newkey)
609 struct dictionary *dictionary = impl_from_IDictionary(iface);
610 struct keyitem_pair *pair;
611 VARIANT empty;
612 HRESULT hr;
614 TRACE("%p, %s, %s.\n", iface, debugstr_variant(key), debugstr_variant(newkey));
616 if ((pair = get_keyitem_pair(dictionary, key)))
618 /* found existing pair for a key, add new pair with new key
619 and old item and remove old pair after that */
621 hr = IDictionary_Add(iface, newkey, &pair->item);
622 if (FAILED(hr))
623 return hr;
625 return IDictionary_Remove(iface, key);
628 VariantInit(&empty);
629 return IDictionary_Add(iface, newkey, &empty);
632 static HRESULT WINAPI dictionary_Keys(IDictionary *iface, VARIANT *keys)
634 struct dictionary *dictionary = impl_from_IDictionary(iface);
635 struct keyitem_pair *pair;
636 SAFEARRAYBOUND bound;
637 SAFEARRAY *sa;
638 VARIANT *v;
639 HRESULT hr;
640 LONG i;
642 TRACE("%p, %p.\n", iface, keys);
644 if (!keys)
645 return S_OK;
647 bound.lLbound = 0;
648 bound.cElements = dictionary->count;
649 sa = SafeArrayCreate(VT_VARIANT, 1, &bound);
650 if (!sa)
651 return E_OUTOFMEMORY;
653 hr = SafeArrayAccessData(sa, (void**)&v);
654 if (FAILED(hr)) {
655 SafeArrayDestroy(sa);
656 return hr;
659 i = 0;
660 LIST_FOR_EACH_ENTRY(pair, &dictionary->pairs, struct keyitem_pair, entry)
662 VariantCopy(&v[i], &pair->key);
663 i++;
665 SafeArrayUnaccessData(sa);
667 V_VT(keys) = VT_ARRAY|VT_VARIANT;
668 V_ARRAY(keys) = sa;
669 return S_OK;
672 static HRESULT WINAPI dictionary_Remove(IDictionary *iface, VARIANT *key)
674 struct dictionary *dictionary = impl_from_IDictionary(iface);
675 struct keyitem_pair *pair;
677 TRACE("%p, %s.\n", iface, debugstr_variant(key));
679 if (!(pair = get_keyitem_pair(dictionary, key)))
680 return CTL_E_ELEMENT_NOT_FOUND;
682 notify_remove_pair(&dictionary->notifier, &pair->entry);
683 list_remove(&pair->entry);
684 list_remove(&pair->bucket);
685 dictionary->count--;
687 free_keyitem_pair(pair);
688 return S_OK;
691 static HRESULT WINAPI dictionary_RemoveAll(IDictionary *iface)
693 struct dictionary *dictionary = impl_from_IDictionary(iface);
694 struct keyitem_pair *pair, *pair2;
696 TRACE("%p.\n", iface);
698 if (!dictionary->count)
699 return S_OK;
701 notify_remove_pair(&dictionary->notifier, NULL);
702 LIST_FOR_EACH_ENTRY_SAFE(pair, pair2, &dictionary->pairs, struct keyitem_pair, entry)
704 list_remove(&pair->entry);
705 list_remove(&pair->bucket);
706 free_keyitem_pair(pair);
708 dictionary->count = 0;
710 return S_OK;
713 static HRESULT WINAPI dictionary_put_CompareMode(IDictionary *iface, CompareMethod method)
715 struct dictionary *dictionary = impl_from_IDictionary(iface);
717 TRACE("%p, %d.\n", iface, method);
719 if (dictionary->count)
720 return CTL_E_ILLEGALFUNCTIONCALL;
722 dictionary->method = method;
723 return S_OK;
726 static HRESULT WINAPI dictionary_get_CompareMode(IDictionary *iface, CompareMethod *method)
728 struct dictionary *dictionary = impl_from_IDictionary(iface);
730 TRACE("%p, %p.\n", iface, method);
732 *method = dictionary->method;
733 return S_OK;
736 static HRESULT WINAPI dictionary__NewEnum(IDictionary *iface, IUnknown **ret)
738 struct dictionary *dictionary = impl_from_IDictionary(iface);
740 TRACE("%p, %p.\n", iface, ret);
742 return create_dict_enum(dictionary, ret);
745 static DWORD get_str_hash(const WCHAR *str, CompareMethod method)
747 DWORD hash = 0;
749 if (str) {
750 while (*str) {
751 WCHAR ch;
753 ch = (method == TextCompare || method == DatabaseCompare) ? towlower(*str) : *str;
755 hash += (hash << 4) + ch;
756 str++;
760 return hash % DICT_HASH_MOD;
763 static DWORD get_num_hash(FLOAT num)
765 return (*((DWORD*)&num)) % DICT_HASH_MOD;
768 static HRESULT get_flt_hash(FLOAT flt, LONG *hash)
770 if (isinf(flt)) {
771 *hash = 0;
772 return S_OK;
774 else if (!isnan(flt)) {
775 *hash = get_num_hash(flt);
776 return S_OK;
779 /* NaN case */
780 *hash = ~0u;
781 return CTL_E_ILLEGALFUNCTIONCALL;
784 static DWORD get_ptr_hash(void *ptr)
786 return PtrToUlong(ptr) % DICT_HASH_MOD;
789 static HRESULT WINAPI dictionary_get_HashVal(IDictionary *iface, VARIANT *key, VARIANT *hash)
791 struct dictionary *dictionary = impl_from_IDictionary(iface);
793 TRACE("%p, %s, %p.\n", iface, debugstr_variant(key), hash);
795 V_VT(hash) = VT_I4;
796 switch (V_VT(key))
798 case VT_BSTR|VT_BYREF:
799 case VT_BSTR:
800 V_I4(hash) = get_str_hash(get_key_strptr(key), dictionary->method);
801 break;
802 case VT_UI1|VT_BYREF:
803 case VT_UI1:
804 V_I4(hash) = get_num_hash(V_VT(key) & VT_BYREF ? *V_UI1REF(key) : V_UI1(key));
805 break;
806 case VT_I2|VT_BYREF:
807 case VT_I2:
808 V_I4(hash) = get_num_hash(V_VT(key) & VT_BYREF ? *V_I2REF(key) : V_I2(key));
809 break;
810 case VT_I4|VT_BYREF:
811 case VT_I4:
812 V_I4(hash) = get_num_hash(V_VT(key) & VT_BYREF ? *V_I4REF(key) : V_I4(key));
813 break;
814 case VT_UNKNOWN|VT_BYREF:
815 case VT_DISPATCH|VT_BYREF:
816 case VT_UNKNOWN:
817 case VT_DISPATCH:
819 IUnknown *src = (V_VT(key) & VT_BYREF) ? *V_UNKNOWNREF(key) : V_UNKNOWN(key);
820 IUnknown *unk = NULL;
822 if (!src) {
823 V_I4(hash) = 0;
824 return S_OK;
827 IUnknown_QueryInterface(src, &IID_IUnknown, (void**)&unk);
828 if (!unk) {
829 V_I4(hash) = ~0u;
830 return CTL_E_ILLEGALFUNCTIONCALL;
832 V_I4(hash) = get_ptr_hash(unk);
833 IUnknown_Release(unk);
834 break;
836 case VT_DATE|VT_BYREF:
837 case VT_DATE:
838 return get_flt_hash(V_VT(key) & VT_BYREF ? *V_DATEREF(key) : V_DATE(key), &V_I4(hash));
839 case VT_R4|VT_BYREF:
840 case VT_R4:
841 return get_flt_hash(V_VT(key) & VT_BYREF ? *V_R4REF(key) : V_R4(key), &V_I4(hash));
842 case VT_R8|VT_BYREF:
843 case VT_R8:
844 return get_flt_hash(V_VT(key) & VT_BYREF ? *V_R8REF(key) : V_R8(key), &V_I4(hash));
845 case VT_INT:
846 case VT_UINT:
847 case VT_I1:
848 case VT_I8:
849 case VT_UI2:
850 case VT_UI4:
851 V_I4(hash) = ~0u;
852 return CTL_E_ILLEGALFUNCTIONCALL;
853 default:
854 FIXME("not implemented for type %d\n", V_VT(key));
855 return E_NOTIMPL;
858 return S_OK;
861 static const struct IDictionaryVtbl dictionary_vtbl =
863 dictionary_QueryInterface,
864 dictionary_AddRef,
865 dictionary_Release,
866 dictionary_GetTypeInfoCount,
867 dictionary_GetTypeInfo,
868 dictionary_GetIDsOfNames,
869 dictionary_Invoke,
870 dictionary_putref_Item,
871 dictionary_put_Item,
872 dictionary_get_Item,
873 dictionary_Add,
874 dictionary_get_Count,
875 dictionary_Exists,
876 dictionary_Items,
877 dictionary_put_Key,
878 dictionary_Keys,
879 dictionary_Remove,
880 dictionary_RemoveAll,
881 dictionary_put_CompareMode,
882 dictionary_get_CompareMode,
883 dictionary__NewEnum,
884 dictionary_get_HashVal
887 HRESULT WINAPI Dictionary_CreateInstance(IClassFactory *factory, IUnknown *outer, REFIID riid, void **ret)
889 struct dictionary *object;
891 TRACE("(%p, %p, %s, %p)\n", factory, outer, debugstr_guid(riid), ret);
893 *ret = NULL;
895 if (!(object = calloc(1, sizeof(*object))))
896 return E_OUTOFMEMORY;
898 object->IDictionary_iface.lpVtbl = &dictionary_vtbl;
899 object->ref = 1;
900 object->method = BinaryCompare;
901 list_init(&object->pairs);
902 list_init(&object->notifier);
904 init_classinfo(&CLSID_Dictionary, (IUnknown *)&object->IDictionary_iface, &object->classinfo);
906 *ret = &object->IDictionary_iface;
908 return S_OK;