d3d8: TRACE fixes.
[wine.git] / dlls / scrrun / dictionary.c
blob844b4d115423114eda5e5d0f61a1f2102cf4022c
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 IDictionary IDictionary_iface;
69 LONG ref;
71 CompareMethod method;
72 LONG count;
73 struct list pairs;
74 struct list buckets[BUCKET_COUNT];
75 struct list notifier;
76 } dictionary;
78 struct dictionary_enum {
79 IEnumVARIANT IEnumVARIANT_iface;
80 LONG ref;
82 dictionary *dict;
83 struct list *cur;
84 struct list notify;
87 static inline dictionary *impl_from_IDictionary(IDictionary *iface)
89 return CONTAINING_RECORD(iface, 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(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 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 ? strcmpW(str1, str2) : strcmpiW(str1, str2);
129 static BOOL is_matching_key(const 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(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(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 pair = heap_alloc(sizeof(*pair));
182 if (!pair)
183 return E_OUTOFMEMORY;
185 pair->hash = V_I4(&hash);
186 VariantInit(&pair->key);
187 VariantInit(&pair->item);
189 hr = VariantCopyInd(&pair->key, key);
190 if (FAILED(hr))
191 goto failed;
193 hr = VariantCopyInd(&pair->item, item);
194 if (FAILED(hr))
195 goto failed;
197 head = get_bucket_head(dict, pair->hash);
198 if (!head->next)
199 /* this only happens once per bucket */
200 list_init(head);
202 /* link to bucket list and to full list */
203 list_add_tail(head, &pair->bucket);
204 list_add_tail(&dict->pairs, &pair->entry);
205 dict->count++;
206 return S_OK;
208 failed:
209 VariantClear(&pair->key);
210 VariantClear(&pair->item);
211 heap_free(pair);
212 return hr;
215 static void free_keyitem_pair(struct keyitem_pair *pair)
217 VariantClear(&pair->key);
218 VariantClear(&pair->item);
219 heap_free(pair);
222 static HRESULT WINAPI dict_enum_QueryInterface(IEnumVARIANT *iface, REFIID riid, void **obj)
224 struct dictionary_enum *This = impl_from_IEnumVARIANT(iface);
226 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), obj);
228 if (IsEqualIID(riid, &IID_IEnumVARIANT) || IsEqualIID(riid, &IID_IUnknown)) {
229 *obj = iface;
230 IEnumVARIANT_AddRef(iface);
231 return S_OK;
233 else {
234 WARN("interface not supported %s\n", debugstr_guid(riid));
235 *obj = NULL;
236 return E_NOINTERFACE;
240 static ULONG WINAPI dict_enum_AddRef(IEnumVARIANT *iface)
242 struct dictionary_enum *This = impl_from_IEnumVARIANT(iface);
243 TRACE("(%p)\n", This);
244 return InterlockedIncrement(&This->ref);
247 static ULONG WINAPI dict_enum_Release(IEnumVARIANT *iface)
249 struct dictionary_enum *This = impl_from_IEnumVARIANT(iface);
250 LONG ref;
252 TRACE("(%p)\n", This);
254 ref = InterlockedDecrement(&This->ref);
255 if(ref == 0) {
256 list_remove(&This->notify);
257 IDictionary_Release(&This->dict->IDictionary_iface);
258 heap_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)->(%u %p %p)\n", This, 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)->(%u)\n", This, 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(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(dictionary *dict, IUnknown **ret)
342 struct dictionary_enum *This;
344 *ret = NULL;
346 This = heap_alloc(sizeof(*This));
347 if (!This)
348 return E_OUTOFMEMORY;
350 This->IEnumVARIANT_iface.lpVtbl = &dictenumvtbl;
351 This->ref = 1;
352 This->cur = list_head(&dict->pairs);
353 list_add_tail(&dict->notifier, &This->notify);
354 This->dict = dict;
355 IDictionary_AddRef(&dict->IDictionary_iface);
357 *ret = (IUnknown*)&This->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 dictionary *This = impl_from_IDictionary(iface);
379 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), obj);
381 *obj = NULL;
383 if(IsEqualIID(riid, &IID_IUnknown) ||
384 IsEqualIID(riid, &IID_IDispatch) ||
385 IsEqualIID(riid, &IID_IDictionary))
387 *obj = &This->IDictionary_iface;
389 else if ( IsEqualGUID( riid, &IID_IDispatchEx ))
391 TRACE("Interface IDispatchEx not supported - returning NULL\n");
392 *obj = NULL;
393 return E_NOINTERFACE;
395 else if ( IsEqualGUID( riid, &IID_IObjectWithSite ))
397 TRACE("Interface IObjectWithSite not supported - returning NULL\n");
398 *obj = NULL;
399 return E_NOINTERFACE;
401 else
403 WARN("interface %s not implemented\n", debugstr_guid(riid));
404 return E_NOINTERFACE;
407 IDictionary_AddRef(iface);
408 return S_OK;
411 static ULONG WINAPI dictionary_AddRef(IDictionary *iface)
413 dictionary *This = impl_from_IDictionary(iface);
414 TRACE("(%p)\n", This);
416 return InterlockedIncrement(&This->ref);
419 static ULONG WINAPI dictionary_Release(IDictionary *iface)
421 dictionary *This = impl_from_IDictionary(iface);
422 LONG ref;
424 TRACE("(%p)\n", This);
426 ref = InterlockedDecrement(&This->ref);
427 if(ref == 0) {
428 IDictionary_RemoveAll(iface);
429 heap_free(This);
432 return ref;
435 static HRESULT WINAPI dictionary_GetTypeInfoCount(IDictionary *iface, UINT *pctinfo)
437 dictionary *This = impl_from_IDictionary(iface);
439 TRACE("(%p)->()\n", This);
441 *pctinfo = 1;
442 return S_OK;
445 static HRESULT WINAPI dictionary_GetTypeInfo(IDictionary *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
447 dictionary *This = impl_from_IDictionary(iface);
449 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
450 return get_typeinfo(IDictionary_tid, ppTInfo);
453 static HRESULT WINAPI dictionary_GetIDsOfNames(IDictionary *iface, REFIID riid, LPOLESTR *rgszNames,
454 UINT cNames, LCID lcid, DISPID *rgDispId)
456 dictionary *This = impl_from_IDictionary(iface);
457 ITypeInfo *typeinfo;
458 HRESULT hr;
460 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
462 hr = get_typeinfo(IDictionary_tid, &typeinfo);
463 if(SUCCEEDED(hr))
465 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
466 ITypeInfo_Release(typeinfo);
469 return hr;
472 static HRESULT WINAPI dictionary_Invoke(IDictionary *iface, DISPID dispIdMember, REFIID riid,
473 LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult,
474 EXCEPINFO *pExcepInfo, UINT *puArgErr)
476 dictionary *This = impl_from_IDictionary(iface);
477 ITypeInfo *typeinfo;
478 HRESULT hr;
480 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
481 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
483 hr = get_typeinfo(IDictionary_tid, &typeinfo);
484 if(SUCCEEDED(hr))
486 hr = ITypeInfo_Invoke(typeinfo, &This->IDictionary_iface, dispIdMember, wFlags,
487 pDispParams, pVarResult, pExcepInfo, puArgErr);
488 ITypeInfo_Release(typeinfo);
491 return hr;
494 static HRESULT WINAPI dictionary_putref_Item(IDictionary *iface, VARIANT *Key, VARIANT *pRetItem)
496 dictionary *This = impl_from_IDictionary(iface);
498 FIXME("(%p)->(%p %p)\n", This, Key, pRetItem);
500 return E_NOTIMPL;
503 static HRESULT WINAPI dictionary_put_Item(IDictionary *iface, VARIANT *key, VARIANT *item)
505 dictionary *This = impl_from_IDictionary(iface);
506 struct keyitem_pair *pair;
508 TRACE("(%p)->(%s %s)\n", This, debugstr_variant(key), debugstr_variant(item));
510 if ((pair = get_keyitem_pair(This, key)))
511 return VariantCopyInd(&pair->item, item);
513 return IDictionary_Add(iface, key, item);
516 static HRESULT WINAPI dictionary_get_Item(IDictionary *iface, VARIANT *key, VARIANT *item)
518 dictionary *This = impl_from_IDictionary(iface);
519 struct keyitem_pair *pair;
521 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(key), item);
523 if ((pair = get_keyitem_pair(This, key)))
524 VariantCopy(item, &pair->item);
525 else {
526 VariantInit(item);
527 return IDictionary_Add(iface, key, item);
530 return S_OK;
533 static HRESULT WINAPI dictionary_Add(IDictionary *iface, VARIANT *key, VARIANT *item)
535 dictionary *This = impl_from_IDictionary(iface);
537 TRACE("(%p)->(%s %s)\n", This, debugstr_variant(key), debugstr_variant(item));
539 if (get_keyitem_pair(This, key))
540 return CTL_E_KEY_ALREADY_EXISTS;
542 return add_keyitem_pair(This, key, item);
545 static HRESULT WINAPI dictionary_get_Count(IDictionary *iface, LONG *count)
547 dictionary *This = impl_from_IDictionary(iface);
549 TRACE("(%p)->(%p)\n", This, count);
551 *count = This->count;
552 return S_OK;
555 static HRESULT WINAPI dictionary_Exists(IDictionary *iface, VARIANT *key, VARIANT_BOOL *exists)
557 dictionary *This = impl_from_IDictionary(iface);
559 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(key), exists);
561 if (!exists)
562 return CTL_E_ILLEGALFUNCTIONCALL;
564 *exists = get_keyitem_pair(This, key) != NULL ? VARIANT_TRUE : VARIANT_FALSE;
565 return S_OK;
568 static HRESULT WINAPI dictionary_Items(IDictionary *iface, VARIANT *items)
570 dictionary *This = impl_from_IDictionary(iface);
571 struct keyitem_pair *pair;
572 SAFEARRAYBOUND bound;
573 SAFEARRAY *sa;
574 VARIANT *v;
575 HRESULT hr;
576 LONG i;
578 TRACE("(%p)->(%p)\n", This, items);
580 if (!items)
581 return S_OK;
583 bound.lLbound = 0;
584 bound.cElements = This->count;
585 sa = SafeArrayCreate(VT_VARIANT, 1, &bound);
586 if (!sa)
587 return E_OUTOFMEMORY;
589 hr = SafeArrayAccessData(sa, (void**)&v);
590 if (FAILED(hr)) {
591 SafeArrayDestroy(sa);
592 return hr;
595 i = 0;
596 LIST_FOR_EACH_ENTRY(pair, &This->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 dictionary *This = impl_from_IDictionary(iface);
610 struct keyitem_pair *pair;
611 VARIANT empty;
612 HRESULT hr;
614 TRACE("(%p)->(%s %s)\n", This, debugstr_variant(key), debugstr_variant(newkey));
616 if ((pair = get_keyitem_pair(This, key))) {
617 /* found existing pair for a key, add new pair with new key
618 and old item and remove old pair after that */
620 hr = IDictionary_Add(iface, newkey, &pair->item);
621 if (FAILED(hr))
622 return hr;
624 return IDictionary_Remove(iface, key);
627 VariantInit(&empty);
628 return IDictionary_Add(iface, newkey, &empty);
631 static HRESULT WINAPI dictionary_Keys(IDictionary *iface, VARIANT *keys)
633 dictionary *This = impl_from_IDictionary(iface);
634 struct keyitem_pair *pair;
635 SAFEARRAYBOUND bound;
636 SAFEARRAY *sa;
637 VARIANT *v;
638 HRESULT hr;
639 LONG i;
641 TRACE("(%p)->(%p)\n", This, keys);
643 if (!keys)
644 return S_OK;
646 bound.lLbound = 0;
647 bound.cElements = This->count;
648 sa = SafeArrayCreate(VT_VARIANT, 1, &bound);
649 if (!sa)
650 return E_OUTOFMEMORY;
652 hr = SafeArrayAccessData(sa, (void**)&v);
653 if (FAILED(hr)) {
654 SafeArrayDestroy(sa);
655 return hr;
658 i = 0;
659 LIST_FOR_EACH_ENTRY(pair, &This->pairs, struct keyitem_pair, entry) {
660 VariantCopy(&v[i], &pair->key);
661 i++;
663 SafeArrayUnaccessData(sa);
665 V_VT(keys) = VT_ARRAY|VT_VARIANT;
666 V_ARRAY(keys) = sa;
667 return S_OK;
670 static HRESULT WINAPI dictionary_Remove(IDictionary *iface, VARIANT *key)
672 dictionary *This = impl_from_IDictionary(iface);
673 struct keyitem_pair *pair;
675 TRACE("(%p)->(%s)\n", This, debugstr_variant(key));
677 if (!(pair = get_keyitem_pair(This, key)))
678 return CTL_E_ELEMENT_NOT_FOUND;
680 notify_remove_pair(&This->notifier, &pair->entry);
681 list_remove(&pair->entry);
682 list_remove(&pair->bucket);
683 This->count--;
685 free_keyitem_pair(pair);
686 return S_OK;
689 static HRESULT WINAPI dictionary_RemoveAll(IDictionary *iface)
691 dictionary *This = impl_from_IDictionary(iface);
692 struct keyitem_pair *pair, *pair2;
694 TRACE("(%p)\n", This);
696 if (This->count == 0)
697 return S_OK;
699 notify_remove_pair(&This->notifier, NULL);
700 LIST_FOR_EACH_ENTRY_SAFE(pair, pair2, &This->pairs, struct keyitem_pair, entry) {
701 list_remove(&pair->entry);
702 list_remove(&pair->bucket);
703 free_keyitem_pair(pair);
705 This->count = 0;
707 return S_OK;
710 static HRESULT WINAPI dictionary_put_CompareMode(IDictionary *iface, CompareMethod method)
712 dictionary *This = impl_from_IDictionary(iface);
714 TRACE("(%p)->(%d)\n", This, method);
716 if (This->count)
717 return CTL_E_ILLEGALFUNCTIONCALL;
719 This->method = method;
720 return S_OK;
723 static HRESULT WINAPI dictionary_get_CompareMode(IDictionary *iface, CompareMethod *method)
725 dictionary *This = impl_from_IDictionary(iface);
727 TRACE("(%p)->(%p)\n", This, method);
729 *method = This->method;
730 return S_OK;
733 static HRESULT WINAPI dictionary__NewEnum(IDictionary *iface, IUnknown **ret)
735 dictionary *This = impl_from_IDictionary(iface);
737 TRACE("(%p)->(%p)\n", This, ret);
739 return create_dict_enum(This, ret);
742 static DWORD get_str_hash(const WCHAR *str, CompareMethod method)
744 DWORD hash = 0;
746 if (str) {
747 while (*str) {
748 WCHAR ch;
750 ch = (method == TextCompare || method == DatabaseCompare) ? tolowerW(*str) : *str;
752 hash += (hash << 4) + ch;
753 str++;
757 return hash % DICT_HASH_MOD;
760 static DWORD get_num_hash(FLOAT num)
762 return (*((DWORD*)&num)) % DICT_HASH_MOD;
765 static HRESULT get_flt_hash(FLOAT flt, LONG *hash)
767 if (isinf(flt)) {
768 *hash = 0;
769 return S_OK;
771 else if (!isnan(flt)) {
772 *hash = get_num_hash(flt);
773 return S_OK;
776 /* NaN case */
777 *hash = ~0u;
778 return CTL_E_ILLEGALFUNCTIONCALL;
781 static DWORD get_ptr_hash(void *ptr)
783 return PtrToUlong(ptr) % DICT_HASH_MOD;
786 static HRESULT WINAPI dictionary_get_HashVal(IDictionary *iface, VARIANT *key, VARIANT *hash)
788 dictionary *This = impl_from_IDictionary(iface);
790 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(key), hash);
792 V_VT(hash) = VT_I4;
793 switch (V_VT(key))
795 case VT_BSTR|VT_BYREF:
796 case VT_BSTR:
797 V_I4(hash) = get_str_hash(get_key_strptr(key), This->method);
798 break;
799 case VT_UI1|VT_BYREF:
800 case VT_UI1:
801 V_I4(hash) = get_num_hash(V_VT(key) & VT_BYREF ? *V_UI1REF(key) : V_UI1(key));
802 break;
803 case VT_I2|VT_BYREF:
804 case VT_I2:
805 V_I4(hash) = get_num_hash(V_VT(key) & VT_BYREF ? *V_I2REF(key) : V_I2(key));
806 break;
807 case VT_I4|VT_BYREF:
808 case VT_I4:
809 V_I4(hash) = get_num_hash(V_VT(key) & VT_BYREF ? *V_I4REF(key) : V_I4(key));
810 break;
811 case VT_UNKNOWN|VT_BYREF:
812 case VT_DISPATCH|VT_BYREF:
813 case VT_UNKNOWN:
814 case VT_DISPATCH:
816 IUnknown *src = (V_VT(key) & VT_BYREF) ? *V_UNKNOWNREF(key) : V_UNKNOWN(key);
817 IUnknown *unk = NULL;
819 if (!src) {
820 V_I4(hash) = 0;
821 return S_OK;
824 IUnknown_QueryInterface(src, &IID_IUnknown, (void**)&unk);
825 if (!unk) {
826 V_I4(hash) = ~0u;
827 return CTL_E_ILLEGALFUNCTIONCALL;
829 V_I4(hash) = get_ptr_hash(unk);
830 IUnknown_Release(unk);
831 break;
833 case VT_DATE|VT_BYREF:
834 case VT_DATE:
835 return get_flt_hash(V_VT(key) & VT_BYREF ? *V_DATEREF(key) : V_DATE(key), &V_I4(hash));
836 case VT_R4|VT_BYREF:
837 case VT_R4:
838 return get_flt_hash(V_VT(key) & VT_BYREF ? *V_R4REF(key) : V_R4(key), &V_I4(hash));
839 case VT_R8|VT_BYREF:
840 case VT_R8:
841 return get_flt_hash(V_VT(key) & VT_BYREF ? *V_R8REF(key) : V_R8(key), &V_I4(hash));
842 case VT_INT:
843 case VT_UINT:
844 case VT_I1:
845 case VT_I8:
846 case VT_UI2:
847 case VT_UI4:
848 V_I4(hash) = ~0u;
849 return CTL_E_ILLEGALFUNCTIONCALL;
850 default:
851 FIXME("not implemented for type %d\n", V_VT(key));
852 return E_NOTIMPL;
855 return S_OK;
858 static const struct IDictionaryVtbl dictionary_vtbl =
860 dictionary_QueryInterface,
861 dictionary_AddRef,
862 dictionary_Release,
863 dictionary_GetTypeInfoCount,
864 dictionary_GetTypeInfo,
865 dictionary_GetIDsOfNames,
866 dictionary_Invoke,
867 dictionary_putref_Item,
868 dictionary_put_Item,
869 dictionary_get_Item,
870 dictionary_Add,
871 dictionary_get_Count,
872 dictionary_Exists,
873 dictionary_Items,
874 dictionary_put_Key,
875 dictionary_Keys,
876 dictionary_Remove,
877 dictionary_RemoveAll,
878 dictionary_put_CompareMode,
879 dictionary_get_CompareMode,
880 dictionary__NewEnum,
881 dictionary_get_HashVal
884 HRESULT WINAPI Dictionary_CreateInstance(IClassFactory *factory,IUnknown *outer,REFIID riid, void **obj)
886 dictionary *This;
888 TRACE("(%p)\n", obj);
890 *obj = NULL;
892 This = heap_alloc(sizeof(*This));
893 if(!This) return E_OUTOFMEMORY;
895 This->IDictionary_iface.lpVtbl = &dictionary_vtbl;
896 This->ref = 1;
897 This->method = BinaryCompare;
898 This->count = 0;
899 list_init(&This->pairs);
900 list_init(&This->notifier);
901 memset(This->buckets, 0, sizeof(This->buckets));
903 *obj = &This->IDictionary_iface;
905 return S_OK;