From: Vibhav Pant vibhavp@gmail.com
--- dlls/wintypes/tests/Makefile.in | 1 + dlls/wintypes/tests/propertyset.c | 583 ++++++++++++++++++++++++++ dlls/wintypes/tests/wintypes.c | 2 + dlls/wintypes/tests/wintypes_test.idl | 10 + 4 files changed, 596 insertions(+) create mode 100644 dlls/wintypes/tests/propertyset.c
diff --git a/dlls/wintypes/tests/Makefile.in b/dlls/wintypes/tests/Makefile.in index c5ae17c4694..afb4fd4a7f5 100644 --- a/dlls/wintypes/tests/Makefile.in +++ b/dlls/wintypes/tests/Makefile.in @@ -2,5 +2,6 @@ TESTDLL = wintypes.dll IMPORTS = wintypes combase uuid
SOURCES = \ + propertyset.c \ wintypes.c \ wintypes_test.idl diff --git a/dlls/wintypes/tests/propertyset.c b/dlls/wintypes/tests/propertyset.c new file mode 100644 index 00000000000..3dbf95940f3 --- /dev/null +++ b/dlls/wintypes/tests/propertyset.c @@ -0,0 +1,583 @@ +/* + * Copyright 2024 Vibhav Pant + * + * 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 "roapi.h" +#include "ole2.h" + +#define WIDL_using_Windows_Foundation +#define WIDL_using_Windows_Foundation_Collections +#include "windows.foundation.h" +#include "wintypes_test.h" + +#include "wine/test.h" + +static const WCHAR *class_name = RuntimeClass_Windows_Foundation_Collections_PropertySet; +static const struct DateTime datetime_value = {0x12345678abcdef}; +static const struct TimeSpan timespan_value = {0x12345678abcdef}; +static const struct Point point_value = {1, 2}; +static const struct Size size_value = {1, 2}; +static const struct Rect rect_value = {1, 2, 3, 4}; + +#define DEFINE_IUNKNOWN_( 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) ); \ + } +#define DEFINE_IUNKNOWN( pfx, iface_type, impl_type, base_iface ) \ + DEFINE_IUNKNOWN_( pfx, iface_type, impl_type, impl_from_##iface_type, iface_type##_iface, \ + &impl->base_iface ) + +struct propset_changed_event_handler +{ + IWinePropertySetChangedEventHandler IWinePropertySetChangedEventHandler_iface; + IMapChangedEventHandler_HSTRING_IInspectable IMapChangedEventHandler_HSTRING_IInspectable_iface; + + CollectionChange expected; + + LONG invoked; + LONG ref; +}; + +static inline struct propset_changed_event_handler * +impl_from_IWinePropertySetChangedEventHandler( IWinePropertySetChangedEventHandler *iface ) +{ + return CONTAINING_RECORD( iface, struct propset_changed_event_handler, + IWinePropertySetChangedEventHandler_iface ); +} + +static HRESULT STDMETHODCALLTYPE propset_changed_event_handler_QueryInterface( + IWinePropertySetChangedEventHandler *iface, REFIID iid, void **out ) +{ + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IInspectable ) || + IsEqualGUID( iid, &IID_IWinePropertySetChangedEventHandler )) + { + *out = iface; + IUnknown_AddRef( iface ); + return S_OK; + } + if (IsEqualGUID( iid, &IID_IMapChangedEventHandler_HSTRING_IInspectable )) + { + struct propset_changed_event_handler *impl = + impl_from_IWinePropertySetChangedEventHandler( iface ); + *out = &impl->IMapChangedEventHandler_HSTRING_IInspectable_iface; + IUnknown_AddRef( iface ); + return S_OK; + } + + return E_NOINTERFACE; +} + +static ULONG STDMETHODCALLTYPE +propset_changed_event_handler_AddRef( IWinePropertySetChangedEventHandler *iface ) +{ + struct propset_changed_event_handler *impl = + impl_from_IWinePropertySetChangedEventHandler( iface ); + return InterlockedIncrement( &impl->ref ); +} + +static ULONG STDMETHODCALLTYPE +propset_changed_event_handler_Release( IWinePropertySetChangedEventHandler *iface ) +{ + struct propset_changed_event_handler *impl = + impl_from_IWinePropertySetChangedEventHandler( iface ); + ULONG ref; + + ref = InterlockedDecrement( &impl->ref ); + if (!ref) + free( impl ); + return ref; +} + +static HRESULT STDMETHODCALLTYPE propset_changed_event_handler_get_TimesInvoked( + IWinePropertySetChangedEventHandler *iface, ULONG *times ) +{ + struct propset_changed_event_handler *impl = + impl_from_IWinePropertySetChangedEventHandler( iface ); + *times = impl->invoked; + return S_OK; +} + +static HRESULT STDMETHODCALLTYPE propset_changed_event_handler_Reset( IWinePropertySetChangedEventHandler *iface ) +{ + struct propset_changed_event_handler *impl = + impl_from_IWinePropertySetChangedEventHandler( iface ); + InterlockedExchange( &impl->invoked, 0 ); + return S_OK; +} + +const static IWinePropertySetChangedEventHandlerVtbl propset_changed_event_handler_vtbl = +{ + /* IUnknown */ + propset_changed_event_handler_QueryInterface, + propset_changed_event_handler_AddRef, + propset_changed_event_handler_Release, + /* IWinePropertySetChangedEventHandlerVtbl */ + propset_changed_event_handler_get_TimesInvoked, + propset_changed_event_handler_Reset, +}; + +DEFINE_IUNKNOWN( map_changed_event_handler, IMapChangedEventHandler_HSTRING_IInspectable, + struct propset_changed_event_handler, + IWinePropertySetChangedEventHandler_iface ); + +static HRESULT STDMETHODCALLTYPE map_changed_event_handler_Invoke( + IMapChangedEventHandler_HSTRING_IInspectable *iface, IObservableMap_HSTRING_IInspectable *map, + IMapChangedEventArgs_HSTRING *event_args ) +{ + struct propset_changed_event_handler *impl; + CollectionChange got; + HRESULT hr; + HSTRING key; + + impl = impl_from_IMapChangedEventHandler_HSTRING_IInspectable( iface ); + hr = IMapChangedEventArgs_HSTRING_get_CollectionChanged( event_args, &got ); + ok( SUCCEEDED( hr ), "got %#lx\n", hr ); + hr = IMapChangedEventArgs_HSTRING_get_Key( event_args, &key ); + ok( SUCCEEDED( hr ), "got %#lx\n", hr ); + if (impl->expected == got) + InterlockedIncrement( &impl->invoked ); + return S_OK; +} + +const static IMapChangedEventHandler_HSTRING_IInspectableVtbl map_changed_event_handler_vtbl = +{ + /* IUnknown */ + map_changed_event_handler_QueryInterface, + map_changed_event_handler_AddRef, + map_changed_event_handler_Release, + /* IMapChangedEventHandler<HSTRING, IInspectable*> */ + map_changed_event_handler_Invoke, +}; + +HRESULT propertyset_changed_event_handler_create( CollectionChange change, + IMapChangedEventHandler_HSTRING_IInspectable **out ) +{ + struct propset_changed_event_handler *impl; + + impl = calloc( 1, sizeof( *impl ) ); + if (!impl) + return E_OUTOFMEMORY; + impl->IWinePropertySetChangedEventHandler_iface.lpVtbl = &propset_changed_event_handler_vtbl; + impl->IMapChangedEventHandler_HSTRING_IInspectable_iface.lpVtbl = + &map_changed_event_handler_vtbl; + impl->expected = change; + impl->ref = 1; + + *out = &impl->IMapChangedEventHandler_HSTRING_IInspectable_iface; + return S_OK; +} + +static void test_IPropertySet(void) +{ + IActivationFactory *factory; + IInspectable *inspectable; + IPropertyValueStatics *statics; + IPropertySet *propset; + IMap_HSTRING_IInspectable *map; + IMapView_HSTRING_IInspectable *map_view, *first_view = NULL, *second_view = NULL; + IIterable_IKeyValuePair_HSTRING_IInspectable *iterable; + IIterator_IKeyValuePair_HSTRING_IInspectable *iterator; + IMapChangedEventHandler_HSTRING_IInspectable *handler_inserted = NULL, *handler_changed = NULL, + *handler_removed = NULL, *handler_reset = NULL; + EventRegistrationToken token_inserted = {0}, token_changed = {0}, token_removed = {0}, + token_reset = {0}; + IObservableMap_HSTRING_IInspectable *observable_map; + unsigned int size, prev_size; + boolean valid; + HRESULT hr; + HSTRING name; + + hr = RoInitialize( RO_INIT_MULTITHREADED ); + ok( SUCCEEDED( hr ), "got %#lx\n", hr ); + + hr = WindowsCreateString( class_name, wcslen( class_name ), &name ); + ok( SUCCEEDED( hr ), "got %#lx\n", hr ); + hr = RoGetActivationFactory( name, &IID_IActivationFactory, (void **)&factory ); + ok( hr == S_OK || broken( hr == REGDB_E_CLASSNOTREG ), + "RoGetActivationFactory failed, hr %#lx.\n", hr ); + if (hr == REGDB_E_CLASSNOTREG) + { + win_skip( "%s runtimeclass not registered, skipping tests.\n", + wine_dbgstr_w( class_name ) ); + WindowsDeleteString( name ); + RoUninitialize(); + return; + } + WindowsDeleteString( name ); + class_name = RuntimeClass_Windows_Foundation_PropertyValue; + hr = WindowsCreateString( class_name, wcslen( class_name ), &name ); + ok( SUCCEEDED( hr ), "got %#lx\n", hr ); + hr = RoGetActivationFactory( name, &IID_IPropertyValueStatics, (void **)&statics ); + ok( hr == S_OK || broken( hr == REGDB_E_CLASSNOTREG ), + "RoGetActivationFactory failed, hr %#lx.\n", hr ); + if (hr == REGDB_E_CLASSNOTREG) + { + win_skip( "%s runtimeclass not registered, skipping tests.\n", + wine_dbgstr_w( class_name ) ); + WindowsDeleteString( name ); + RoUninitialize(); + return; + } + WindowsDeleteString( name ); + + hr = IActivationFactory_ActivateInstance( factory, &inspectable ); + IActivationFactory_Release( factory ); + todo_wine ok( SUCCEEDED( hr ), "got %#lx\n", hr ); + if (FAILED( hr )) + { + skip("could not activate PropertySet instance.\n"); + IPropertyValueStatics_Release( statics ); + RoUninitialize(); + return; + } + + hr = IInspectable_QueryInterface( inspectable, &IID_IPropertySet, (void **)&propset ); + IInspectable_Release( inspectable ); + todo_wine ok( SUCCEEDED( hr ), "QueryInterface failed, got %#lx\n", hr ); + if (FAILED( hr )) + { + IPropertyValueStatics_Release( statics ); + RoUninitialize(); + return; + } + + hr = IPropertySet_QueryInterface( propset, &IID_IMap_HSTRING_IInspectable, (void **)&map ); + todo_wine ok( SUCCEEDED( hr ), "QueryInterface failed, got %#lx\n", hr ); + if (FAILED( hr )) + { + IPropertyValueStatics_Release( statics ); + RoUninitialize(); + return; + } + + hr = IPropertySet_QueryInterface( propset, &IID_IObservableMap_HSTRING_IInspectable, + (void *)&observable_map ); + IPropertySet_Release(propset); + todo_wine ok(SUCCEEDED(hr), "QueryInterface failed, got %#lx\n", hr); + +#define EVENT_HANDLER_CREATE(t, c) \ + do \ + { \ + hr = propertyset_changed_event_handler_create( (c), &handler_##t); \ + ok( SUCCEEDED( hr ), "got %#lx\n", hr); \ + if (FAILED( hr )) break; \ + hr = IObservableMap_HSTRING_IInspectable_add_MapChanged( observable_map, \ + handler_##t, \ + &token_##t ); \ + todo_wine ok( SUCCEEDED( hr ), "got %#lx\n", hr); \ + } while(0) + + if (SUCCEEDED( hr )) + { + EVENT_HANDLER_CREATE( inserted, CollectionChange_ItemInserted ); + EVENT_HANDLER_CREATE( changed, CollectionChange_ItemChanged ); + EVENT_HANDLER_CREATE( removed, CollectionChange_ItemRemoved ); + EVENT_HANDLER_CREATE( reset, CollectionChange_Reset ); + } + else + skip( "could not obtain an IObservableMap<HSTRING, IInspectable *> instance.\n" ); + +#define TEST_MAP_VALUES \ + MAP_TEST( Boolean, 1, boolean ); \ + MAP_TEST( UInt16, 0xdead, UINT16 ); \ + MAP_TEST( Int16, 0xdead, INT16 ); \ + MAP_TEST( UInt32, 0xdeadbeef, UINT32 ); \ + MAP_TEST( Int32, 0xdeadbeef, INT32 ); \ + MAP_TEST( UInt64, 0xdeadbeefdeadbeef, UINT64 ); \ + MAP_TEST( Int64, 0xdeadbeefdeadbeef, INT64 ); \ + MAP_TEST( Single, 1.5, FLOAT ); \ + MAP_TEST( Double, 2.5, DOUBLE ); \ + MAP_TEST( DateTime, datetime_value, struct DateTime ); \ + MAP_TEST( TimeSpan, timespan_value, struct TimeSpan ); \ + MAP_TEST( Point, point_value, struct Point ); \ + MAP_TEST( Size, size_value, struct Size ); \ + MAP_TEST( Rect, rect_value, struct Rect ); \ + MAP_TEST( Guid, IID_IPropertyValue, GUID ) + +#define STR_(a) L###a +#define STR(a) STR_(a) +#define MAP_TEST( t, v, ct ) \ + do \ + { \ + HSTRING key; \ + IInspectable *value; \ + boolean replace; \ + const static WCHAR *str = STR( t ); \ + unsigned int cur_size; \ + ct data_val; \ + memset( &data_val, 0, sizeof( ct ) ); \ + hr = WindowsCreateString( str, wcslen( str ), &key ); \ + ok( SUCCEEDED( hr ), "got %#lx\n", hr ); \ + if (FAILED( hr )) break; \ + hr = IPropertyValueStatics_Create##t( statics, data_val, &value ); \ + ok( SUCCEEDED( hr ), "got %#lx\n", hr ); \ + if (FAILED( hr )) \ + { \ + WindowsDeleteString( key ); \ + break; \ + } \ + hr = IMap_HSTRING_IInspectable_Insert( map, key, value, &replace ); \ + IInspectable_Release( value ); \ + todo_wine ok( SUCCEEDED( hr ), "Insert failed, got %#lx\n", hr ); \ + if (SUCCEEDED( hr )) ok( !replace, "%d != 0\n", replace ); \ + hr = IMap_HSTRING_IInspectable_get_Size( map, &size ); \ + todo_wine ok( SUCCEEDED( hr ), "get_Size failed, got %#lx\n", hr ); \ + if (SUCCEEDED( hr )) ok( size == prev_size + 1, "%u != %u\n", size, prev_size + 1 ); \ + prev_size = cur_size = size; \ + hr = IPropertyValueStatics_Create##t( statics, ( v ), &value ); \ + ok( SUCCEEDED( hr ), "got %#lx\n", hr ); \ + if (FAILED( hr )) \ + { \ + WindowsDeleteString( key ); \ + break; \ + } \ + hr = IMap_HSTRING_IInspectable_Insert( map, key, value, &replace ); \ + IInspectable_Release( value ); \ + todo_wine ok( SUCCEEDED( hr ), "Insert failed, got %#lx\n", hr ); \ + todo_wine ok( replace, "%d is not non-zero\n", replace ); \ + hr = IMap_HSTRING_IInspectable_get_Size( map, &size ); \ + todo_wine ok( SUCCEEDED( hr ), "get_Size failed, got %#lx\n", hr); \ + if (SUCCEEDED( hr )) ok( size == cur_size, "%u != %u\n", size, cur_size ); \ + } while (0) + + prev_size = 0; + TEST_MAP_VALUES; + +#define TEST_EVENT_HANDLER(t, v) \ + do \ + { \ + IWinePropertySetChangedEventHandler *handler; \ + ULONG invoked; \ + if (!(handler_##t) || !(token_##t.value)) break; \ + hr = IUnknown_QueryInterface( (handler_##t), \ + &IID_IWinePropertySetChangedEventHandler, \ + (void **)&handler ); \ + ok( SUCCEEDED( hr ), "got %#lx\n", hr ); \ + if (FAILED(hr)) break; \ + hr = IWinePropertySetChangedEventHandler_get_TimesInvoked( handler, &invoked ); \ + ok( SUCCEEDED( hr ), "got %#lx\n", hr); \ + todo_wine ok( invoked == (v), "%lu != %lu\n", invoked, (ULONG)(v)); \ + hr = IWinePropertySetChangedEventHandler_Reset( handler ); \ + ok( SUCCEEDED( hr ), "got %#lx\n", hr ); \ + } while(0); + + TEST_EVENT_HANDLER( inserted, 15 ); + TEST_EVENT_HANDLER( changed, 15 ); + + hr = IMap_HSTRING_IInspectable_get_Size( map, &size ); + todo_wine ok( SUCCEEDED( hr ), "get_Size failed, got %#lx\n", hr ); + if (SUCCEEDED( hr )) ok( size == 15, "%u != 15\n", size ); + hr = IMap_HSTRING_IInspectable_Clear( map ); + todo_wine ok( SUCCEEDED( hr ), "Clear failed, got %#lx\n", hr ); + TEST_EVENT_HANDLER( reset, 1 ); + hr = IMap_HSTRING_IInspectable_get_Size( map, &size ); + todo_wine ok( SUCCEEDED( hr ), "get_Size failed, got %#lx\n", hr ); + if (SUCCEEDED( hr )) ok( size == 0, "%u != 0\n", size ); + + prev_size = 0; + TEST_MAP_VALUES; + + hr = IMap_HSTRING_IInspectable_QueryInterface( + map, &IID_IIterable_IKeyValuePair_HSTRING_IInspectable, (void **)&iterable ); + todo_wine ok( SUCCEEDED( hr ), "QueryInterface failed, got %#lx\n", hr ); + if (SUCCEEDED( hr )) + { + hr = IIterable_IKeyValuePair_HSTRING_IInspectable_First( iterable, &iterator ); + IIterable_IKeyValuePair_HSTRING_IInspectable_Release( iterable ); + ok( SUCCEEDED( hr ), "got %#lx\n", hr ); + + size = 15; + valid = 1; + while (valid) + { + + IKeyValuePair_HSTRING_IInspectable *kvpair; + HSTRING key; + IInspectable *value; + hr = IIterator_IKeyValuePair_HSTRING_IInspectable_get_Current( iterator, &kvpair ); + todo_wine ok( SUCCEEDED( hr ), "get_Current failed, got %#lx\n", hr ); + hr = IKeyValuePair_HSTRING_IInspectable_get_Key( kvpair, &key ); + todo_wine ok( SUCCEEDED( hr ), "get_Key failed, got %#lx\n", hr ); + WindowsDeleteString( key ); + hr = IKeyValuePair_HSTRING_IInspectable_get_Value( kvpair, &value ); + todo_wine ok( SUCCEEDED( hr ), "get_Value failed, got %#lx\n", hr ); + IInspectable_Release( value ); + hr = IIterator_IKeyValuePair_HSTRING_IInspectable_MoveNext( iterator, &valid ); + todo_wine ok( SUCCEEDED( hr ), "MoveNext failed, got %#lx\n", hr ); + size--; + } + todo_wine ok( size == 0, "%d != 0\n", size ); + hr = IIterator_IKeyValuePair_HSTRING_IInspectable_get_HasCurrent( iterator, &valid ); + todo_wine ok( SUCCEEDED( hr ), "get_HasCurrent failed, got %#lx\n", hr ); + if (SUCCEEDED( hr )) ok( !valid, "%d is non-zero\n", valid ); + IIterator_IKeyValuePair_HSTRING_IInspectable_Release( iterator ); + } + else + skip( "Could not obtain IIterable<IKeyValuePair<HSTRING, IInspectable *>> instance.\n"); + +#undef MAP_TEST +#define MAP_TEST(t, v, ct) \ + MAP_TEST_(PropertyType_##t, IPropertyValue_Get##t, IMap, map, STR(t), v, ct) + +#define MAP_TEST_( pt, pg, mi, m, k, v, ct ) \ + do \ + { \ + const static WCHAR *str = (k); \ + HSTRING key; \ + IInspectable *inspect; \ + IPropertyValue *value; \ + PropertyType type; \ + boolean exists; \ + ct data_expect = (v); \ + ct data_got; \ + hr = WindowsCreateString( str, wcslen( str ), &key ); \ + ok( SUCCEEDED( hr ), "got %#lx\n", hr ); \ + if (FAILED( hr )) break; \ + hr = mi##_HSTRING_IInspectable_HasKey( (m), key, &exists ); \ + todo_wine ok( SUCCEEDED( hr ), "HasKey failed, got %#lx\n", hr ); \ + todo_wine ok( exists, "expected map to have key %s\n", debugstr_w( str ) ); \ + hr = mi##_HSTRING_IInspectable_Lookup( (m), key, &inspect ); \ + WindowsDeleteString( key ); \ + todo_wine ok( SUCCEEDED( hr ), "Lookup failed, got %#lx\n", hr ); \ + if (FAILED( hr )) break; \ + hr = IInspectable_QueryInterface( inspect, &IID_IPropertyValue, (void **)&value ); \ + IInspectable_Release( inspect ); \ + ok( SUCCEEDED( hr ), "got %#lx\n", hr ); \ + IPropertyValue_get_Type( value, &type ); \ + ok( type == (pt), "%d != %d\n", type, (pt) ); \ + hr = (pg)( value, &data_got ); \ + ok( !memcmp( &data_expect, &data_got, sizeof( ct ) ), "Got unexpected value.\n" ); \ + IPropertyValue_Release( value ); \ + } while (0) + + TEST_MAP_VALUES; + +#undef MAP_TEST +#define MAP_TEST(t, v, ct) \ + MAP_TEST_(PropertyType_##t, IPropertyValue_Get##t, IMapView, map_view, STR(t), v, ct) + + hr = IMap_HSTRING_IInspectable_GetView( map, &map_view ); + todo_wine ok( SUCCEEDED( hr ), "GetView failed, got %#lx\n", hr ); + if (SUCCEEDED( hr )) + { + TEST_MAP_VALUES; + + hr = IMapView_HSTRING_IInspectable_QueryInterface( + map_view, &IID_IIterable_IKeyValuePair_HSTRING_IInspectable, (void **)&iterable ); + todo_wine ok( SUCCEEDED( hr ), "QuerInterface failed, got %#lx\n", hr ); + if (iterable) + { + hr = IIterable_IKeyValuePair_HSTRING_IInspectable_First( iterable, &iterator ); + IIterable_IKeyValuePair_HSTRING_IInspectable_Release( iterable ); + todo_wine ok( SUCCEEDED( hr ), "got %#lx\n", hr ); + size = 15; + valid = 1; + while (valid && iterator) + { + + IKeyValuePair_HSTRING_IInspectable *kvpair; + HSTRING key; + IInspectable *value; + hr = IIterator_IKeyValuePair_HSTRING_IInspectable_get_Current( iterator, &kvpair ); + todo_wine ok( SUCCEEDED( hr ), "get_Current failed, got %#lx\n", hr ); + if (FAILED( hr )) break; + hr = IKeyValuePair_HSTRING_IInspectable_get_Key( kvpair, &key ); + todo_wine ok( SUCCEEDED( hr ), "get_Key failed, got %#lx\n", hr ); + WindowsDeleteString( key ); + hr = IKeyValuePair_HSTRING_IInspectable_get_Value( kvpair, &value ); + todo_wine ok( SUCCEEDED( hr ), "get_Value failed, got %#lx\n", hr ); + IInspectable_Release( value ); + hr = IIterator_IKeyValuePair_HSTRING_IInspectable_MoveNext( iterator, &valid ); + todo_wine ok( SUCCEEDED( hr ), "MoveNext failed, got %#lx\n", hr ); + size--; + } + todo_wine ok( size == 0, "%d != 0\n", size ); + if (iterator) + { + hr = IIterator_IKeyValuePair_HSTRING_IInspectable_get_HasCurrent( iterator, &valid ); + todo_wine ok( SUCCEEDED( hr ), "got %#lx\n", hr ); + if (SUCCEEDED( hr )) ok( !valid, "%d is non-zero\n", valid ); + IIterator_IKeyValuePair_HSTRING_IInspectable_Release( iterator ); + } + } + + hr = IMapView_HSTRING_IInspectable_Split( map_view, &first_view, &second_view ); + todo_wine ok( SUCCEEDED( hr ), "Split failed, got %#lx\n", hr ); + if (SUCCEEDED( hr )) + ok( !first_view && !second_view, "Expected %p and %p to be NULL\n", first_view, + second_view ); + IMapView_HSTRING_IInspectable_Release( map_view ); + } + +#undef MAP_TEST +#undef MAP_TEST_ +#define MAP_TEST(t, v, ct) MAP_TEST_(STR(t)) +#define MAP_TEST_( k ) \ + do \ + { \ + const static WCHAR *str = ( k ); \ + HSTRING key; \ + IInspectable *inspect; \ + boolean exists; \ + hr = WindowsCreateString( str, wcslen( str ), &key ); \ + ok( SUCCEEDED( hr ), "got %#lx\n", hr ); \ + if (FAILED( hr )) break; \ + hr = IMap_HSTRING_IInspectable_Remove( map, key ); \ + todo_wine ok( SUCCEEDED( hr ), "Remove failed, got %#lx\n", hr ); \ + hr = IMap_HSTRING_IInspectable_HasKey( map, key, &exists ); \ + todo_wine ok( SUCCEEDED( hr ), "got %#lx\n", hr ); \ + if (SUCCEEDED( hr )) ok( !exists, "expected map to not have key %s\n", debugstr_w( str ) ); \ + hr = IMap_HSTRING_IInspectable_Lookup( map, key, &inspect ); \ + WindowsDeleteString( key ); \ + todo_wine ok( hr == E_BOUNDS, "got %#lx != %#lx\n", hr, E_BOUNDS ); \ + } while (0) + + TEST_MAP_VALUES; + TEST_EVENT_HANDLER( removed, 15 ); + hr = IMap_HSTRING_IInspectable_get_Size( map, &size ); + todo_wine ok( SUCCEEDED( hr ), "got %#lx\n", hr ); + if (SUCCEEDED( hr )) ok( size == 0, "%u != 0\n", size ); + + IObservableMap_HSTRING_IInspectable_Release( observable_map ); + IMap_HSTRING_IInspectable_Release( map ); + IPropertyValueStatics_Release( statics ); + RoUninitialize(); +} + +START_TEST(propertyset) +{ + test_IPropertySet(); +} diff --git a/dlls/wintypes/tests/wintypes.c b/dlls/wintypes/tests/wintypes.c index cb24dee77cf..4a70c184ef8 100644 --- a/dlls/wintypes/tests/wintypes.c +++ b/dlls/wintypes/tests/wintypes.c @@ -28,7 +28,9 @@ #include "rometadataresolution.h"
#define WIDL_using_Windows_Foundation +#define WIDL_using_Windows_Foundation_Collections #define WIDL_using_Windows_Foundation_Metadata +#include "windows.foundation.collections.h" #include "windows.foundation.metadata.h" #include "wintypes_test.h"
diff --git a/dlls/wintypes/tests/wintypes_test.idl b/dlls/wintypes/tests/wintypes_test.idl index 33cfbed210b..2180604d304 100644 --- a/dlls/wintypes/tests/wintypes_test.idl +++ b/dlls/wintypes/tests/wintypes_test.idl @@ -26,4 +26,14 @@ import "windows.foundation.idl";
declare { interface Windows.Foundation.IReference<HSTRING>; + interface Windows.Foundation.Collections.MapChangedEventHandler<HSTRING, IInspectable*>; } + +[ + uuid(7e860ccf-d9d0-4fbb-87a9-aa6c26f7f6ec) +] +interface IWinePropertySetChangedEventHandler : IUnknown + requires Windows.Foundation.Collections.MapChangedEventHandler<HSTRING, IInspectable *> { + [propget] HRESULT TimesInvoked([out, retval] ULONG *times); + HRESULT Reset(); +};