From 5189dc417aa2c4fb95c46a3446d2b69e03230ad0 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Sat, 21 Mar 2015 23:30:56 +0300 Subject: [PATCH] scrrun: Added support for interface pointers as keys for dictionary. --- dlls/scrrun/dictionary.c | 34 +++++- dlls/scrrun/tests/dictionary.c | 214 ++++++++++++++++++++++++++++++++- 2 files changed, 242 insertions(+), 6 deletions(-) diff --git a/dlls/scrrun/dictionary.c b/dlls/scrrun/dictionary.c index 5c770b6559..24ca094ebb 100644 --- a/dlls/scrrun/dictionary.c +++ b/dlls/scrrun/dictionary.c @@ -37,7 +37,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(scrrun); -#define BUCKET_COUNT 509 +#define BUCKET_COUNT 509 +#define DICT_HASH_MOD 1201 /* Implementation details @@ -752,12 +753,17 @@ static DWORD get_str_hash(const WCHAR *str, CompareMethod method) } } - return hash % 1201; + return hash % DICT_HASH_MOD; } static DWORD get_num_hash(FLOAT num) { - return (*((DWORD*)&num)) % 1201; + return (*((DWORD*)&num)) % DICT_HASH_MOD; +} + +static DWORD get_ptr_hash(void *ptr) +{ + return PtrToUlong(ptr) % DICT_HASH_MOD; } static HRESULT WINAPI dictionary_get_HashVal(IDictionary *iface, VARIANT *key, VARIANT *hash) @@ -782,6 +788,28 @@ static HRESULT WINAPI dictionary_get_HashVal(IDictionary *iface, VARIANT *key, V case VT_I4: V_I4(hash) = get_num_hash(V_I4(key)); break; + case VT_UNKNOWN|VT_BYREF: + case VT_DISPATCH|VT_BYREF: + case VT_UNKNOWN: + case VT_DISPATCH: + { + IUnknown *src = (V_VT(key) & VT_BYREF) ? *V_UNKNOWNREF(key) : V_UNKNOWN(key); + IUnknown *unk = NULL; + + if (!src) { + V_I4(hash) = 0; + return S_OK; + } + + IUnknown_QueryInterface(src, &IID_IUnknown, (void**)&unk); + if (!unk) { + V_I4(hash) = ~0u; + return CTL_E_ILLEGALFUNCTIONCALL; + } + V_I4(hash) = get_ptr_hash(unk); + IUnknown_Release(unk); + break; + } case VT_R4: case VT_R8: { diff --git a/dlls/scrrun/tests/dictionary.c b/dlls/scrrun/tests/dictionary.c index 18698610aa..de6531081f 100644 --- a/dlls/scrrun/tests/dictionary.c +++ b/dlls/scrrun/tests/dictionary.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2012 Alistair Leslie-Hughes + * Copyright 2015 Nikolay Sivov for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -160,6 +161,11 @@ static DWORD get_num_hash(FLOAT num) return (*((DWORD*)&num)) % 1201; } +static DWORD get_ptr_hash(void *ptr) +{ + return PtrToUlong(ptr) % 1201; +} + typedef union { struct @@ -183,6 +189,110 @@ typedef union double d; } R8_FIELDS; +static HRESULT WINAPI test_unk_QI(IUnknown *iface, REFIID riid, void **obj) +{ + if (IsEqualIID(riid, &IID_IUnknown)) { + *obj = iface; + return S_OK; + } + + ok(0, "unexpected %s\n", wine_dbgstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; +} + +static HRESULT WINAPI test_unk_no_QI(IUnknown *iface, REFIID riid, void **obj) +{ + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI test_unk_AddRef(IUnknown *iface) +{ + ok(0, "unxpected\n"); + return 2; +} + +static ULONG WINAPI test_unk_Release(IUnknown *iface) +{ + return 1; +} + +static const IUnknownVtbl test_unk_vtbl = { + test_unk_QI, + test_unk_AddRef, + test_unk_Release +}; + +static const IUnknownVtbl test_unk_no_vtbl = { + test_unk_no_QI, + test_unk_AddRef, + test_unk_Release +}; + +static HRESULT WINAPI test_disp_QI(IDispatch *iface, REFIID riid, void **obj) +{ + if (IsEqualIID(riid, &IID_IDispatch) || IsEqualIID(riid, &IID_IUnknown)) { + *obj = iface; + return S_OK; + } + + ok(0, "unexpected %s\n", wine_dbgstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI test_disp_AddRef(IDispatch *iface) +{ + ok(0, "unxpected\n"); + return 2; +} + +static ULONG WINAPI test_disp_Release(IDispatch *iface) +{ + return 1; +} + +static HRESULT WINAPI test_disp_GetTypeInfoCount(IDispatch *iface, UINT *count) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_disp_GetTypeInfo(IDispatch *iface, UINT index, LCID lcid, ITypeInfo **ti) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_disp_GetIDsOfNames(IDispatch *iface, REFIID riid, LPOLESTR *names, + UINT name_count, LCID lcid, DISPID *dispid) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_disp_Invoke(IDispatch *iface, DISPID dispid, REFIID riid, + LCID lcid, WORD flags, DISPPARAMS *params, VARIANT *result, EXCEPINFO *excepinfo, UINT *arg_err) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static const IDispatchVtbl test_disp_vtbl = { + test_disp_QI, + test_disp_AddRef, + test_disp_Release, + test_disp_GetTypeInfoCount, + test_disp_GetTypeInfo, + test_disp_GetIDsOfNames, + test_disp_Invoke +}; + +static IUnknown test_unk = { &test_unk_vtbl }; +static IUnknown test_unk2 = { &test_unk_no_vtbl }; +static IDispatch test_disp = { &test_disp_vtbl }; + static void test_hash_value(void) { /* string test data */ @@ -205,6 +315,9 @@ static void test_hash_value(void) IDictionary *dict; VARIANT key, hash; + IDispatch *disp; + DWORD expected; + IUnknown *unk; R8_FIELDS fx8; R4_FIELDS fx4; HRESULT hr; @@ -223,7 +336,7 @@ static void test_hash_value(void) ok(V_I4(&hash) == 0, "got %d\n", V_I4(&hash)); for (i = 0; i < sizeof(str_hash_tests)/sizeof(str_hash_tests[0]); i++) { - DWORD expected = get_str_hash(str_hash_tests[i], BinaryCompare); + expected = get_str_hash(str_hash_tests[i], BinaryCompare); hr = IDictionary_put_CompareMode(dict, BinaryCompare); ok(hr == S_OK, "got 0x%08x\n", hr); @@ -316,7 +429,7 @@ static void test_hash_value(void) ok(V_I4(&hash) == ~0u, "got hash 0x%08x\n", V_I4(&hash)); for (i = 0; i < sizeof(int_hash_tests)/sizeof(int_hash_tests[0]); i++) { - DWORD expected = get_num_hash(int_hash_tests[i]); + expected = get_num_hash(int_hash_tests[i]); V_VT(&key) = VT_I2; V_I2(&key) = int_hash_tests[i]; @@ -401,7 +514,7 @@ static void test_hash_value(void) ok(V_I4(&hash) == 0, "got hash 0x%08x\n", V_I4(&hash)); for (i = 0; i < sizeof(float_hash_tests)/sizeof(float_hash_tests[0]); i++) { - DWORD expected = get_num_hash(float_hash_tests[i]); + expected = get_num_hash(float_hash_tests[i]); V_VT(&key) = VT_R4; V_R4(&key) = float_hash_tests[i]; @@ -422,6 +535,101 @@ static void test_hash_value(void) expected); } + /* interface pointers as keys */ + V_VT(&key) = VT_UNKNOWN; + V_UNKNOWN(&key) = 0; + VariantInit(&hash); + V_I4(&hash) = 1; + hr = IDictionary_get_HashVal(dict, &key, &hash); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(V_VT(&hash) == VT_I4, "got %d\n", V_VT(&hash)); + ok(V_I4(&hash) == 0, "got hash 0x%08x, expected 0\n", V_I4(&hash)); + + /* QI doesn't work */ + V_VT(&key) = VT_UNKNOWN; + V_UNKNOWN(&key) = &test_unk2; + VariantInit(&hash); + expected = get_ptr_hash(&test_unk2); + hr = IDictionary_get_HashVal(dict, &key, &hash); + ok(hr == CTL_E_ILLEGALFUNCTIONCALL || broken(hr == S_OK) /* win2k */, "got 0x%08x\n", hr); + ok(V_VT(&hash) == VT_I4, "got %d\n", V_VT(&hash)); + ok(V_I4(&hash) == ~0u, "got hash 0x%08x, expected 0x%08x\n", V_I4(&hash), expected); + + V_VT(&key) = VT_UNKNOWN; + V_UNKNOWN(&key) = &test_unk; + VariantInit(&hash); + expected = get_ptr_hash(&test_unk); + hr = IDictionary_get_HashVal(dict, &key, &hash); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(V_VT(&hash) == VT_I4, "got %d\n", V_VT(&hash)); + ok(V_I4(&hash) == expected, "got hash 0x%08x, expected 0x%08x\n", V_I4(&hash), expected); + + /* interface without IDispatch support */ + V_VT(&key) = VT_DISPATCH; + V_DISPATCH(&key) = (IDispatch*)&test_unk; + VariantInit(&hash); + expected = get_ptr_hash(&test_unk); + hr = IDictionary_get_HashVal(dict, &key, &hash); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(V_VT(&hash) == VT_I4, "got %d\n", V_VT(&hash)); + ok(V_I4(&hash) == expected, "got hash 0x%08x, expected 0x%08x\n", V_I4(&hash), expected); + + V_VT(&key) = VT_DISPATCH; + V_DISPATCH(&key) = &test_disp; + VariantInit(&hash); + expected = get_ptr_hash(&test_disp); + hr = IDictionary_get_HashVal(dict, &key, &hash); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(V_VT(&hash) == VT_I4, "got %d\n", V_VT(&hash)); + ok(V_I4(&hash) == expected, "got hash 0x%08x, expected 0x%08x\n", V_I4(&hash), expected); + + /* same with BYREF */ +if (0) { /* crashes on native */ + V_VT(&key) = VT_UNKNOWN|VT_BYREF; + V_UNKNOWNREF(&key) = 0; + hr = IDictionary_get_HashVal(dict, &key, &hash); +} + unk = NULL; + V_VT(&key) = VT_UNKNOWN|VT_BYREF; + V_UNKNOWNREF(&key) = &unk; + VariantInit(&hash); + V_I4(&hash) = 1; + hr = IDictionary_get_HashVal(dict, &key, &hash); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(V_VT(&hash) == VT_I4, "got %d\n", V_VT(&hash)); + ok(V_I4(&hash) == 0, "got hash 0x%08x, expected 0\n", V_I4(&hash)); + + V_VT(&key) = VT_UNKNOWN|VT_BYREF; + unk = &test_unk; + V_UNKNOWNREF(&key) = &unk; + VariantInit(&hash); + expected = get_ptr_hash(&test_unk); + hr = IDictionary_get_HashVal(dict, &key, &hash); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(V_VT(&hash) == VT_I4, "got %d\n", V_VT(&hash)); + ok(V_I4(&hash) == expected, "got hash 0x%08x, expected 0x%08x\n", V_I4(&hash), expected); + + /* interface without IDispatch support */ + V_VT(&key) = VT_DISPATCH|VT_BYREF; + unk = &test_unk; + V_DISPATCHREF(&key) = (IDispatch**)&unk; + VariantInit(&hash); + expected = get_ptr_hash(&test_unk); + hr = IDictionary_get_HashVal(dict, &key, &hash); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(V_VT(&hash) == VT_I4, "got %d\n", V_VT(&hash)); + ok(V_I4(&hash) == expected, "got hash 0x%08x, expected 0x%08x\n", V_I4(&hash), expected); + + V_VT(&key) = VT_DISPATCH|VT_BYREF; + disp = &test_disp; + V_DISPATCHREF(&key) = &disp; + VariantInit(&hash); + expected = get_ptr_hash(&test_disp); + hr = IDictionary_get_HashVal(dict, &key, &hash); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(V_VT(&hash) == VT_I4, "got %d\n", V_VT(&hash)); + ok(V_I4(&hash) == expected, "got hash 0x%08x, expected 0x%08x\n", V_I4(&hash), expected); + IDictionary_Release(dict); }