-- v2: wintypes: Introduce a locked IMap<HSTRING, IInspectable> implementation. wintypes: Introduce a serial to track IMap state changes. wintypes: Implement a generic IMap<HSTRING, IInspectable>. wintypes: Introduce a generic IMap stub implementation. wintypes/tests: Check IAgileObject interface on map objects. wintypes/tests: Add tests for IMapView. wintypes/tests: Add tests for PropertySet::{Insert, Lookup, HasKey}.
From: Vibhav Pant vibhavp@gmail.com
--- dlls/wintypes/tests/wintypes.c | 177 +++++++++++++++++++++++++++++---- 1 file changed, 158 insertions(+), 19 deletions(-)
diff --git a/dlls/wintypes/tests/wintypes.c b/dlls/wintypes/tests/wintypes.c index ebdf5acbadf..24d64f849b5 100644 --- a/dlls/wintypes/tests/wintypes.c +++ b/dlls/wintypes/tests/wintypes.c @@ -1256,15 +1256,17 @@ static void test_IPropertySet(void) { static const WCHAR *class_name = RuntimeClass_Windows_Foundation_Collections_PropertySet; IActivationFactory *propset_factory; - IInspectable *inspectable; + IPropertyValueStatics *propval_statics; + IInspectable *inspectable, *val, *val1, *val2, *val3; IPropertySet *propset; IMap_HSTRING_IInspectable *map; IMapView_HSTRING_IInspectable *map_view; IObservableMap_HSTRING_IInspectable *observable_map; IIterable_IKeyValuePair_HSTRING_IInspectable *iterable; IIterator_IKeyValuePair_HSTRING_IInspectable *iterator; + BOOLEAN boolean; HRESULT hr; - HSTRING name; + HSTRING name, key1, key2;
hr = RoInitialize( RO_INIT_MULTITHREADED ); ok( hr == S_OK, "got %#lx\n", hr ); @@ -1280,6 +1282,19 @@ static void test_IPropertySet(void) goto done; }
+ class_name = RuntimeClass_Windows_Foundation_PropertyValue; + hr = WindowsCreateString( class_name, wcslen( class_name ), &name ); + ok( hr == S_OK, "got %#lx\n", hr ); + hr = RoGetActivationFactory( name, &IID_IPropertyValueStatics, (void **)&propval_statics); + WindowsDeleteString( name ); + ok( hr == S_OK || broken( hr == REGDB_E_CLASSNOTREG ), "RoGetActivationFactory failed, hr %#lx.\n", hr ); + if (hr != S_OK) + { + win_skip( "%s runtimeclass not registered, skipping tests.\n", wine_dbgstr_w( class_name ) ); + IActivationFactory_Release( propset_factory ); + goto done; + } + hr = IActivationFactory_ActivateInstance( propset_factory, &inspectable ); IActivationFactory_Release( propset_factory ); ok( hr == S_OK, "got %#lx\n", hr ); @@ -1296,6 +1311,134 @@ static void test_IPropertySet(void) IPropertySet_Release( propset ); ok( hr == S_OK, "QueryInterface failed, got %#lx\n", hr );
+ boolean = TRUE; + hr = IMap_HSTRING_IInspectable_HasKey( map, NULL, &boolean ); + todo_wine + ok( hr == S_OK, "HasKey failed, got %#lx\n", hr ); + todo_wine + ok( !boolean, "Got boolean %d.\n", boolean ); + hr = IMap_HSTRING_IInspectable_Lookup( map, NULL, &val ); + todo_wine + ok( hr == E_BOUNDS, "Got hr %#lx\n", hr ); + + hr = IPropertyValueStatics_CreateUInt32( propval_statics, 0xdeadbeef, &val1 ); + ok( hr == S_OK, "CreateUInt32 failed, got %#lx\n", hr ); + boolean = TRUE; + hr = IMap_HSTRING_IInspectable_Insert( map, NULL, val1, &boolean ); + todo_wine + ok( hr == S_OK, "Insert failed, got %#lx\n", hr ); + todo_wine + ok( !boolean, "Got boolean %d.\n", boolean ); + + hr = IPropertyValueStatics_CreateUInt32( propval_statics, 0xc0decafe, &val2 ); + ok( hr == S_OK, "CreateUInt32 failed, got %#lx\n", hr ); + boolean = FALSE; + hr = IMap_HSTRING_IInspectable_Insert( map, NULL, val2, &boolean ); + IInspectable_Release( val2 ); + todo_wine + ok( boolean, "Got boolean %d.\n", boolean ); + todo_wine + ok( hr == S_OK, "Insert failed, got %#lx\n", hr ); + boolean = FALSE; + hr = IMap_HSTRING_IInspectable_HasKey( map, NULL, &boolean ); + todo_wine + ok( hr == S_OK, "HasKey failed, got %#lx\n", hr ); + todo_wine + ok( boolean, "Got boolean %d.\n", boolean ); + hr = IMap_HSTRING_IInspectable_Lookup( map, NULL, &val ); + todo_wine + ok( hr == S_OK, "Lookup failed, got %#lx\n", hr ); + if (SUCCEEDED(hr)) + { + IPropertyValue *propval; + UINT32 uint32 = 0; + + hr = IInspectable_QueryInterface( val, &IID_IPropertyValue, (void **)&propval ); + IInspectable_Release( val ); + ok( hr == S_OK, "QueryInterface failed, got %#lx\n", hr ); + hr = IPropertyValue_GetUInt32( propval, &uint32 ); + IPropertyValue_Release( propval ); + ok( hr == S_OK, "GetUInt32, got %#lx\n", hr ); + ok( uint32 == 0xc0decafe, "Got uint32 %u\n", uint32 ); + } + + hr = WindowsCreateString( L"foo", 3, &key1 ); + ok( hr == S_OK, "WindowsCreateString failed, got %#lx\n", hr ); + boolean = TRUE; + hr = IMap_HSTRING_IInspectable_Lookup( map, key1, &val ); + todo_wine + ok( hr == E_BOUNDS, "Got hr %#lx\n", hr ); + hr = IMap_HSTRING_IInspectable_Insert( map, key1, val1, &boolean ); + IInspectable_Release( val1 ); + todo_wine + ok( hr == S_OK, "Insert failed, got %#lx\n", hr ); + todo_wine + ok( !boolean, "Got boolean %d.\n", boolean ); + boolean = FALSE; + hr = IMap_HSTRING_IInspectable_HasKey( map, key1, &boolean ); + todo_wine + ok( hr == S_OK, "HasKey failed, got %#lx\n", hr ); + todo_wine + ok( boolean, "Got boolean %d.\n", boolean ); + hr = IMap_HSTRING_IInspectable_Lookup( map, key1, &val ); + todo_wine + ok( hr == S_OK, "Lookup failed, got %#lx\n", hr ); + if (SUCCEEDED(hr)) + { + IPropertyValue *propval; + UINT32 uint32 = 0; + + hr = IInspectable_QueryInterface( val, &IID_IPropertyValue, (void **)&propval ); + IInspectable_Release( val ); + ok( hr == S_OK, "QueryInterface failed, got %#lx\n", hr ); + hr = IPropertyValue_GetUInt32( propval, &uint32 ); + IPropertyValue_Release( propval ); + ok( hr == S_OK, "GetUInt32, got %#lx\n", hr ); + ok( uint32 == 0xdeadbeef, "Got uint32 %u\n", uint32 ); + } + WindowsDeleteString( key1 ); + + hr = WindowsCreateString( L"bar", 3, &key2 ); + ok( hr == S_OK, "WindowsCreateString failed, got %#lx\n", hr ); + boolean = TRUE; + hr = IMap_HSTRING_IInspectable_HasKey( map, key2, &boolean ); + todo_wine + ok( hr == S_OK, "HasKey failed, got %#lx\n", hr ); + todo_wine + ok( !boolean, "Got boolean %d.\n", boolean ); + hr = IPropertyValueStatics_CreateUInt64( propval_statics, 0xdeadbeefdeadbeef, &val3 ); + ok( hr == S_OK, "CreateUInt32 failed, got %#lx\n", hr ); + boolean = TRUE; + hr = IMap_HSTRING_IInspectable_Insert( map, key2, val3, &boolean ); + IInspectable_Release( val3 ); + todo_wine + ok( hr == S_OK, "Insert failed, got %#lx\n", hr ); + todo_wine + ok( !boolean, "Got boolean %d.\n", boolean ); + boolean = FALSE; + hr = IMap_HSTRING_IInspectable_HasKey( map, key2, &boolean ); + todo_wine + ok( hr == S_OK, "HasKey failed, got %#lx\n", hr ); + todo_wine + ok( boolean, "Got boolean %d.\n", boolean ); + hr = IMap_HSTRING_IInspectable_Lookup( map, key2, &val ); + todo_wine + ok( hr == S_OK, "Lookup failed, got %#lx\n", hr ); + if (SUCCEEDED(hr)) + { + IPropertyValue *propval; + UINT64 uint64 = 0; + + hr = IInspectable_QueryInterface( val, &IID_IPropertyValue, (void **)&propval ); + IInspectable_Release( val ); + ok( hr == S_OK, "QueryInterface failed, got %#lx\n", hr ); + hr = IPropertyValue_GetUInt64( propval, &uint64 ); + IPropertyValue_Release( propval ); + ok( hr == S_OK, "GetUInt32, got %#lx\n", hr ); + ok( uint64 == 0xdeadbeefdeadbeef, "Got uint64 %I64u\n", uint64 ); + } + WindowsDeleteString( key2 ); + hr = IMap_HSTRING_IInspectable_QueryInterface( map, &IID_IIterable_IKeyValuePair_HSTRING_IInspectable, (void **)&iterable ); ok( hr == S_OK, "QueryInterface failed, got %#lx\n", hr ); @@ -1309,24 +1452,20 @@ static void test_IPropertySet(void) hr = IMap_HSTRING_IInspectable_GetView( map, &map_view ); todo_wine ok( hr == S_OK, "GetView failed, got %#lx\n", hr ); - if (SUCCEEDED( hr )) - { - hr = IMapView_HSTRING_IInspectable_QueryInterface( map_view, &IID_IIterable_IKeyValuePair_HSTRING_IInspectable, - (void **)&iterable ); - todo_wine - ok( hr == S_OK, "QueryInterface failed, got %#lx\n", hr ); - if (SUCCEEDED( hr )) - { - hr = IIterable_IKeyValuePair_HSTRING_IInspectable_First( iterable, &iterator ); - todo_wine - ok( hr == S_OK, "got %#lx\n", hr ); - if (SUCCEEDED( hr )) - IIterator_IKeyValuePair_HSTRING_IInspectable_Release( iterator ); - IIterable_IKeyValuePair_HSTRING_IInspectable_Release( iterable ); - } - IMapView_HSTRING_IInspectable_Release( map_view ); - } + if (FAILED( hr )) goto skip_test; + + hr = IMapView_HSTRING_IInspectable_QueryInterface( map_view, &IID_IIterable_IKeyValuePair_HSTRING_IInspectable, + (void **)&iterable ); + ok( hr == S_OK, "QueryInterface failed, got %#lx\n", hr ); + hr = IIterable_IKeyValuePair_HSTRING_IInspectable_First( iterable, &iterator ); + ok( hr == S_OK, "got %#lx\n", hr ); + IIterator_IKeyValuePair_HSTRING_IInspectable_Release( iterator ); + IIterable_IKeyValuePair_HSTRING_IInspectable_Release( iterable ); + IMapView_HSTRING_IInspectable_Release( map_view ); + +skip_test: IMap_HSTRING_IInspectable_Release( map ); + IPropertyValueStatics_Release( propval_statics ); done: RoUninitialize(); }
From: Vibhav Pant vibhavp@gmail.com
--- dlls/wintypes/tests/wintypes.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-)
diff --git a/dlls/wintypes/tests/wintypes.c b/dlls/wintypes/tests/wintypes.c index 24d64f849b5..71a1977f35a 100644 --- a/dlls/wintypes/tests/wintypes.c +++ b/dlls/wintypes/tests/wintypes.c @@ -1437,7 +1437,6 @@ static void test_IPropertySet(void) ok( hr == S_OK, "GetUInt32, got %#lx\n", hr ); ok( uint64 == 0xdeadbeefdeadbeef, "Got uint64 %I64u\n", uint64 ); } - WindowsDeleteString( key2 );
hr = IMap_HSTRING_IInspectable_QueryInterface( map, &IID_IIterable_IKeyValuePair_HSTRING_IInspectable, (void **)&iterable ); @@ -1454,6 +1453,28 @@ static void test_IPropertySet(void) ok( hr == S_OK, "GetView failed, got %#lx\n", hr ); if (FAILED( hr )) goto skip_test;
+ hr = IMapView_HSTRING_IInspectable_QueryInterface( map_view, &IID_IIterable_IKeyValuePair_HSTRING_IInspectable, + (void **)&iterable ); + ok( hr == S_OK, "QueryInterface failed, got %#lx\n", hr ); + hr = IMapView_HSTRING_IInspectable_Lookup( map_view, key2, &val ); + todo_wine + ok( hr == S_OK, "Lookup failed, got %#lx\n", hr ); + if (SUCCEEDED(hr)) IInspectable_Release( val ); + hr = IMap_HSTRING_IInspectable_Remove( map, key2 ); + todo_wine + ok( hr == S_OK, "Remove failed, got %#lx\n", hr ); + hr = IMapView_HSTRING_IInspectable_Lookup( map_view, key2, &val ); + todo_wine + ok( hr == E_CHANGED_STATE, "Got hr %#lx\n", hr ); + WindowsDeleteString( key2 ); + hr = IIterable_IKeyValuePair_HSTRING_IInspectable_First( iterable, &iterator ); + todo_wine + ok( hr == E_CHANGED_STATE, "got %#lx\n", hr ); + IIterable_IKeyValuePair_HSTRING_IInspectable_Release( iterable ); + IMapView_HSTRING_IInspectable_Release( map_view ); + + hr = IMap_HSTRING_IInspectable_GetView( map, &map_view ); + ok( hr == S_OK, "GetView failed, got %#lx\n", hr ); hr = IMapView_HSTRING_IInspectable_QueryInterface( map_view, &IID_IIterable_IKeyValuePair_HSTRING_IInspectable, (void **)&iterable ); ok( hr == S_OK, "QueryInterface failed, got %#lx\n", hr );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/wintypes/tests/wintypes.c | 42 +++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-)
diff --git a/dlls/wintypes/tests/wintypes.c b/dlls/wintypes/tests/wintypes.c index 71a1977f35a..955f0e28988 100644 --- a/dlls/wintypes/tests/wintypes.c +++ b/dlls/wintypes/tests/wintypes.c @@ -1264,6 +1264,7 @@ static void test_IPropertySet(void) IObservableMap_HSTRING_IInspectable *observable_map; IIterable_IKeyValuePair_HSTRING_IInspectable *iterable; IIterator_IKeyValuePair_HSTRING_IInspectable *iterator; + IKeyValuePair_HSTRING_IInspectable *pair; BOOLEAN boolean; HRESULT hr; HSTRING name, key1, key2; @@ -1438,31 +1439,66 @@ static void test_IPropertySet(void) ok( uint64 == 0xdeadbeefdeadbeef, "Got uint64 %I64u\n", uint64 ); }
+ todo_wine check_interface( map, &IID_IAgileObject, TRUE ); hr = IMap_HSTRING_IInspectable_QueryInterface( map, &IID_IIterable_IKeyValuePair_HSTRING_IInspectable, (void **)&iterable ); ok( hr == S_OK, "QueryInterface failed, got %#lx\n", hr ); hr = IIterable_IKeyValuePair_HSTRING_IInspectable_First( iterable, &iterator ); todo_wine ok( hr == S_OK, "got %#lx\n", hr ); - if (SUCCEEDED( hr )) - IIterator_IKeyValuePair_HSTRING_IInspectable_Release( iterator ); IIterable_IKeyValuePair_HSTRING_IInspectable_Release( iterable ); + if (FAILED( hr )) goto skip_test; + + check_interface( iterator, &IID_IAgileObject, TRUE ); + hr = IIterator_IKeyValuePair_HSTRING_IInspectable_get_HasCurrent( iterator, &boolean ); + ok( hr == S_OK, "Got hr %#lx\n", hr ); + ok( boolean == TRUE, "Got %u\n", boolean ); + + hr = IIterator_IKeyValuePair_HSTRING_IInspectable_get_Current( iterator, &pair ); + ok( hr == S_OK, "Got hr %#lx\n", hr ); + check_interface( pair, &IID_IAgileObject, TRUE ); + hr = IKeyValuePair_HSTRING_IInspectable_get_Key( pair, &key2 ); + ok( hr == S_OK, "Got %#lx\n", hr ); + WindowsDeleteString( key2 ); + hr = IKeyValuePair_HSTRING_IInspectable_get_Value( pair, &val ); + ok( hr == S_OK, "Got %#lx\n", hr ); + IInspectable_Release( val );
hr = IMap_HSTRING_IInspectable_GetView( map, &map_view ); todo_wine ok( hr == S_OK, "GetView failed, got %#lx\n", hr ); if (FAILED( hr )) goto skip_test;
+ check_interface( map_view, &IID_IAgileObject, TRUE ); hr = IMapView_HSTRING_IInspectable_QueryInterface( map_view, &IID_IIterable_IKeyValuePair_HSTRING_IInspectable, (void **)&iterable ); ok( hr == S_OK, "QueryInterface failed, got %#lx\n", hr ); hr = IMapView_HSTRING_IInspectable_Lookup( map_view, key2, &val ); todo_wine ok( hr == S_OK, "Lookup failed, got %#lx\n", hr ); - if (SUCCEEDED(hr)) IInspectable_Release( val ); + IInspectable_Release( val ); + + + /* after map is modified, associated objects are invalidated */ hr = IMap_HSTRING_IInspectable_Remove( map, key2 ); todo_wine ok( hr == S_OK, "Remove failed, got %#lx\n", hr ); + + hr = IKeyValuePair_HSTRING_IInspectable_get_Key( pair, &key2 ); + ok( hr == S_OK, "Got %#lx\n", hr ); + WindowsDeleteString( key2 ); + hr = IKeyValuePair_HSTRING_IInspectable_get_Value( pair, &val ); + ok( hr == S_OK, "Got %#lx\n", hr ); + IInspectable_Release( val ); + IKeyValuePair_HSTRING_IInspectable_Release( pair ); + + hr = IIterator_IKeyValuePair_HSTRING_IInspectable_get_HasCurrent( iterator, &boolean ); + ok( hr == S_OK, "Got hr %#lx\n", hr ); + ok( boolean == TRUE, "Got %u\n", boolean ); + hr = IIterator_IKeyValuePair_HSTRING_IInspectable_get_Current( iterator, &pair ); + ok( hr == E_CHANGED_STATE, "Got hr %#lx\n", hr ); + IIterator_IKeyValuePair_HSTRING_IInspectable_Release( iterator ); + hr = IMapView_HSTRING_IInspectable_Lookup( map_view, key2, &val ); todo_wine ok( hr == E_CHANGED_STATE, "Got hr %#lx\n", hr );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/wintypes/Makefile.in | 1 + dlls/wintypes/map.c | 647 +++++++++++++++++++++++++++++ dlls/wintypes/private.h | 50 +++ dlls/wintypes/propertyset.c | 145 ++----- dlls/wintypes/tests/wintypes.c | 31 +- dlls/wintypes/wintypes_private.idl | 39 -- 6 files changed, 743 insertions(+), 170 deletions(-) create mode 100644 dlls/wintypes/map.c
diff --git a/dlls/wintypes/Makefile.in b/dlls/wintypes/Makefile.in index fd370133cf8..883d02f8b83 100644 --- a/dlls/wintypes/Makefile.in +++ b/dlls/wintypes/Makefile.in @@ -6,6 +6,7 @@ SOURCES = \ buffer.c \ classes.idl \ main.c \ + map.c \ propertyset.c \ storage.c \ wintypes_private.idl diff --git a/dlls/wintypes/map.c b/dlls/wintypes/map.c new file mode 100644 index 00000000000..8d92d204e77 --- /dev/null +++ b/dlls/wintypes/map.c @@ -0,0 +1,647 @@ +/* + * Copyright 2025 Rémi Bernon for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define COBJMACROS +#include <winstring.h> +#include <wine/debug.h> + +#include "private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(combase); + +struct pair +{ + IKeyValuePair_HSTRING_IInspectable IKeyValuePair_HSTRING_IInspectable_iface; + const GUID *iid; + LONG ref; +}; + +static struct pair *impl_from_IKeyValuePair_HSTRING_IInspectable( IKeyValuePair_HSTRING_IInspectable *iface ) +{ + return CONTAINING_RECORD( iface, struct pair, IKeyValuePair_HSTRING_IInspectable_iface ); +} + +static HRESULT WINAPI pair_QueryInterface( IKeyValuePair_HSTRING_IInspectable *iface, REFIID iid, void **out ) +{ + struct pair *impl = impl_from_IKeyValuePair_HSTRING_IInspectable( iface ); + + TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out ); + + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IInspectable ) || + IsEqualGUID( iid, &IID_IAgileObject ) || + IsEqualGUID( iid, impl->iid )) + { + IInspectable_AddRef( (*out = &impl->IKeyValuePair_HSTRING_IInspectable_iface) ); + return S_OK; + } + + FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI pair_AddRef( IKeyValuePair_HSTRING_IInspectable *iface ) +{ + struct pair *impl = impl_from_IKeyValuePair_HSTRING_IInspectable( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + TRACE( "iface %p increasing refcount to %lu.\n", iface, ref ); + return ref; +} + +static ULONG WINAPI pair_Release( IKeyValuePair_HSTRING_IInspectable *iface ) +{ + struct pair *impl = impl_from_IKeyValuePair_HSTRING_IInspectable( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + + TRACE( "iface %p decreasing refcount to %lu.\n", iface, ref ); + + if (!ref) + { + free( impl ); + } + + return ref; +} + +static HRESULT WINAPI pair_GetIids( IKeyValuePair_HSTRING_IInspectable *iface, ULONG *iid_count, IID **iids ) +{ + FIXME( "iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids ); + return E_NOTIMPL; +} + +static HRESULT WINAPI pair_GetRuntimeClassName( IKeyValuePair_HSTRING_IInspectable *iface, HSTRING *class_name ) +{ + FIXME( "iface %p, class_name %p stub!\n", iface, class_name ); + return E_NOTIMPL; +} + +static HRESULT WINAPI pair_GetTrustLevel( IKeyValuePair_HSTRING_IInspectable *iface, TrustLevel *trust_level ) +{ + FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level ); + return E_NOTIMPL; +} + +static HRESULT WINAPI pair_get_Key( IKeyValuePair_HSTRING_IInspectable *iface, HSTRING *value ) +{ + FIXME( "iface %p, value %p stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI pair_get_Value( IKeyValuePair_HSTRING_IInspectable *iface, IInspectable **value ) +{ + TRACE( "iface %p, value %p stub!\n", iface, value ); + return E_NOTIMPL; +} + +static const IKeyValuePair_HSTRING_IInspectableVtbl pair_vtbl = +{ + pair_QueryInterface, + pair_AddRef, + pair_Release, + /* IInspectable methods */ + pair_GetIids, + pair_GetRuntimeClassName, + pair_GetTrustLevel, + /* IKeyValuePair<HSTRING,IInspectable*> methods */ + pair_get_Key, + pair_get_Value, +}; + +static HRESULT pair_create( const GUID *iid, IKeyValuePair_HSTRING_IInspectable **out ) +{ + struct pair *pair; + + if (!(pair = calloc(1, sizeof(*pair)))) return E_OUTOFMEMORY; + pair->IKeyValuePair_HSTRING_IInspectable_iface.lpVtbl = &pair_vtbl; + pair->iid = iid; + pair->ref = 1; + + *out = &pair->IKeyValuePair_HSTRING_IInspectable_iface; + return S_OK; +} + +struct map +{ + IInspectable IInspectable_iface; + IMap_HSTRING_IInspectable IMap_HSTRING_IInspectable_iface; + IIterable_IKeyValuePair_HSTRING_IInspectable IIterable_IKeyValuePair_HSTRING_IInspectable_iface; + IInspectable *IInspectable_outer; + struct map_iids iids; + LONG ref; +}; + +struct map_view +{ + IMapView_HSTRING_IInspectable IMapView_HSTRING_IInspectable_iface; + IIterable_IKeyValuePair_HSTRING_IInspectable IIterable_IKeyValuePair_HSTRING_IInspectable_iface; + LONG ref; + + struct map *map; +}; + +struct iterator +{ + IIterator_IKeyValuePair_HSTRING_IInspectable IIterator_IKeyValuePair_HSTRING_IInspectable_iface; + LONG ref; + + struct map_view *view; +}; + +static struct iterator *impl_from_IIterator_IKeyValuePair_HSTRING_IInspectable( IIterator_IKeyValuePair_HSTRING_IInspectable *iface ) +{ + return CONTAINING_RECORD( iface, struct iterator, IIterator_IKeyValuePair_HSTRING_IInspectable_iface ); +} + +static HRESULT WINAPI iterator_QueryInterface( IIterator_IKeyValuePair_HSTRING_IInspectable *iface, REFIID iid, void **out ) +{ + struct iterator *impl = impl_from_IIterator_IKeyValuePair_HSTRING_IInspectable( iface ); + + TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out ); + + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IInspectable ) || + IsEqualGUID( iid, &IID_IAgileObject ) || + IsEqualGUID( iid, impl->view->map->iids.iterator )) + { + IInspectable_AddRef( (*out = &impl->IIterator_IKeyValuePair_HSTRING_IInspectable_iface) ); + return S_OK; + } + + FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI iterator_AddRef( IIterator_IKeyValuePair_HSTRING_IInspectable *iface ) +{ + struct iterator *impl = impl_from_IIterator_IKeyValuePair_HSTRING_IInspectable( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + TRACE( "iface %p increasing refcount to %lu.\n", iface, ref ); + return ref; +} + +static ULONG WINAPI iterator_Release( IIterator_IKeyValuePair_HSTRING_IInspectable *iface ) +{ + struct iterator *impl = impl_from_IIterator_IKeyValuePair_HSTRING_IInspectable( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + + TRACE( "iface %p decreasing refcount to %lu.\n", iface, ref ); + + if (!ref) + { + IMapView_HSTRING_IInspectable_Release( &impl->view->IMapView_HSTRING_IInspectable_iface ); + free( impl ); + } + + return ref; +} + +static HRESULT WINAPI iterator_GetIids( IIterator_IKeyValuePair_HSTRING_IInspectable *iface, ULONG *iid_count, IID **iids ) +{ + FIXME( "iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids ); + return E_NOTIMPL; +} + +static HRESULT WINAPI iterator_GetRuntimeClassName( IIterator_IKeyValuePair_HSTRING_IInspectable *iface, HSTRING *class_name ) +{ + FIXME( "iface %p, class_name %p stub!\n", iface, class_name ); + return E_NOTIMPL; +} + +static HRESULT WINAPI iterator_GetTrustLevel( IIterator_IKeyValuePair_HSTRING_IInspectable *iface, TrustLevel *trust_level ) +{ + FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level ); + return E_NOTIMPL; +} + +static HRESULT WINAPI iterator_get_Current( IIterator_IKeyValuePair_HSTRING_IInspectable *iface, IKeyValuePair_HSTRING_IInspectable **value ) +{ + struct iterator *impl = impl_from_IIterator_IKeyValuePair_HSTRING_IInspectable( iface ); + FIXME( "iface %p, value %p stub!\n", iface, value ); + return pair_create( impl->view->map->iids.pair, value ); +} + +static HRESULT WINAPI iterator_get_HasCurrent( IIterator_IKeyValuePair_HSTRING_IInspectable *iface, boolean *value ) +{ + TRACE( "iface %p, value %p stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI iterator_MoveNext( IIterator_IKeyValuePair_HSTRING_IInspectable *iface, boolean *value ) +{ + FIXME( "iface %p, value %p stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI iterator_GetMany( IIterator_IKeyValuePair_HSTRING_IInspectable *iface, UINT32 items_size, + IKeyValuePair_HSTRING_IInspectable **items, UINT *count ) +{ + FIXME( "iface %p, items_size %u, items %p, count %p stub!\n", iface, items_size, items, count ); + return E_NOTIMPL; +} + +static const IIterator_IKeyValuePair_HSTRING_IInspectableVtbl iterator_vtbl = +{ + iterator_QueryInterface, + iterator_AddRef, + iterator_Release, + /* IInspectable methods */ + iterator_GetIids, + iterator_GetRuntimeClassName, + iterator_GetTrustLevel, + /* IIterator<IInspectable*> methods */ + iterator_get_Current, + iterator_get_HasCurrent, + iterator_MoveNext, + iterator_GetMany, +}; + +static struct map_view *impl_from_IMapView_HSTRING_IInspectable( IMapView_HSTRING_IInspectable *iface ) +{ + return CONTAINING_RECORD( iface, struct map_view, IMapView_HSTRING_IInspectable_iface ); +} + +static HRESULT WINAPI map_view_QueryInterface( IMapView_HSTRING_IInspectable *iface, REFIID iid, void **out ) +{ + struct map_view *impl = impl_from_IMapView_HSTRING_IInspectable( iface ); + + TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out ); + + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IInspectable ) || + IsEqualGUID( iid, &IID_IAgileObject ) || + IsEqualGUID( iid, impl->map->iids.view )) + { + IInspectable_AddRef( (*out = &impl->IMapView_HSTRING_IInspectable_iface) ); + return S_OK; + } + + if (IsEqualGUID( iid, impl->map->iids.iterable )) + { + IInspectable_AddRef( (*out = &impl->IIterable_IKeyValuePair_HSTRING_IInspectable_iface) ); + return S_OK; + } + + FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI map_view_AddRef( IMapView_HSTRING_IInspectable *iface ) +{ + struct map_view *impl = impl_from_IMapView_HSTRING_IInspectable( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + TRACE( "iface %p increasing refcount to %lu.\n", iface, ref ); + return ref; +} + +static ULONG WINAPI map_view_Release( IMapView_HSTRING_IInspectable *iface ) +{ + struct map_view *impl = impl_from_IMapView_HSTRING_IInspectable( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + + TRACE( "iface %p decreasing refcount to %lu.\n", iface, ref ); + + if (!ref) + { + IMap_HSTRING_IInspectable_Release( &impl->map->IMap_HSTRING_IInspectable_iface ); + free( impl ); + } + return ref; +} + +static HRESULT WINAPI map_view_GetIids( IMapView_HSTRING_IInspectable *iface, ULONG *iid_count, IID **iids ) +{ + FIXME( "iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids ); + return E_NOTIMPL; +} + +static HRESULT WINAPI map_view_GetRuntimeClassName( IMapView_HSTRING_IInspectable *iface, HSTRING *class_name ) +{ + FIXME( "iface %p, class_name %p stub!\n", iface, class_name ); + return E_NOTIMPL; +} + +static HRESULT WINAPI map_view_GetTrustLevel( IMapView_HSTRING_IInspectable *iface, TrustLevel *trust_level ) +{ + FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level ); + return E_NOTIMPL; +} + +static HRESULT WINAPI map_view_Lookup( IMapView_HSTRING_IInspectable *iface, HSTRING key, IInspectable **value ) +{ + FIXME( "iface %p, key %s, value %p stub!\n", iface, debugstr_hstring( key ), value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI map_view_get_Size( IMapView_HSTRING_IInspectable *iface, UINT32 *value ) +{ + FIXME( "iface %p, value %p stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI map_view_HasKey( IMapView_HSTRING_IInspectable *iface, HSTRING key, boolean *found ) +{ + FIXME( "iface %p, key %s, found %p stub!\n", iface, debugstr_hstring( key ), found ); + return E_NOTIMPL; +} + +static HRESULT WINAPI map_view_Split( IMapView_HSTRING_IInspectable *iface, IMapView_HSTRING_IInspectable **first, + IMapView_HSTRING_IInspectable **second ) +{ + FIXME( "iface %p, first %p, second %p stub!\n", iface, first, second ); + return E_NOTIMPL; +} + +static const struct IMapView_HSTRING_IInspectableVtbl map_view_vtbl = +{ + map_view_QueryInterface, + map_view_AddRef, + map_view_Release, + /* IInspectable methods */ + map_view_GetIids, + map_view_GetRuntimeClassName, + map_view_GetTrustLevel, + /* IMapView_HSTRING<IInspectable*> methods */ + map_view_Lookup, + map_view_get_Size, + map_view_HasKey, + map_view_Split, +}; + +DEFINE_IINSPECTABLE_( iterable_view, IIterable_IKeyValuePair_HSTRING_IInspectable, struct map_view, view_impl_from_IIterable_IKeyValuePair_HSTRING_IInspectable, + IIterable_IKeyValuePair_HSTRING_IInspectable_iface, &impl->IMapView_HSTRING_IInspectable_iface ) + +static HRESULT WINAPI iterable_view_First( IIterable_IKeyValuePair_HSTRING_IInspectable *iface, IIterator_IKeyValuePair_HSTRING_IInspectable **value ) +{ + struct map_view *impl = view_impl_from_IIterable_IKeyValuePair_HSTRING_IInspectable( iface ); + struct iterator *iter; + + TRACE( "iface %p, value %p.\n", iface, value ); + + if (!(iter = calloc( 1, sizeof(struct iterator) ))) return E_OUTOFMEMORY; + iter->IIterator_IKeyValuePair_HSTRING_IInspectable_iface.lpVtbl = &iterator_vtbl; + iter->ref = 1; + + IIterable_IKeyValuePair_HSTRING_IInspectable_AddRef( &impl->IIterable_IKeyValuePair_HSTRING_IInspectable_iface ); + iter->view = impl; + + *value = &iter->IIterator_IKeyValuePair_HSTRING_IInspectable_iface; + return S_OK; +} + +static const struct IIterable_IKeyValuePair_HSTRING_IInspectableVtbl iterable_view_vtbl = +{ + iterable_view_QueryInterface, + iterable_view_AddRef, + iterable_view_Release, + /* IInspectable methods */ + iterable_view_GetIids, + iterable_view_GetRuntimeClassName, + iterable_view_GetTrustLevel, + /* IIterable<T> methods */ + iterable_view_First, +}; + +static HRESULT map_view_create( struct map *map, IMapView_HSTRING_IInspectable **out ) +{ + struct map_view *view; + + if (!(view = calloc( 1, sizeof(*view) ))) return E_OUTOFMEMORY; + view->IMapView_HSTRING_IInspectable_iface.lpVtbl = &map_view_vtbl; + view->IIterable_IKeyValuePair_HSTRING_IInspectable_iface.lpVtbl = &iterable_view_vtbl; + view->ref = 1; + + IMap_HSTRING_IInspectable_AddRef( &map->IMap_HSTRING_IInspectable_iface ); + view->map = map; + + *out = &view->IMapView_HSTRING_IInspectable_iface; + return S_OK; +} + +static struct map *impl_from_IInspectable( IInspectable *iface ) +{ + return CONTAINING_RECORD( iface, struct map, IInspectable_iface ); +} + +static HRESULT WINAPI map_inner_QueryInterface( IInspectable *iface, REFIID iid, void **out ) +{ + struct map *impl = impl_from_IInspectable( iface ); + + TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out ); + + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IInspectable ) || + IsEqualGUID( iid, &IID_IAgileObject )) + { + IInspectable_AddRef( (*out = &impl->IInspectable_iface) ); + return S_OK; + } + + if (IsEqualGUID( iid, impl->iids.map )) + { + IInspectable_AddRef( (*out = &impl->IMap_HSTRING_IInspectable_iface) ); + return S_OK; + } + + if (IsEqualGUID( iid, impl->iids.iterable )) + { + IInspectable_AddRef( (*out = &impl->IIterable_IKeyValuePair_HSTRING_IInspectable_iface) ); + return S_OK; + } + + FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI map_inner_AddRef( IInspectable *iface ) +{ + struct map *impl = impl_from_IInspectable( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + TRACE( "iface %p increasing refcount to %lu.\n", iface, ref ); + return ref; +} + +static ULONG WINAPI map_inner_Release( IInspectable *iface ) +{ + struct map *impl = impl_from_IInspectable( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + + TRACE( "iface %p decreasing refcount to %lu.\n", iface, ref ); + + if (!ref) + { + IMap_HSTRING_IInspectable_Clear( &impl->IMap_HSTRING_IInspectable_iface ); + free( impl ); + } + + return ref; +} + +static HRESULT WINAPI map_inner_GetIids( IInspectable *iface, ULONG *iid_count, IID **iids ) +{ + FIXME( "iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids ); + return E_NOTIMPL; +} + +static HRESULT WINAPI map_inner_GetRuntimeClassName( IInspectable *iface, HSTRING *class_name ) +{ + FIXME( "iface %p, class_name %p stub!\n", iface, class_name ); + return E_NOTIMPL; +} + +static HRESULT WINAPI map_inner_GetTrustLevel( IInspectable *iface, TrustLevel *trust_level ) +{ + FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level ); + return E_NOTIMPL; +} + +static const IInspectableVtbl map_inner_vtbl = +{ + /* IUnknown */ + map_inner_QueryInterface, + map_inner_AddRef, + map_inner_Release, + /* IInspectable */ + map_inner_GetIids, + map_inner_GetRuntimeClassName, + map_inner_GetTrustLevel, +}; + +DEFINE_IINSPECTABLE_OUTER( map, IMap_HSTRING_IInspectable, struct map, IInspectable_outer ) + +static HRESULT WINAPI map_Lookup( IMap_HSTRING_IInspectable *iface, HSTRING key, IInspectable **value ) +{ + FIXME( "iface %p, key %s, value %p stub!\n", iface, debugstr_hstring( key ), value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI map_get_Size( IMap_HSTRING_IInspectable *iface, UINT32 *size ) +{ + FIXME( "iface %p, size %p stub!\n", iface, size ); + return E_NOTIMPL; +} + +static HRESULT WINAPI map_HasKey( IMap_HSTRING_IInspectable *iface, HSTRING key, boolean *exists ) +{ + FIXME( "iface %p, key %s, exists %p stub!\n", iface, debugstr_hstring( key ), exists ); + return E_NOTIMPL; +} + +static HRESULT WINAPI map_GetView( IMap_HSTRING_IInspectable *iface, IMapView_HSTRING_IInspectable **value ) +{ + struct map *impl = impl_from_IMap_HSTRING_IInspectable( iface ); + + TRACE( "iface %p, value %p.\n", iface, value ); + + return map_view_create( impl, value ); +} + +static HRESULT WINAPI map_Insert( IMap_HSTRING_IInspectable *iface, HSTRING key, IInspectable *value, boolean *replaced ) +{ + FIXME( "iface %p, key %p, value %p, replaced %p stub!\n", iface, key, value, replaced ); + return E_NOTIMPL; +} + +static HRESULT WINAPI map_Remove( IMap_HSTRING_IInspectable *iface, HSTRING key ) +{ + FIXME( "iface %p, key %s stub!\n", iface, debugstr_hstring( key ) ); + return E_NOTIMPL; +} + +static HRESULT WINAPI map_Clear( IMap_HSTRING_IInspectable *iface ) +{ + FIXME( "iface %p stub!\n", iface ); + return E_NOTIMPL; +} + +static const IMap_HSTRING_IInspectableVtbl map_vtbl = +{ + /* IUnknown */ + map_QueryInterface, + map_AddRef, + map_Release, + /* IInspectable */ + map_GetIids, + map_GetRuntimeClassName, + map_GetTrustLevel, + /* IMap<HSTRING, IInspectable *> */ + map_Lookup, + map_get_Size, + map_HasKey, + map_GetView, + map_Insert, + map_Remove, + map_Clear, +}; + +DEFINE_IINSPECTABLE_OUTER( iterable, IIterable_IKeyValuePair_HSTRING_IInspectable, struct map, IInspectable_outer ) + +static HRESULT WINAPI iterable_First( IIterable_IKeyValuePair_HSTRING_IInspectable *iface, IIterator_IKeyValuePair_HSTRING_IInspectable **value ) +{ + struct map *impl = impl_from_IIterable_IKeyValuePair_HSTRING_IInspectable( iface ); + IIterable_IKeyValuePair_HSTRING_IInspectable *iterable; + IMapView_HSTRING_IInspectable *view; + HRESULT hr; + + TRACE( "iface %p, value %p.\n", iface, value ); + + if (FAILED(hr = IMap_HSTRING_IInspectable_GetView( &impl->IMap_HSTRING_IInspectable_iface, &view ))) return hr; + + hr = IMapView_HSTRING_IInspectable_QueryInterface( view, impl->iids.iterable, (void **)&iterable ); + IMapView_HSTRING_IInspectable_Release( view ); + if (FAILED(hr)) return hr; + + hr = IIterable_IKeyValuePair_HSTRING_IInspectable_First( iterable, value ); + IIterable_IKeyValuePair_HSTRING_IInspectable_Release( iterable ); + return hr; +} + +static const struct IIterable_IKeyValuePair_HSTRING_IInspectableVtbl iterable_vtbl = +{ + iterable_QueryInterface, + iterable_AddRef, + iterable_Release, + /* IInspectable methods */ + iterable_GetIids, + iterable_GetRuntimeClassName, + iterable_GetTrustLevel, + /* IIterable<T> methods */ + iterable_First, +}; + +HRESULT map_create( const struct map_iids *iids, IInspectable *outer, IInspectable **out ) +{ + struct map *impl; + + TRACE( "iid %s, out %p.\n", debugstr_guid( iids->map ), out ); + + if (!(impl = calloc( 1, sizeof(*impl) ))) return E_OUTOFMEMORY; + impl->IInspectable_iface.lpVtbl = &map_inner_vtbl; + impl->IMap_HSTRING_IInspectable_iface.lpVtbl = &map_vtbl; + impl->IIterable_IKeyValuePair_HSTRING_IInspectable_iface.lpVtbl = &iterable_vtbl; + impl->IInspectable_outer = outer ? outer : (IInspectable *)&impl->IInspectable_iface; + impl->iids = *iids; + impl->ref = 1; + + *out = &impl->IInspectable_iface; + TRACE( "created %p\n", *out ); + return S_OK; +} diff --git a/dlls/wintypes/private.h b/dlls/wintypes/private.h index fe9e8cb951c..c127ae2358d 100644 --- a/dlls/wintypes/private.h +++ b/dlls/wintypes/private.h @@ -39,6 +39,56 @@ #include "windows.storage.streams.h" #include "wintypes_private.h"
+struct map_iids +{ + const GUID *map; + const GUID *view; + const GUID *iterable; + const GUID *iterator; + const GUID *pair; +}; +extern HRESULT map_create( const struct map_iids *iids, IInspectable *outer, IInspectable **out ); + extern IActivationFactory *data_writer_activation_factory; extern IActivationFactory *buffer_activation_factory; extern IActivationFactory *property_set_factory; + +#define DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from, iface_mem, expr ) \ + static inline impl_type *impl_from( iface_type *iface ) \ + { \ + return CONTAINING_RECORD( iface, impl_type, iface_mem ); \ + } \ + static HRESULT WINAPI pfx##_QueryInterface( iface_type *iface, REFIID iid, void **out ) \ + { \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_QueryInterface( (IInspectable *)(expr), iid, out ); \ + } \ + static ULONG WINAPI pfx##_AddRef( iface_type *iface ) \ + { \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_AddRef( (IInspectable *)(expr) ); \ + } \ + static ULONG WINAPI pfx##_Release( iface_type *iface ) \ + { \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_Release( (IInspectable *)(expr) ); \ + } \ + static HRESULT WINAPI pfx##_GetIids( iface_type *iface, ULONG *iid_count, IID **iids ) \ + { \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_GetIids( (IInspectable *)(expr), iid_count, iids ); \ + } \ + static HRESULT WINAPI pfx##_GetRuntimeClassName( iface_type *iface, HSTRING *class_name ) \ + { \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_GetRuntimeClassName( (IInspectable *)(expr), class_name ); \ + } \ + static HRESULT WINAPI pfx##_GetTrustLevel( iface_type *iface, TrustLevel *trust_level ) \ + { \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_GetTrustLevel( (IInspectable *)(expr), trust_level ); \ + } +#define DEFINE_IINSPECTABLE( pfx, iface_type, impl_type, base_iface ) \ + DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from_##iface_type, iface_type##_iface, &impl->base_iface ) +#define DEFINE_IINSPECTABLE_OUTER( pfx, iface_type, impl_type, outer_iface ) \ + DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from_##iface_type, iface_type##_iface, impl->outer_iface ) diff --git a/dlls/wintypes/propertyset.c b/dlls/wintypes/propertyset.c index 6a0ccc30c2b..9d625de921c 100644 --- a/dlls/wintypes/propertyset.c +++ b/dlls/wintypes/propertyset.c @@ -30,9 +30,9 @@ struct propertyset { IPropertySet IPropertySet_iface; IObservableMap_HSTRING_IInspectable IObservableMap_HSTRING_IInspectable_iface; - IMap_HSTRING_IInspectable IMap_HSTRING_IInspectable_iface; - IIterable_IKeyValuePair_HSTRING_IInspectable IIterable_IKeyValuePair_HSTRING_IInspectable_iface; LONG ref; + + IInspectable *map_inner; };
static inline struct propertyset *impl_from_IPropertySet( IPropertySet *iface ) @@ -61,18 +61,8 @@ static HRESULT STDMETHODCALLTYPE propertyset_QueryInterface( IPropertySet *iface IUnknown_AddRef( (IUnknown *)*out ); return S_OK; } - else if (IsEqualGUID( iid, &IID_IMap_HSTRING_IInspectable )) - { - *out = &impl->IMap_HSTRING_IInspectable_iface; - IUnknown_AddRef( (IUnknown *)iface ); - return S_OK; - } - else if (IsEqualGUID( iid, &IID_IIterable_IKeyValuePair_HSTRING_IInspectable )) - { - *out = &impl->IIterable_IKeyValuePair_HSTRING_IInspectable_iface; - IUnknown_AddRef( (IUnknown *)iface ); - return S_OK; - } + + if (SUCCEEDED(IInspectable_QueryInterface( impl->map_inner, iid, out ))) return S_OK;
FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); return E_NOINTERFACE; @@ -81,22 +71,26 @@ static HRESULT STDMETHODCALLTYPE propertyset_QueryInterface( IPropertySet *iface static ULONG STDMETHODCALLTYPE propertyset_AddRef( IPropertySet *iface ) { struct propertyset *impl = impl_from_IPropertySet( iface ); - - TRACE( "(%p)\n", iface ); - - return InterlockedIncrement( &impl->ref ); + ULONG ref = InterlockedIncrement( &impl->ref ); + TRACE( "iface %p increasing refcount to %lu.\n", iface, ref ); + return ref; }
static ULONG STDMETHODCALLTYPE propertyset_Release( IPropertySet *iface ) { struct propertyset *impl = impl_from_IPropertySet( iface ); - ULONG ref; + ULONG ref = InterlockedDecrement( &impl->ref );
- TRACE( "(%p)\n", iface ); + TRACE( "iface %p decreasing refcount to %lu.\n", iface, ref );
- ref = InterlockedDecrement( &impl->ref ); if (!ref) + { + /* guard against re-entry if inner releases an outer iface */ + InterlockedIncrement( &impl->ref ); + IInspectable_Release( impl->map_inner ); free( impl ); + } + return ref; }
@@ -161,96 +155,6 @@ const static IObservableMap_HSTRING_IInspectableVtbl propertyset_IObservableMap_ propertyset_IObservableMap_remove_MapChanged, };
-DEFINE_IINSPECTABLE( propertyset_IMap, IMap_HSTRING_IInspectable, struct propertyset, - IPropertySet_iface ); - -static HRESULT STDMETHODCALLTYPE propertyset_Lookup( IMap_HSTRING_IInspectable *iface, HSTRING key, IInspectable **value ) -{ - FIXME( "(%p, %s, %p) stub!\n", iface, debugstr_hstring( key ), value ); - return E_NOTIMPL; -} - -static HRESULT STDMETHODCALLTYPE propertyset_get_Size( IMap_HSTRING_IInspectable *iface, UINT32 *size ) -{ - FIXME( "(%p, %p) stub!\n", iface, size ); - return E_NOTIMPL; -} - -static HRESULT STDMETHODCALLTYPE propertyset_HasKey( IMap_HSTRING_IInspectable *iface, HSTRING key, boolean *exists ) -{ - FIXME( "(%p, %s, %p) stub!\n", iface, debugstr_hstring( key ), exists ); - return E_NOTIMPL; -} - -static HRESULT STDMETHODCALLTYPE propertyset_GetView( IMap_HSTRING_IInspectable *iface, IMapView_HSTRING_IInspectable **view ) -{ - FIXME( "(%p, %p) stub!\n", iface, view ); - return E_NOTIMPL; -} - -static HRESULT STDMETHODCALLTYPE propertyset_Insert( IMap_HSTRING_IInspectable *iface, HSTRING key, IInspectable *value, boolean *replaced ) -{ - FIXME( "(%p, %s, %p, %p) stub!\n", iface, debugstr_hstring( key ), value, replaced ); - return E_NOTIMPL; -} - -static HRESULT STDMETHODCALLTYPE propertyset_Remove( IMap_HSTRING_IInspectable *iface, HSTRING key ) -{ - FIXME( "(%p, %s) stub!\n", iface, debugstr_hstring( key ) ); - return E_NOTIMPL; -} - -static HRESULT STDMETHODCALLTYPE propertyset_Clear( IMap_HSTRING_IInspectable *iface ) -{ - FIXME( "(%p) stub!\n", iface ); - return E_NOTIMPL; -} - -const static IMap_HSTRING_IInspectableVtbl propertyset_IMap_vtbl = -{ - /* IUnknown */ - propertyset_IMap_QueryInterface, - propertyset_IMap_AddRef, - propertyset_IMap_Release, - /* IInspectable */ - propertyset_IMap_GetIids, - propertyset_IMap_GetRuntimeClassName, - propertyset_IMap_GetTrustLevel, - /* IMap<HSTRING, IInspectable*> */ - propertyset_Lookup, - propertyset_get_Size, - propertyset_HasKey, - propertyset_GetView, - propertyset_Insert, - propertyset_Remove, - propertyset_Clear, -}; - -DEFINE_IINSPECTABLE_( iterable_kvpair_HSTRING_IInspectable, IIterable_IKeyValuePair_HSTRING_IInspectable, struct propertyset, - impl_from_IIterable_IKeyValuePair_HSTRING_IInspectable, IIterable_IKeyValuePair_HSTRING_IInspectable_iface, - &impl->IMap_HSTRING_IInspectable_iface ); - -static HRESULT STDMETHODCALLTYPE iterable_kvpair_HSTRING_IInspectable_First( IIterable_IKeyValuePair_HSTRING_IInspectable *iface, - IIterator_IKeyValuePair_HSTRING_IInspectable **iter ) -{ - FIXME( "(%p, %p) stub!\n", iface, iter ); - return E_NOTIMPL; -} - -const static IIterable_IKeyValuePair_HSTRING_IInspectableVtbl iterable_kvpair_HSTRING_IInspectable_vtbl = -{ - /* IUnknown */ - iterable_kvpair_HSTRING_IInspectable_QueryInterface, - iterable_kvpair_HSTRING_IInspectable_AddRef, - iterable_kvpair_HSTRING_IInspectable_Release, - /* IInspectable */ - iterable_kvpair_HSTRING_IInspectable_GetIids, - iterable_kvpair_HSTRING_IInspectable_GetRuntimeClassName, - iterable_kvpair_HSTRING_IInspectable_GetTrustLevel, - /* IIterable<IKeyValuePair<HSTRING, IInspectable*>> */ - iterable_kvpair_HSTRING_IInspectable_First -}; - struct propertyset_factory { IActivationFactory IActivationFactory_iface; @@ -314,7 +218,17 @@ static HRESULT STDMETHODCALLTYPE factory_GetTrustLevel( IActivationFactory *ifac
static HRESULT STDMETHODCALLTYPE factory_ActivateInstance( IActivationFactory *iface, IInspectable **instance ) { + static const struct map_iids iids = + { + .map = &IID_IMap_HSTRING_IInspectable, + .view = &IID_IMapView_HSTRING_IInspectable, + .iterable = &IID_IIterable_IKeyValuePair_HSTRING_IInspectable, + .iterator = &IID_IIterator_IKeyValuePair_HSTRING_IInspectable, + .pair = &IID_IKeyValuePair_HSTRING_IInspectable, + }; + struct propertyset *impl; + HRESULT hr;
TRACE( "(%p, %p)\n", iface, instance );
@@ -324,9 +238,14 @@ static HRESULT STDMETHODCALLTYPE factory_ActivateInstance( IActivationFactory *i
impl->IPropertySet_iface.lpVtbl = &propertyset_vtbl; impl->IObservableMap_HSTRING_IInspectable_iface.lpVtbl = &propertyset_IObservableMap_vtbl; - impl->IMap_HSTRING_IInspectable_iface.lpVtbl = &propertyset_IMap_vtbl; - impl->IIterable_IKeyValuePair_HSTRING_IInspectable_iface.lpVtbl = &iterable_kvpair_HSTRING_IInspectable_vtbl; impl->ref = 1; + + if (FAILED(hr = map_create( &iids, (IInspectable *)&impl->IPropertySet_iface, &impl->map_inner ))) + { + free( impl ); + return hr; + } + *instance = (IInspectable *)&impl->IPropertySet_iface; return S_OK; } diff --git a/dlls/wintypes/tests/wintypes.c b/dlls/wintypes/tests/wintypes.c index 955f0e28988..4165d67ee1a 100644 --- a/dlls/wintypes/tests/wintypes.c +++ b/dlls/wintypes/tests/wintypes.c @@ -1439,35 +1439,31 @@ static void test_IPropertySet(void) ok( uint64 == 0xdeadbeefdeadbeef, "Got uint64 %I64u\n", uint64 ); }
- todo_wine check_interface( map, &IID_IAgileObject, TRUE ); + check_interface( map, &IID_IAgileObject, TRUE ); hr = IMap_HSTRING_IInspectable_QueryInterface( map, &IID_IIterable_IKeyValuePair_HSTRING_IInspectable, (void **)&iterable ); ok( hr == S_OK, "QueryInterface failed, got %#lx\n", hr ); hr = IIterable_IKeyValuePair_HSTRING_IInspectable_First( iterable, &iterator ); - todo_wine ok( hr == S_OK, "got %#lx\n", hr ); IIterable_IKeyValuePair_HSTRING_IInspectable_Release( iterable ); - if (FAILED( hr )) goto skip_test;
check_interface( iterator, &IID_IAgileObject, TRUE ); hr = IIterator_IKeyValuePair_HSTRING_IInspectable_get_HasCurrent( iterator, &boolean ); - ok( hr == S_OK, "Got hr %#lx\n", hr ); - ok( boolean == TRUE, "Got %u\n", boolean ); + todo_wine ok( hr == S_OK, "Got hr %#lx\n", hr ); + todo_wine ok( boolean == TRUE, "Got %u\n", boolean );
hr = IIterator_IKeyValuePair_HSTRING_IInspectable_get_Current( iterator, &pair ); ok( hr == S_OK, "Got hr %#lx\n", hr ); check_interface( pair, &IID_IAgileObject, TRUE ); hr = IKeyValuePair_HSTRING_IInspectable_get_Key( pair, &key2 ); - ok( hr == S_OK, "Got %#lx\n", hr ); + todo_wine ok( hr == S_OK, "Got %#lx\n", hr ); WindowsDeleteString( key2 ); hr = IKeyValuePair_HSTRING_IInspectable_get_Value( pair, &val ); - ok( hr == S_OK, "Got %#lx\n", hr ); - IInspectable_Release( val ); + todo_wine ok( hr == S_OK, "Got %#lx\n", hr ); + if (hr == S_OK) IInspectable_Release( val );
hr = IMap_HSTRING_IInspectable_GetView( map, &map_view ); - todo_wine ok( hr == S_OK, "GetView failed, got %#lx\n", hr ); - if (FAILED( hr )) goto skip_test;
check_interface( map_view, &IID_IAgileObject, TRUE ); hr = IMapView_HSTRING_IInspectable_QueryInterface( map_view, &IID_IIterable_IKeyValuePair_HSTRING_IInspectable, @@ -1476,7 +1472,7 @@ static void test_IPropertySet(void) hr = IMapView_HSTRING_IInspectable_Lookup( map_view, key2, &val ); todo_wine ok( hr == S_OK, "Lookup failed, got %#lx\n", hr ); - IInspectable_Release( val ); + if (hr == S_OK) IInspectable_Release( val );
/* after map is modified, associated objects are invalidated */ @@ -1485,18 +1481,18 @@ static void test_IPropertySet(void) ok( hr == S_OK, "Remove failed, got %#lx\n", hr );
hr = IKeyValuePair_HSTRING_IInspectable_get_Key( pair, &key2 ); - ok( hr == S_OK, "Got %#lx\n", hr ); + todo_wine ok( hr == S_OK, "Got %#lx\n", hr ); WindowsDeleteString( key2 ); hr = IKeyValuePair_HSTRING_IInspectable_get_Value( pair, &val ); - ok( hr == S_OK, "Got %#lx\n", hr ); - IInspectable_Release( val ); + todo_wine ok( hr == S_OK, "Got %#lx\n", hr ); + if (hr == S_OK) IInspectable_Release( val ); IKeyValuePair_HSTRING_IInspectable_Release( pair );
hr = IIterator_IKeyValuePair_HSTRING_IInspectable_get_HasCurrent( iterator, &boolean ); - ok( hr == S_OK, "Got hr %#lx\n", hr ); - ok( boolean == TRUE, "Got %u\n", boolean ); + todo_wine ok( hr == S_OK, "Got hr %#lx\n", hr ); + todo_wine ok( boolean == TRUE, "Got %u\n", boolean ); hr = IIterator_IKeyValuePair_HSTRING_IInspectable_get_Current( iterator, &pair ); - ok( hr == E_CHANGED_STATE, "Got hr %#lx\n", hr ); + todo_wine ok( hr == E_CHANGED_STATE, "Got hr %#lx\n", hr ); IIterator_IKeyValuePair_HSTRING_IInspectable_Release( iterator );
hr = IMapView_HSTRING_IInspectable_Lookup( map_view, key2, &val ); @@ -1520,7 +1516,6 @@ static void test_IPropertySet(void) IIterable_IKeyValuePair_HSTRING_IInspectable_Release( iterable ); IMapView_HSTRING_IInspectable_Release( map_view );
-skip_test: IMap_HSTRING_IInspectable_Release( map ); IPropertyValueStatics_Release( propval_statics ); done: diff --git a/dlls/wintypes/wintypes_private.idl b/dlls/wintypes/wintypes_private.idl index b0d7b7d2241..33cfbed210b 100644 --- a/dlls/wintypes/wintypes_private.idl +++ b/dlls/wintypes/wintypes_private.idl @@ -27,42 +27,3 @@ import "windows.foundation.idl"; declare { interface Windows.Foundation.IReference<HSTRING>; } - -cpp_quote("#define DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from, iface_mem, expr ) \") -cpp_quote(" static inline impl_type *impl_from( iface_type *iface ) \") -cpp_quote(" { \") -cpp_quote(" return CONTAINING_RECORD( iface, impl_type, iface_mem ); \") -cpp_quote(" } \") -cpp_quote(" static HRESULT WINAPI pfx##_QueryInterface( iface_type *iface, REFIID iid, void **out ) \") -cpp_quote(" { \") -cpp_quote(" impl_type *impl = impl_from( iface ); \") -cpp_quote(" return IInspectable_QueryInterface( (IInspectable *)(expr), iid, out ); \") -cpp_quote(" } \") -cpp_quote(" static ULONG WINAPI pfx##_AddRef( iface_type *iface ) \") -cpp_quote(" { \") -cpp_quote(" impl_type *impl = impl_from( iface ); \") -cpp_quote(" return IInspectable_AddRef( (IInspectable *)(expr) ); \") -cpp_quote(" } \") -cpp_quote(" static ULONG WINAPI pfx##_Release( iface_type *iface ) \") -cpp_quote(" { \") -cpp_quote(" impl_type *impl = impl_from( iface ); \") -cpp_quote(" return IInspectable_Release( (IInspectable *)(expr) ); \") -cpp_quote(" } \") -cpp_quote(" static HRESULT WINAPI pfx##_GetIids( iface_type *iface, ULONG *iid_count, IID **iids ) \") -cpp_quote(" { \") -cpp_quote(" impl_type *impl = impl_from( iface ); \") -cpp_quote(" return IInspectable_GetIids( (IInspectable *)(expr), iid_count, iids ); \") -cpp_quote(" } \") -cpp_quote(" static HRESULT WINAPI pfx##_GetRuntimeClassName( iface_type *iface, HSTRING *class_name ) \") -cpp_quote(" { \") -cpp_quote(" impl_type *impl = impl_from( iface ); \") -cpp_quote(" return IInspectable_GetRuntimeClassName( (IInspectable *)(expr), class_name ); \") -cpp_quote(" } \") -cpp_quote(" static HRESULT WINAPI pfx##_GetTrustLevel( iface_type *iface, TrustLevel *trust_level ) \") -cpp_quote(" { \") -cpp_quote(" impl_type *impl = impl_from( iface ); \") -cpp_quote(" return IInspectable_GetTrustLevel( (IInspectable *)(expr), trust_level ); \") -cpp_quote(" }") - -cpp_quote("#define DEFINE_IINSPECTABLE( pfx, iface_type, impl_type, base_iface ) \") -cpp_quote(" DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from_##iface_type, iface_type##_iface, &impl->base_iface )")
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/wintypes/map.c | 240 ++++++++++++++++++++++++++++----- dlls/wintypes/tests/wintypes.c | 89 ++++-------- 2 files changed, 231 insertions(+), 98 deletions(-)
diff --git a/dlls/wintypes/map.c b/dlls/wintypes/map.c index 8d92d204e77..0d431f479e7 100644 --- a/dlls/wintypes/map.c +++ b/dlls/wintypes/map.c @@ -24,11 +24,61 @@
WINE_DEFAULT_DEBUG_CHANNEL(combase);
+struct map_entry +{ + HSTRING key; + IInspectable *value; +}; + +static HRESULT map_entry_init( HSTRING key, IInspectable *value, struct map_entry *entry ) +{ + HRESULT hr; + if (FAILED(hr = WindowsDuplicateString( key, &entry->key ))) return hr; + IInspectable_AddRef( (entry->value = value) ); + return S_OK; +} + +static void map_entry_copy( struct map_entry *dst, const struct map_entry *src ) +{ + /* key has been duplicated already and further duplication cannot fail */ + WindowsDuplicateString( src->key, &dst->key ); + IInspectable_AddRef( (dst->value = src->value) ); +} + +static void map_entry_clear( struct map_entry *entry ) +{ + WindowsDeleteString( entry->key ); + entry->key = NULL; + IInspectable_AddRef( entry->value ); + entry->value = NULL; +} + +/* returns the first entry which is not less than addr, or entries + size if there's none. */ +static struct map_entry *map_entries_lower_bound( struct map_entry *entries, UINT32 size, HSTRING key, int *ret ) +{ + struct map_entry *begin = entries, *end = begin + size, *mid; + int order = -1; + + while (begin < end) + { + mid = begin + (end - begin) / 2; + WindowsCompareStringOrdinal( mid->key, key, &order ); + if (order < 0) begin = mid + 1; + else if (order > 0) end = mid; + else begin = end = mid; + } + + *ret = order; + return begin; +} + struct pair { IKeyValuePair_HSTRING_IInspectable IKeyValuePair_HSTRING_IInspectable_iface; const GUID *iid; LONG ref; + + struct map_entry entry; };
static struct pair *impl_from_IKeyValuePair_HSTRING_IInspectable( IKeyValuePair_HSTRING_IInspectable *iface ) @@ -73,6 +123,7 @@ static ULONG WINAPI pair_Release( IKeyValuePair_HSTRING_IInspectable *iface )
if (!ref) { + map_entry_clear( &impl->entry ); free( impl ); }
@@ -99,14 +150,17 @@ static HRESULT WINAPI pair_GetTrustLevel( IKeyValuePair_HSTRING_IInspectable *if
static HRESULT WINAPI pair_get_Key( IKeyValuePair_HSTRING_IInspectable *iface, HSTRING *value ) { - FIXME( "iface %p, value %p stub!\n", iface, value ); - return E_NOTIMPL; + struct pair *impl = impl_from_IKeyValuePair_HSTRING_IInspectable( iface ); + TRACE( "iface %p, value %p\n", iface, value ); + return WindowsDuplicateString( impl->entry.key, value ); }
static HRESULT WINAPI pair_get_Value( IKeyValuePair_HSTRING_IInspectable *iface, IInspectable **value ) { - TRACE( "iface %p, value %p stub!\n", iface, value ); - return E_NOTIMPL; + struct pair *impl = impl_from_IKeyValuePair_HSTRING_IInspectable( iface ); + TRACE( "iface %p, value %p\n", iface, value ); + IInspectable_AddRef( (*value = impl->entry.value) ); + return S_OK; }
static const IKeyValuePair_HSTRING_IInspectableVtbl pair_vtbl = @@ -123,7 +177,7 @@ static const IKeyValuePair_HSTRING_IInspectableVtbl pair_vtbl = pair_get_Value, };
-static HRESULT pair_create( const GUID *iid, IKeyValuePair_HSTRING_IInspectable **out ) +static HRESULT pair_create( const GUID *iid, struct map_entry *entry, IKeyValuePair_HSTRING_IInspectable **out ) { struct pair *pair;
@@ -131,6 +185,7 @@ static HRESULT pair_create( const GUID *iid, IKeyValuePair_HSTRING_IInspectable pair->IKeyValuePair_HSTRING_IInspectable_iface.lpVtbl = &pair_vtbl; pair->iid = iid; pair->ref = 1; + map_entry_copy( &pair->entry, entry );
*out = &pair->IKeyValuePair_HSTRING_IInspectable_iface; return S_OK; @@ -144,6 +199,10 @@ struct map IInspectable *IInspectable_outer; struct map_iids iids; LONG ref; + + UINT32 size; + UINT32 capacity; + struct map_entry *entries; };
struct map_view @@ -153,6 +212,8 @@ struct map_view LONG ref;
struct map *map; + UINT32 size; + struct map_entry entries[1]; };
struct iterator @@ -161,6 +222,7 @@ struct iterator LONG ref;
struct map_view *view; + UINT32 index; };
static struct iterator *impl_from_IIterator_IKeyValuePair_HSTRING_IInspectable( IIterator_IKeyValuePair_HSTRING_IInspectable *iface ) @@ -233,27 +295,47 @@ static HRESULT WINAPI iterator_GetTrustLevel( IIterator_IKeyValuePair_HSTRING_II static HRESULT WINAPI iterator_get_Current( IIterator_IKeyValuePair_HSTRING_IInspectable *iface, IKeyValuePair_HSTRING_IInspectable **value ) { struct iterator *impl = impl_from_IIterator_IKeyValuePair_HSTRING_IInspectable( iface ); - FIXME( "iface %p, value %p stub!\n", iface, value ); - return pair_create( impl->view->map->iids.pair, value ); + TRACE( "iface %p, value %p\n", iface, value ); + return pair_create( impl->view->map->iids.pair, impl->view->entries + impl->index, value ); }
static HRESULT WINAPI iterator_get_HasCurrent( IIterator_IKeyValuePair_HSTRING_IInspectable *iface, boolean *value ) { - TRACE( "iface %p, value %p stub!\n", iface, value ); - return E_NOTIMPL; + struct iterator *impl = impl_from_IIterator_IKeyValuePair_HSTRING_IInspectable( iface ); + TRACE( "iface %p, value %p\n", iface, value ); + *value = impl->index < impl->view->size; + return S_OK; }
static HRESULT WINAPI iterator_MoveNext( IIterator_IKeyValuePair_HSTRING_IInspectable *iface, boolean *value ) { - FIXME( "iface %p, value %p stub!\n", iface, value ); - return E_NOTIMPL; + struct iterator *impl = impl_from_IIterator_IKeyValuePair_HSTRING_IInspectable( iface ); + TRACE( "iface %p, value %p\n", iface, value ); + if (impl->index < impl->view->size) impl->index++; + return IIterator_IKeyValuePair_HSTRING_IInspectable_get_HasCurrent( iface, value ); }
static HRESULT WINAPI iterator_GetMany( IIterator_IKeyValuePair_HSTRING_IInspectable *iface, UINT32 items_size, IKeyValuePair_HSTRING_IInspectable **items, UINT *count ) { - FIXME( "iface %p, items_size %u, items %p, count %p stub!\n", iface, items_size, items, count ); - return E_NOTIMPL; + struct iterator *impl = impl_from_IIterator_IKeyValuePair_HSTRING_IInspectable( iface ); + HRESULT hr; + int len; + + TRACE( "iface %p, items_size %u, items %p, count %p\n", iface, items_size, items, count ); + + if ((len = impl->view->size - impl->index) < 0) return E_BOUNDS; + for (UINT32 i = 0; i < len; ++i) + { + if (i >= items_size) break; + if (FAILED(hr = pair_create( impl->view->map->iids.pair, impl->view->entries + impl->index + i, items + i ))) + { + while (i) IKeyValuePair_HSTRING_IInspectable_Release( items[--i] ); + return hr; + } + } + *count = len; + return S_OK; }
static const IIterator_IKeyValuePair_HSTRING_IInspectableVtbl iterator_vtbl = @@ -346,27 +428,52 @@ static HRESULT WINAPI map_view_GetTrustLevel( IMapView_HSTRING_IInspectable *ifa
static HRESULT WINAPI map_view_Lookup( IMapView_HSTRING_IInspectable *iface, HSTRING key, IInspectable **value ) { - FIXME( "iface %p, key %s, value %p stub!\n", iface, debugstr_hstring( key ), value ); - return E_NOTIMPL; + struct map_view *impl = impl_from_IMapView_HSTRING_IInspectable( iface ); + struct map_entry *entry; + int order; + + TRACE( "iface %p, key %s, value %p\n", iface, debugstr_hstring( key ), value ); + + if (!(entry = map_entries_lower_bound( impl->entries, impl->size, key, &order )) || order) return E_BOUNDS; + IInspectable_AddRef( (*value = entry->value )); + return S_OK; }
static HRESULT WINAPI map_view_get_Size( IMapView_HSTRING_IInspectable *iface, UINT32 *value ) { - FIXME( "iface %p, value %p stub!\n", iface, value ); - return E_NOTIMPL; + struct map_view *impl = impl_from_IMapView_HSTRING_IInspectable( iface ); + TRACE( "iface %p, value %p\n", iface, value ); + *value = impl->size; + return S_OK; }
static HRESULT WINAPI map_view_HasKey( IMapView_HSTRING_IInspectable *iface, HSTRING key, boolean *found ) { - FIXME( "iface %p, key %s, found %p stub!\n", iface, debugstr_hstring( key ), found ); - return E_NOTIMPL; + struct map_view *impl = impl_from_IMapView_HSTRING_IInspectable( iface ); + int order; + + TRACE( "iface %p, key %s, found %p\n", iface, debugstr_hstring( key ), found ); + + map_entries_lower_bound( impl->entries, impl->size, key, &order ); + *found = !order; + return S_OK; }
+static HRESULT map_view_create( struct map *map, UINT first, UINT count, IMapView_HSTRING_IInspectable **out ); + static HRESULT WINAPI map_view_Split( IMapView_HSTRING_IInspectable *iface, IMapView_HSTRING_IInspectable **first, IMapView_HSTRING_IInspectable **second ) { - FIXME( "iface %p, first %p, second %p stub!\n", iface, first, second ); - return E_NOTIMPL; + struct map_view *impl = impl_from_IMapView_HSTRING_IInspectable( iface ); + HRESULT hr; + + TRACE( "iface %p, first %p, second %p\n", iface, first, second ); + + if (FAILED(hr = map_view_create( impl->map, 0, impl->size / 2, first ))) return hr; + if (FAILED(hr = map_view_create( impl->map, impl->size / 2, impl->size - impl->size / 2, second ))) + IMapView_HSTRING_IInspectable_Release( *first ); + + return hr; }
static const struct IMapView_HSTRING_IInspectableVtbl map_view_vtbl = @@ -419,11 +526,11 @@ static const struct IIterable_IKeyValuePair_HSTRING_IInspectableVtbl iterable_vi iterable_view_First, };
-static HRESULT map_view_create( struct map *map, IMapView_HSTRING_IInspectable **out ) +static HRESULT map_view_create( struct map *map, UINT first, UINT count, IMapView_HSTRING_IInspectable **out ) { struct map_view *view;
- if (!(view = calloc( 1, sizeof(*view) ))) return E_OUTOFMEMORY; + if (!(view = calloc( 1, offsetof( struct map_view, entries[count] ) ))) return E_OUTOFMEMORY; view->IMapView_HSTRING_IInspectable_iface.lpVtbl = &map_view_vtbl; view->IIterable_IKeyValuePair_HSTRING_IInspectable_iface.lpVtbl = &iterable_view_vtbl; view->ref = 1; @@ -431,6 +538,8 @@ static HRESULT map_view_create( struct map *map, IMapView_HSTRING_IInspectable * IMap_HSTRING_IInspectable_AddRef( &map->IMap_HSTRING_IInspectable_iface ); view->map = map;
+ for (UINT32 i = 0; i < count; ++i) map_entry_copy( view->entries + view->size++, map->entries + i ); + *out = &view->IMapView_HSTRING_IInspectable_iface; return S_OK; } @@ -529,20 +638,35 @@ DEFINE_IINSPECTABLE_OUTER( map, IMap_HSTRING_IInspectable, struct map, IInspecta
static HRESULT WINAPI map_Lookup( IMap_HSTRING_IInspectable *iface, HSTRING key, IInspectable **value ) { - FIXME( "iface %p, key %s, value %p stub!\n", iface, debugstr_hstring( key ), value ); - return E_NOTIMPL; + struct map *impl = impl_from_IMap_HSTRING_IInspectable( iface ); + struct map_entry *entry; + int order; + + TRACE( "iface %p, key %s, value %p\n", iface, debugstr_hstring( key ), value ); + + if (!(entry = map_entries_lower_bound( impl->entries, impl->size, key, &order )) || order) return E_BOUNDS; + IInspectable_AddRef( (*value = entry->value )); + return S_OK; }
static HRESULT WINAPI map_get_Size( IMap_HSTRING_IInspectable *iface, UINT32 *size ) { - FIXME( "iface %p, size %p stub!\n", iface, size ); - return E_NOTIMPL; + struct map *impl = impl_from_IMap_HSTRING_IInspectable( iface ); + TRACE( "iface %p, size %p\n", iface, size ); + *size = impl->size; + return S_OK; }
static HRESULT WINAPI map_HasKey( IMap_HSTRING_IInspectable *iface, HSTRING key, boolean *exists ) { - FIXME( "iface %p, key %s, exists %p stub!\n", iface, debugstr_hstring( key ), exists ); - return E_NOTIMPL; + struct map *impl = impl_from_IMap_HSTRING_IInspectable( iface ); + int order; + + TRACE( "iface %p, key %s, exists %p\n", iface, debugstr_hstring( key ), exists ); + + map_entries_lower_bound( impl->entries, impl->size, key, &order ); + *exists = !order; + return S_OK; }
static HRESULT WINAPI map_GetView( IMap_HSTRING_IInspectable *iface, IMapView_HSTRING_IInspectable **value ) @@ -551,25 +675,69 @@ static HRESULT WINAPI map_GetView( IMap_HSTRING_IInspectable *iface, IMapView_HS
TRACE( "iface %p, value %p.\n", iface, value );
- return map_view_create( impl, value ); + return map_view_create( impl, 0, impl->size, value ); }
static HRESULT WINAPI map_Insert( IMap_HSTRING_IInspectable *iface, HSTRING key, IInspectable *value, boolean *replaced ) { - FIXME( "iface %p, key %p, value %p, replaced %p stub!\n", iface, key, value, replaced ); - return E_NOTIMPL; + struct map *impl = impl_from_IMap_HSTRING_IInspectable( iface ); + struct map_entry *tmp = impl->entries, *entry, copy; + HRESULT hr; + int order; + + TRACE( "iface %p, key %p, value %p, replaced %p\n", iface, key, value, replaced ); + + if (impl->size == impl->capacity) + { + impl->capacity = max( 32, impl->capacity * 3 / 2 ); + if (!(impl->entries = realloc( impl->entries, impl->capacity * sizeof(*impl->entries) ))) + { + impl->entries = tmp; + return E_OUTOFMEMORY; + } + } + + if (!(entry = map_entries_lower_bound( impl->entries, impl->size, key, &order ))) return E_OUTOFMEMORY; + if (FAILED(hr = map_entry_init( key, value, © ))) return hr; + + if ((*replaced = !order)) map_entry_clear( entry ); + else memmove( entry + 1, entry, (impl->entries + impl->size++ - entry) * sizeof(*impl->entries) ); + *entry = copy; + + return S_OK; }
static HRESULT WINAPI map_Remove( IMap_HSTRING_IInspectable *iface, HSTRING key ) { - FIXME( "iface %p, key %s stub!\n", iface, debugstr_hstring( key ) ); - return E_NOTIMPL; + struct map *impl = impl_from_IMap_HSTRING_IInspectable( iface ); + struct map_entry *entry; + int order; + + TRACE( "iface %p, key %s\n", iface, debugstr_hstring( key ) ); + + if (!(entry = map_entries_lower_bound( impl->entries, impl->size, key, &order )) || order) return E_BOUNDS; + map_entry_clear( entry ); + memmove( entry, entry + 1, (impl->entries + --impl->size - entry) * sizeof(*impl->entries) ); + + return S_OK; }
static HRESULT WINAPI map_Clear( IMap_HSTRING_IInspectable *iface ) { - FIXME( "iface %p stub!\n", iface ); - return E_NOTIMPL; + struct map *impl = impl_from_IMap_HSTRING_IInspectable( iface ); + struct map_entry *entries = impl->entries; + UINT32 size = impl->size; + + TRACE( "iface %p\n", iface ); + + impl->entries = NULL; + impl->capacity = 0; + impl->size = 0; + + while (size) map_entry_clear( entries + --size ); + free( entries ); + + return S_OK; }
static const IMap_HSTRING_IInspectableVtbl map_vtbl = diff --git a/dlls/wintypes/tests/wintypes.c b/dlls/wintypes/tests/wintypes.c index 4165d67ee1a..4a89fb57b70 100644 --- a/dlls/wintypes/tests/wintypes.c +++ b/dlls/wintypes/tests/wintypes.c @@ -1268,6 +1268,8 @@ static void test_IPropertySet(void) BOOLEAN boolean; HRESULT hr; HSTRING name, key1, key2; + IPropertyValue *propval; + UINT32 uint32 = 0;
hr = RoInitialize( RO_INIT_MULTITHREADED ); ok( hr == S_OK, "got %#lx\n", hr ); @@ -1314,21 +1316,16 @@ static void test_IPropertySet(void)
boolean = TRUE; hr = IMap_HSTRING_IInspectable_HasKey( map, NULL, &boolean ); - todo_wine ok( hr == S_OK, "HasKey failed, got %#lx\n", hr ); - todo_wine ok( !boolean, "Got boolean %d.\n", boolean ); hr = IMap_HSTRING_IInspectable_Lookup( map, NULL, &val ); - todo_wine ok( hr == E_BOUNDS, "Got hr %#lx\n", hr );
hr = IPropertyValueStatics_CreateUInt32( propval_statics, 0xdeadbeef, &val1 ); ok( hr == S_OK, "CreateUInt32 failed, got %#lx\n", hr ); boolean = TRUE; hr = IMap_HSTRING_IInspectable_Insert( map, NULL, val1, &boolean ); - todo_wine ok( hr == S_OK, "Insert failed, got %#lx\n", hr ); - todo_wine ok( !boolean, "Got boolean %d.\n", boolean );
hr = IPropertyValueStatics_CreateUInt32( propval_statics, 0xc0decafe, &val2 ); @@ -1336,94 +1333,64 @@ static void test_IPropertySet(void) boolean = FALSE; hr = IMap_HSTRING_IInspectable_Insert( map, NULL, val2, &boolean ); IInspectable_Release( val2 ); - todo_wine ok( boolean, "Got boolean %d.\n", boolean ); - todo_wine ok( hr == S_OK, "Insert failed, got %#lx\n", hr ); boolean = FALSE; hr = IMap_HSTRING_IInspectable_HasKey( map, NULL, &boolean ); - todo_wine ok( hr == S_OK, "HasKey failed, got %#lx\n", hr ); - todo_wine ok( boolean, "Got boolean %d.\n", boolean ); hr = IMap_HSTRING_IInspectable_Lookup( map, NULL, &val ); - todo_wine ok( hr == S_OK, "Lookup failed, got %#lx\n", hr ); - if (SUCCEEDED(hr)) - { - IPropertyValue *propval; - UINT32 uint32 = 0; - - hr = IInspectable_QueryInterface( val, &IID_IPropertyValue, (void **)&propval ); - IInspectable_Release( val ); - ok( hr == S_OK, "QueryInterface failed, got %#lx\n", hr ); - hr = IPropertyValue_GetUInt32( propval, &uint32 ); - IPropertyValue_Release( propval ); - ok( hr == S_OK, "GetUInt32, got %#lx\n", hr ); - ok( uint32 == 0xc0decafe, "Got uint32 %u\n", uint32 ); - } + hr = IInspectable_QueryInterface( val, &IID_IPropertyValue, (void **)&propval ); + IInspectable_Release( val ); + ok( hr == S_OK, "QueryInterface failed, got %#lx\n", hr ); + hr = IPropertyValue_GetUInt32( propval, &uint32 ); + IPropertyValue_Release( propval ); + ok( hr == S_OK, "GetUInt32, got %#lx\n", hr ); + ok( uint32 == 0xc0decafe, "Got uint32 %u\n", uint32 );
hr = WindowsCreateString( L"foo", 3, &key1 ); ok( hr == S_OK, "WindowsCreateString failed, got %#lx\n", hr ); boolean = TRUE; hr = IMap_HSTRING_IInspectable_Lookup( map, key1, &val ); - todo_wine ok( hr == E_BOUNDS, "Got hr %#lx\n", hr ); hr = IMap_HSTRING_IInspectable_Insert( map, key1, val1, &boolean ); IInspectable_Release( val1 ); - todo_wine ok( hr == S_OK, "Insert failed, got %#lx\n", hr ); - todo_wine ok( !boolean, "Got boolean %d.\n", boolean ); boolean = FALSE; hr = IMap_HSTRING_IInspectable_HasKey( map, key1, &boolean ); - todo_wine ok( hr == S_OK, "HasKey failed, got %#lx\n", hr ); - todo_wine ok( boolean, "Got boolean %d.\n", boolean ); hr = IMap_HSTRING_IInspectable_Lookup( map, key1, &val ); - todo_wine ok( hr == S_OK, "Lookup failed, got %#lx\n", hr ); - if (SUCCEEDED(hr)) - { - IPropertyValue *propval; - UINT32 uint32 = 0; - - hr = IInspectable_QueryInterface( val, &IID_IPropertyValue, (void **)&propval ); - IInspectable_Release( val ); - ok( hr == S_OK, "QueryInterface failed, got %#lx\n", hr ); - hr = IPropertyValue_GetUInt32( propval, &uint32 ); - IPropertyValue_Release( propval ); - ok( hr == S_OK, "GetUInt32, got %#lx\n", hr ); - ok( uint32 == 0xdeadbeef, "Got uint32 %u\n", uint32 ); - } + hr = IInspectable_QueryInterface( val, &IID_IPropertyValue, (void **)&propval ); + IInspectable_Release( val ); + ok( hr == S_OK, "QueryInterface failed, got %#lx\n", hr ); + hr = IPropertyValue_GetUInt32( propval, &uint32 ); + IPropertyValue_Release( propval ); + ok( hr == S_OK, "GetUInt32, got %#lx\n", hr ); + ok( uint32 == 0xdeadbeef, "Got uint32 %u\n", uint32 ); WindowsDeleteString( key1 );
hr = WindowsCreateString( L"bar", 3, &key2 ); ok( hr == S_OK, "WindowsCreateString failed, got %#lx\n", hr ); boolean = TRUE; hr = IMap_HSTRING_IInspectable_HasKey( map, key2, &boolean ); - todo_wine ok( hr == S_OK, "HasKey failed, got %#lx\n", hr ); - todo_wine ok( !boolean, "Got boolean %d.\n", boolean ); hr = IPropertyValueStatics_CreateUInt64( propval_statics, 0xdeadbeefdeadbeef, &val3 ); ok( hr == S_OK, "CreateUInt32 failed, got %#lx\n", hr ); boolean = TRUE; hr = IMap_HSTRING_IInspectable_Insert( map, key2, val3, &boolean ); IInspectable_Release( val3 ); - todo_wine ok( hr == S_OK, "Insert failed, got %#lx\n", hr ); - todo_wine ok( !boolean, "Got boolean %d.\n", boolean ); boolean = FALSE; hr = IMap_HSTRING_IInspectable_HasKey( map, key2, &boolean ); - todo_wine ok( hr == S_OK, "HasKey failed, got %#lx\n", hr ); - todo_wine ok( boolean, "Got boolean %d.\n", boolean ); hr = IMap_HSTRING_IInspectable_Lookup( map, key2, &val ); - todo_wine ok( hr == S_OK, "Lookup failed, got %#lx\n", hr ); if (SUCCEEDED(hr)) { @@ -1449,18 +1416,18 @@ static void test_IPropertySet(void)
check_interface( iterator, &IID_IAgileObject, TRUE ); hr = IIterator_IKeyValuePair_HSTRING_IInspectable_get_HasCurrent( iterator, &boolean ); - todo_wine ok( hr == S_OK, "Got hr %#lx\n", hr ); - todo_wine ok( boolean == TRUE, "Got %u\n", boolean ); + ok( hr == S_OK, "Got hr %#lx\n", hr ); + ok( boolean == TRUE, "Got %u\n", boolean );
hr = IIterator_IKeyValuePair_HSTRING_IInspectable_get_Current( iterator, &pair ); ok( hr == S_OK, "Got hr %#lx\n", hr ); check_interface( pair, &IID_IAgileObject, TRUE ); hr = IKeyValuePair_HSTRING_IInspectable_get_Key( pair, &key2 ); - todo_wine ok( hr == S_OK, "Got %#lx\n", hr ); + ok( hr == S_OK, "Got %#lx\n", hr ); WindowsDeleteString( key2 ); hr = IKeyValuePair_HSTRING_IInspectable_get_Value( pair, &val ); - todo_wine ok( hr == S_OK, "Got %#lx\n", hr ); - if (hr == S_OK) IInspectable_Release( val ); + ok( hr == S_OK, "Got %#lx\n", hr ); + IInspectable_Release( val );
hr = IMap_HSTRING_IInspectable_GetView( map, &map_view ); ok( hr == S_OK, "GetView failed, got %#lx\n", hr ); @@ -1470,27 +1437,25 @@ static void test_IPropertySet(void) (void **)&iterable ); ok( hr == S_OK, "QueryInterface failed, got %#lx\n", hr ); hr = IMapView_HSTRING_IInspectable_Lookup( map_view, key2, &val ); - todo_wine ok( hr == S_OK, "Lookup failed, got %#lx\n", hr ); - if (hr == S_OK) IInspectable_Release( val ); + IInspectable_Release( val );
/* after map is modified, associated objects are invalidated */ hr = IMap_HSTRING_IInspectable_Remove( map, key2 ); - todo_wine ok( hr == S_OK, "Remove failed, got %#lx\n", hr );
hr = IKeyValuePair_HSTRING_IInspectable_get_Key( pair, &key2 ); - todo_wine ok( hr == S_OK, "Got %#lx\n", hr ); + ok( hr == S_OK, "Got %#lx\n", hr ); WindowsDeleteString( key2 ); hr = IKeyValuePair_HSTRING_IInspectable_get_Value( pair, &val ); - todo_wine ok( hr == S_OK, "Got %#lx\n", hr ); - if (hr == S_OK) IInspectable_Release( val ); + ok( hr == S_OK, "Got %#lx\n", hr ); + IInspectable_Release( val ); IKeyValuePair_HSTRING_IInspectable_Release( pair );
hr = IIterator_IKeyValuePair_HSTRING_IInspectable_get_HasCurrent( iterator, &boolean ); - todo_wine ok( hr == S_OK, "Got hr %#lx\n", hr ); - todo_wine ok( boolean == TRUE, "Got %u\n", boolean ); + ok( hr == S_OK, "Got hr %#lx\n", hr ); + ok( boolean == TRUE, "Got %u\n", boolean ); hr = IIterator_IKeyValuePair_HSTRING_IInspectable_get_Current( iterator, &pair ); todo_wine ok( hr == E_CHANGED_STATE, "Got hr %#lx\n", hr ); IIterator_IKeyValuePair_HSTRING_IInspectable_Release( iterator );
From: Vibhav Pant vibhavp@gmail.com
--- dlls/wintypes/map.c | 34 ++++++++++++++++++++++++++++++++++ dlls/wintypes/tests/wintypes.c | 4 +--- 2 files changed, 35 insertions(+), 3 deletions(-)
diff --git a/dlls/wintypes/map.c b/dlls/wintypes/map.c index 0d431f479e7..944760a67c3 100644 --- a/dlls/wintypes/map.c +++ b/dlls/wintypes/map.c @@ -200,6 +200,7 @@ struct map struct map_iids iids; LONG ref;
+ LONG64 serial; UINT32 size; UINT32 capacity; struct map_entry *entries; @@ -212,6 +213,7 @@ struct map_view LONG ref;
struct map *map; + LONG64 serial; UINT32 size; struct map_entry entries[1]; }; @@ -225,6 +227,11 @@ struct iterator UINT32 index; };
+static HRESULT map_view_check_serial( struct map_view *view ) +{ + return ReadNoFence64( &view->map->serial ) == view->serial ? S_OK : E_CHANGED_STATE; +} + static struct iterator *impl_from_IIterator_IKeyValuePair_HSTRING_IInspectable( IIterator_IKeyValuePair_HSTRING_IInspectable *iface ) { return CONTAINING_RECORD( iface, struct iterator, IIterator_IKeyValuePair_HSTRING_IInspectable_iface ); @@ -295,14 +302,20 @@ static HRESULT WINAPI iterator_GetTrustLevel( IIterator_IKeyValuePair_HSTRING_II static HRESULT WINAPI iterator_get_Current( IIterator_IKeyValuePair_HSTRING_IInspectable *iface, IKeyValuePair_HSTRING_IInspectable **value ) { struct iterator *impl = impl_from_IIterator_IKeyValuePair_HSTRING_IInspectable( iface ); + HRESULT hr; + TRACE( "iface %p, value %p\n", iface, value ); + + if (FAILED(hr = map_view_check_serial( impl->view ))) return hr; return pair_create( impl->view->map->iids.pair, impl->view->entries + impl->index, value ); }
static HRESULT WINAPI iterator_get_HasCurrent( IIterator_IKeyValuePair_HSTRING_IInspectable *iface, boolean *value ) { struct iterator *impl = impl_from_IIterator_IKeyValuePair_HSTRING_IInspectable( iface ); + TRACE( "iface %p, value %p\n", iface, value ); + *value = impl->index < impl->view->size; return S_OK; } @@ -310,7 +323,11 @@ static HRESULT WINAPI iterator_get_HasCurrent( IIterator_IKeyValuePair_HSTRING_I static HRESULT WINAPI iterator_MoveNext( IIterator_IKeyValuePair_HSTRING_IInspectable *iface, boolean *value ) { struct iterator *impl = impl_from_IIterator_IKeyValuePair_HSTRING_IInspectable( iface ); + HRESULT hr; + TRACE( "iface %p, value %p\n", iface, value ); + + if (FAILED(hr = map_view_check_serial( impl->view ))) return hr; if (impl->index < impl->view->size) impl->index++; return IIterator_IKeyValuePair_HSTRING_IInspectable_get_HasCurrent( iface, value ); } @@ -324,6 +341,7 @@ static HRESULT WINAPI iterator_GetMany( IIterator_IKeyValuePair_HSTRING_IInspect
TRACE( "iface %p, items_size %u, items %p, count %p\n", iface, items_size, items, count );
+ if (FAILED(hr = map_view_check_serial( impl->view ))) return hr; if ((len = impl->view->size - impl->index) < 0) return E_BOUNDS; for (UINT32 i = 0; i < len; ++i) { @@ -430,10 +448,12 @@ static HRESULT WINAPI map_view_Lookup( IMapView_HSTRING_IInspectable *iface, HST { struct map_view *impl = impl_from_IMapView_HSTRING_IInspectable( iface ); struct map_entry *entry; + HRESULT hr; int order;
TRACE( "iface %p, key %s, value %p\n", iface, debugstr_hstring( key ), value );
+ if (FAILED(hr = map_view_check_serial( impl ))) return hr; if (!(entry = map_entries_lower_bound( impl->entries, impl->size, key, &order )) || order) return E_BOUNDS; IInspectable_AddRef( (*value = entry->value )); return S_OK; @@ -442,7 +462,11 @@ static HRESULT WINAPI map_view_Lookup( IMapView_HSTRING_IInspectable *iface, HST static HRESULT WINAPI map_view_get_Size( IMapView_HSTRING_IInspectable *iface, UINT32 *value ) { struct map_view *impl = impl_from_IMapView_HSTRING_IInspectable( iface ); + HRESULT hr; + TRACE( "iface %p, value %p\n", iface, value ); + + if (FAILED(hr = map_view_check_serial( impl ))) return hr; *value = impl->size; return S_OK; } @@ -450,10 +474,12 @@ static HRESULT WINAPI map_view_get_Size( IMapView_HSTRING_IInspectable *iface, U static HRESULT WINAPI map_view_HasKey( IMapView_HSTRING_IInspectable *iface, HSTRING key, boolean *found ) { struct map_view *impl = impl_from_IMapView_HSTRING_IInspectable( iface ); + HRESULT hr; int order;
TRACE( "iface %p, key %s, found %p\n", iface, debugstr_hstring( key ), found );
+ if (FAILED(hr = map_view_check_serial( impl ))) return hr; map_entries_lower_bound( impl->entries, impl->size, key, &order ); *found = !order; return S_OK; @@ -469,6 +495,7 @@ static HRESULT WINAPI map_view_Split( IMapView_HSTRING_IInspectable *iface, IMap
TRACE( "iface %p, first %p, second %p\n", iface, first, second );
+ if (FAILED(hr = map_view_check_serial( impl ))) return hr; if (FAILED(hr = map_view_create( impl->map, 0, impl->size / 2, first ))) return hr; if (FAILED(hr = map_view_create( impl->map, impl->size / 2, impl->size - impl->size / 2, second ))) IMapView_HSTRING_IInspectable_Release( *first ); @@ -499,9 +526,12 @@ static HRESULT WINAPI iterable_view_First( IIterable_IKeyValuePair_HSTRING_IInsp { struct map_view *impl = view_impl_from_IIterable_IKeyValuePair_HSTRING_IInspectable( iface ); struct iterator *iter; + HRESULT hr;
TRACE( "iface %p, value %p.\n", iface, value );
+ if (FAILED(hr = map_view_check_serial( impl ))) return hr; + if (!(iter = calloc( 1, sizeof(struct iterator) ))) return E_OUTOFMEMORY; iter->IIterator_IKeyValuePair_HSTRING_IInspectable_iface.lpVtbl = &iterator_vtbl; iter->ref = 1; @@ -537,6 +567,7 @@ static HRESULT map_view_create( struct map *map, UINT first, UINT count, IMapVie
IMap_HSTRING_IInspectable_AddRef( &map->IMap_HSTRING_IInspectable_iface ); view->map = map; + view->serial = map->serial;
for (UINT32 i = 0; i < count; ++i) map_entry_copy( view->entries + view->size++, map->entries + i );
@@ -704,6 +735,7 @@ static HRESULT WINAPI map_Insert( IMap_HSTRING_IInspectable *iface, HSTRING key, else memmove( entry + 1, entry, (impl->entries + impl->size++ - entry) * sizeof(*impl->entries) ); *entry = copy;
+ InterlockedIncrement64( &impl->serial ); return S_OK; }
@@ -719,6 +751,7 @@ static HRESULT WINAPI map_Remove( IMap_HSTRING_IInspectable *iface, HSTRING key map_entry_clear( entry ); memmove( entry, entry + 1, (impl->entries + --impl->size - entry) * sizeof(*impl->entries) );
+ InterlockedIncrement64( &impl->serial ); return S_OK; }
@@ -737,6 +770,7 @@ static HRESULT WINAPI map_Clear( IMap_HSTRING_IInspectable *iface ) while (size) map_entry_clear( entries + --size ); free( entries );
+ InterlockedIncrement64( &impl->serial ); return S_OK; }
diff --git a/dlls/wintypes/tests/wintypes.c b/dlls/wintypes/tests/wintypes.c index 4a89fb57b70..3025ab69235 100644 --- a/dlls/wintypes/tests/wintypes.c +++ b/dlls/wintypes/tests/wintypes.c @@ -1457,15 +1457,13 @@ static void test_IPropertySet(void) ok( hr == S_OK, "Got hr %#lx\n", hr ); ok( boolean == TRUE, "Got %u\n", boolean ); hr = IIterator_IKeyValuePair_HSTRING_IInspectable_get_Current( iterator, &pair ); - todo_wine ok( hr == E_CHANGED_STATE, "Got hr %#lx\n", hr ); + ok( hr == E_CHANGED_STATE, "Got hr %#lx\n", hr ); IIterator_IKeyValuePair_HSTRING_IInspectable_Release( iterator );
hr = IMapView_HSTRING_IInspectable_Lookup( map_view, key2, &val ); - todo_wine ok( hr == E_CHANGED_STATE, "Got hr %#lx\n", hr ); WindowsDeleteString( key2 ); hr = IIterable_IKeyValuePair_HSTRING_IInspectable_First( iterable, &iterator ); - todo_wine ok( hr == E_CHANGED_STATE, "got %#lx\n", hr ); IIterable_IKeyValuePair_HSTRING_IInspectable_Release( iterable ); IMapView_HSTRING_IInspectable_Release( map_view );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/wintypes/map.c | 235 +++++++++++++++++++++++++++++++++++- dlls/wintypes/private.h | 3 +- dlls/wintypes/propertyset.c | 2 +- 3 files changed, 237 insertions(+), 3 deletions(-)
diff --git a/dlls/wintypes/map.c b/dlls/wintypes/map.c index 944760a67c3..080964bb5d8 100644 --- a/dlls/wintypes/map.c +++ b/dlls/wintypes/map.c @@ -829,7 +829,7 @@ static const struct IIterable_IKeyValuePair_HSTRING_IInspectableVtbl iterable_vt iterable_First, };
-HRESULT map_create( const struct map_iids *iids, IInspectable *outer, IInspectable **out ) +HRESULT single_threaded_map_create( const struct map_iids *iids, IInspectable *outer, IInspectable **out ) { struct map *impl;
@@ -847,3 +847,236 @@ HRESULT map_create( const struct map_iids *iids, IInspectable *outer, IInspectab TRACE( "created %p\n", *out ); return S_OK; } + +struct locked_map +{ + IInspectable IInspectable_iface; + IMap_HSTRING_IInspectable IMap_HSTRING_IInspectable_iface; + IInspectable *IInspectable_outer; + struct map_iids iids; + LONG ref; + + SRWLOCK lock; + IInspectable *inner; + IMap_HSTRING_IInspectable *inner_map; +}; + +static struct locked_map *locked_map_from_IInspectable( IInspectable *iface ) +{ + return CONTAINING_RECORD( iface, struct locked_map, IInspectable_iface ); +} + +static HRESULT WINAPI locked_map_inner_QueryInterface( IInspectable *iface, REFIID iid, void **out ) +{ + struct locked_map *impl = locked_map_from_IInspectable( iface ); + + TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out ); + + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IInspectable ) || + IsEqualGUID( iid, &IID_IAgileObject )) + { + IInspectable_AddRef( (*out = &impl->IInspectable_iface) ); + return S_OK; + } + + if (IsEqualGUID( iid, impl->iids.map )) + { + IInspectable_AddRef( (*out = &impl->IMap_HSTRING_IInspectable_iface) ); + return S_OK; + } + + if (SUCCEEDED(IInspectable_QueryInterface( impl->inner, iid, out ))) return S_OK; + + FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI locked_map_inner_AddRef( IInspectable *iface ) +{ + struct locked_map *impl = locked_map_from_IInspectable( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + TRACE( "iface %p increasing refcount to %lu.\n", iface, ref ); + return ref; +} + +static ULONG WINAPI locked_map_inner_Release( IInspectable *iface ) +{ + struct locked_map *impl = locked_map_from_IInspectable( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + + TRACE( "iface %p decreasing refcount to %lu.\n", iface, ref ); + + if (!ref) + { + IInspectable_Release( impl->inner ); + free( impl ); + } + + return ref; +} + +static HRESULT WINAPI locked_map_inner_GetIids( IInspectable *iface, ULONG *iid_count, IID **iids ) +{ + FIXME( "iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids ); + return E_NOTIMPL; +} + +static HRESULT WINAPI locked_map_inner_GetRuntimeClassName( IInspectable *iface, HSTRING *class_name ) +{ + FIXME( "iface %p, class_name %p stub!\n", iface, class_name ); + return E_NOTIMPL; +} + +static HRESULT WINAPI locked_map_inner_GetTrustLevel( IInspectable *iface, TrustLevel *trust_level ) +{ + FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level ); + return E_NOTIMPL; +} + +static const IInspectableVtbl locked_map_inner_vtbl = +{ + /* IUnknown */ + locked_map_inner_QueryInterface, + locked_map_inner_AddRef, + locked_map_inner_Release, + /* IInspectable */ + locked_map_inner_GetIids, + locked_map_inner_GetRuntimeClassName, + locked_map_inner_GetTrustLevel, +}; + +DEFINE_IINSPECTABLE_( locked_map, IMap_HSTRING_IInspectable, struct locked_map, locked_map_from_IMap_HSTRING_IInspectable, + IMap_HSTRING_IInspectable_iface, impl->IInspectable_outer ); + +static HRESULT WINAPI locked_map_Lookup( IMap_HSTRING_IInspectable *iface, HSTRING key, IInspectable **value ) +{ + struct locked_map *impl = locked_map_from_IMap_HSTRING_IInspectable( iface ); + HRESULT hr; + + AcquireSRWLockExclusive( &impl->lock ); + hr = IMap_HSTRING_IInspectable_Lookup( impl->inner_map, key, value ); + ReleaseSRWLockExclusive( &impl->lock ); + + return hr; +} + +static HRESULT WINAPI locked_map_get_Size( IMap_HSTRING_IInspectable *iface, UINT32 *size ) +{ + struct locked_map *impl = locked_map_from_IMap_HSTRING_IInspectable( iface ); + HRESULT hr; + + AcquireSRWLockExclusive( &impl->lock ); + hr = IMap_HSTRING_IInspectable_get_Size( impl->inner_map, size ); + ReleaseSRWLockExclusive( &impl->lock ); + + return hr; +} + +static HRESULT WINAPI locked_map_HasKey( IMap_HSTRING_IInspectable *iface, HSTRING key, boolean *exists ) +{ + struct locked_map *impl = locked_map_from_IMap_HSTRING_IInspectable( iface ); + HRESULT hr; + + AcquireSRWLockExclusive( &impl->lock ); + hr = IMap_HSTRING_IInspectable_HasKey( impl->inner_map, key, exists ); + ReleaseSRWLockExclusive( &impl->lock ); + + return hr; +} + +static HRESULT WINAPI locked_map_GetView( IMap_HSTRING_IInspectable *iface, IMapView_HSTRING_IInspectable **value ) +{ + struct locked_map *impl = locked_map_from_IMap_HSTRING_IInspectable( iface ); + HRESULT hr; + + AcquireSRWLockExclusive( &impl->lock ); + hr = IMap_HSTRING_IInspectable_GetView( impl->inner_map, value ); + ReleaseSRWLockExclusive( &impl->lock ); + + return hr; +} + +static HRESULT WINAPI locked_map_Insert( IMap_HSTRING_IInspectable *iface, HSTRING key, IInspectable *value, boolean *replaced ) +{ + struct locked_map *impl = locked_map_from_IMap_HSTRING_IInspectable( iface ); + HRESULT hr; + + AcquireSRWLockExclusive( &impl->lock ); + hr = IMap_HSTRING_IInspectable_Insert( impl->inner_map, key, value, replaced ); + ReleaseSRWLockExclusive( &impl->lock ); + + return hr; +} + +static HRESULT WINAPI locked_map_Remove( IMap_HSTRING_IInspectable *iface, HSTRING key ) +{ + struct locked_map *impl = locked_map_from_IMap_HSTRING_IInspectable( iface ); + HRESULT hr; + + AcquireSRWLockExclusive( &impl->lock ); + hr = IMap_HSTRING_IInspectable_Remove( impl->inner_map, key ); + ReleaseSRWLockExclusive( &impl->lock ); + + return hr; +} + +static HRESULT WINAPI locked_map_Clear( IMap_HSTRING_IInspectable *iface ) +{ + struct locked_map *impl = locked_map_from_IMap_HSTRING_IInspectable( iface ); + HRESULT hr; + + AcquireSRWLockExclusive( &impl->lock ); + hr = IMap_HSTRING_IInspectable_Clear( impl->inner_map ); + ReleaseSRWLockExclusive( &impl->lock ); + + return hr; +} + +static const IMap_HSTRING_IInspectableVtbl locked_map_vtbl = +{ + /* IUnknown */ + locked_map_QueryInterface, + locked_map_AddRef, + locked_map_Release, + /* IInspectable */ + locked_map_GetIids, + locked_map_GetRuntimeClassName, + locked_map_GetTrustLevel, + /* IMap<HSTRING, IInspectable *> */ + locked_map_Lookup, + locked_map_get_Size, + locked_map_HasKey, + locked_map_GetView, + locked_map_Insert, + locked_map_Remove, + locked_map_Clear, +}; + +HRESULT multi_threaded_map_create( const struct map_iids *iids, IInspectable *outer, IInspectable **out ) +{ + struct locked_map *impl; + HRESULT hr; + + TRACE( "iid %s, out %p.\n", debugstr_guid( iids->map ), out ); + + if (!(impl = calloc( 1, sizeof(*impl) ))) return E_OUTOFMEMORY; + impl->IInspectable_iface.lpVtbl = &locked_map_inner_vtbl; + impl->IMap_HSTRING_IInspectable_iface.lpVtbl = &locked_map_vtbl; + impl->IInspectable_outer = outer ? outer : &impl->IInspectable_iface; + impl->iids = *iids; + impl->ref = 1; + + if (FAILED(hr = single_threaded_map_create( iids, impl->IInspectable_outer, &impl->inner ))) + { + free( impl ); + return hr; + } + IInspectable_QueryInterface( impl->inner, iids->map, (void **)&impl->inner_map ); + IMap_HSTRING_IInspectable_Release( impl->inner_map ); /* release outer reference */ + + *out = &impl->IInspectable_iface; + TRACE( "created %p\n", *out ); + return S_OK; +} diff --git a/dlls/wintypes/private.h b/dlls/wintypes/private.h index c127ae2358d..901b651208b 100644 --- a/dlls/wintypes/private.h +++ b/dlls/wintypes/private.h @@ -47,7 +47,8 @@ struct map_iids const GUID *iterator; const GUID *pair; }; -extern HRESULT map_create( const struct map_iids *iids, IInspectable *outer, IInspectable **out ); +extern HRESULT single_threaded_map_create( const struct map_iids *iids, IInspectable *outer, IInspectable **out ); +extern HRESULT multi_threaded_map_create( const struct map_iids *iids, IInspectable *outer, IInspectable **out );
extern IActivationFactory *data_writer_activation_factory; extern IActivationFactory *buffer_activation_factory; diff --git a/dlls/wintypes/propertyset.c b/dlls/wintypes/propertyset.c index 9d625de921c..14804758f5b 100644 --- a/dlls/wintypes/propertyset.c +++ b/dlls/wintypes/propertyset.c @@ -240,7 +240,7 @@ static HRESULT STDMETHODCALLTYPE factory_ActivateInstance( IActivationFactory *i impl->IObservableMap_HSTRING_IInspectable_iface.lpVtbl = &propertyset_IObservableMap_vtbl; impl->ref = 1;
- if (FAILED(hr = map_create( &iids, (IInspectable *)&impl->IPropertySet_iface, &impl->map_inner ))) + if (FAILED(hr = multi_threaded_map_create( &iids, (IInspectable *)&impl->IPropertySet_iface, &impl->map_inner ))) { free( impl ); return hr;