From: Vibhav Pant vibhavp@gmail.com
--- dlls/windows.devices.enumeration/Makefile.in | 3 +- dlls/windows.devices.enumeration/main.c | 20 +- dlls/windows.devices.enumeration/private.h | 1 + .../tests/devices.c | 28 ++- dlls/windows.devices.enumeration/weakref.c | 175 ++++++++++++++++++ dlls/windows.devices.enumeration/weakref.h | 38 ++++ 6 files changed, 244 insertions(+), 21 deletions(-) create mode 100644 dlls/windows.devices.enumeration/weakref.c create mode 100644 dlls/windows.devices.enumeration/weakref.h
diff --git a/dlls/windows.devices.enumeration/Makefile.in b/dlls/windows.devices.enumeration/Makefile.in index 853c1303efa..c81a88d2ec7 100644 --- a/dlls/windows.devices.enumeration/Makefile.in +++ b/dlls/windows.devices.enumeration/Makefile.in @@ -9,4 +9,5 @@ SOURCES = \ event_handlers.c \ information.c \ main.c \ - vector.c + vector.c \ + weakref.c diff --git a/dlls/windows.devices.enumeration/main.c b/dlls/windows.devices.enumeration/main.c index 2cd727a4149..693e8f5103c 100644 --- a/dlls/windows.devices.enumeration/main.c +++ b/dlls/windows.devices.enumeration/main.c @@ -83,7 +83,7 @@ static HRESULT enum_device_information( enum_device_information_cb callback, voi struct device_watcher { IDeviceWatcher IDeviceWatcher_iface; - LONG ref; + struct weak_reference_source weak_reference_source;
struct list added_handlers; struct list enumerated_handlers; @@ -114,6 +114,13 @@ static HRESULT WINAPI device_watcher_QueryInterface( IDeviceWatcher *iface, REFI return S_OK; }
+ if (IsEqualGUID( iid, &IID_IWeakReferenceSource )) + { + *out = &impl->weak_reference_source.IWeakReferenceSource_iface; + IWeakReferenceSource_AddRef(*out); + return S_OK; + } + FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); *out = NULL; return E_NOINTERFACE; @@ -122,7 +129,7 @@ static HRESULT WINAPI device_watcher_QueryInterface( IDeviceWatcher *iface, REFI static ULONG WINAPI device_watcher_AddRef( IDeviceWatcher *iface ) { struct device_watcher *impl = impl_from_IDeviceWatcher( iface ); - ULONG ref = InterlockedIncrement( &impl->ref ); + ULONG ref = weak_reference_strong_add_ref( &impl->weak_reference_source ); TRACE( "iface %p, ref %lu.\n", iface, ref ); return ref; } @@ -130,7 +137,7 @@ static ULONG WINAPI device_watcher_AddRef( IDeviceWatcher *iface ) static ULONG WINAPI device_watcher_Release( IDeviceWatcher *iface ) { struct device_watcher *impl = impl_from_IDeviceWatcher( iface ); - ULONG ref = InterlockedDecrement( &impl->ref ); + ULONG ref = weak_reference_strong_release( &impl->weak_reference_source ); TRACE( "iface %p, ref %lu.\n", iface, ref );
if (!ref) @@ -386,10 +393,15 @@ static HRESULT device_watcher_create( HSTRING filter, IDeviceWatcher **out )
if (!(impl = calloc( 1, sizeof(*impl) ))) return E_OUTOFMEMORY;
- impl->ref = 1; impl->IDeviceWatcher_iface.lpVtbl = &device_watcher_vtbl; + if (FAILED(hr = weak_reference_source_init( &impl->weak_reference_source, (IUnknown *)&impl->IDeviceWatcher_iface ))) + { + free( impl ); + return hr; + } if (FAILED(hr = WindowsDuplicateString( filter, &impl->filter ))) { + weak_reference_strong_release( &impl->weak_reference_source ); free( impl ); return hr; } diff --git a/dlls/windows.devices.enumeration/private.h b/dlls/windows.devices.enumeration/private.h index e0a8e46f8b5..ad15b7916ca 100644 --- a/dlls/windows.devices.enumeration/private.h +++ b/dlls/windows.devices.enumeration/private.h @@ -40,6 +40,7 @@ #include "wine/list.h"
#include "async_private.h" +#include "weakref.h"
struct vector_iids { diff --git a/dlls/windows.devices.enumeration/tests/devices.c b/dlls/windows.devices.enumeration/tests/devices.c index a0b8cfd043b..529215df0f2 100644 --- a/dlls/windows.devices.enumeration/tests/devices.c +++ b/dlls/windows.devices.enumeration/tests/devices.c @@ -341,6 +341,8 @@ static void test_DeviceInformation( void ) IVectorView_DeviceInformation *info_collection = NULL; IDeviceInformation *info; IWeakReferenceSource *weak_src; + IWeakReference *weak_ref; + IDeviceWatcher *watcher; UINT32 i, size; HSTRING str; HRESULT hr; @@ -388,22 +390,16 @@ static void test_DeviceInformation( void ) check_interface( device_watcher, &IID_IDeviceWatcher, TRUE );
hr = IDeviceWatcher_QueryInterface( device_watcher, &IID_IWeakReferenceSource, (void **)&weak_src ); - todo_wine ok( hr == S_OK, "got hr %#lx\n", hr ); - if (SUCCEEDED( hr )) - { - IWeakReference *weak_ref; - IDeviceWatcher *watcher; - - check_interface( weak_src, &IID_IAgileObject, TRUE ); - hr = IWeakReferenceSource_GetWeakReference( weak_src, &weak_ref ); - IWeakReferenceSource_Release( weak_src ); - ok( hr == S_OK, "got hr %#lx\n", hr ); - hr = IWeakReference_Resolve( weak_ref, &IID_IDeviceWatcher, (IInspectable **)&watcher ); - IWeakReference_Release( weak_ref ); - ok( hr == S_OK, "got hr %#lx\n", hr ); - ref = IDeviceWatcher_Release( watcher ); - ok( ref == 1, "got ref %lu\n", ref ); - } + ok( hr == S_OK, "got hr %#lx\n", hr ); + check_interface( weak_src, &IID_IAgileObject, TRUE ); + hr = IWeakReferenceSource_GetWeakReference( weak_src, &weak_ref ); + IWeakReferenceSource_Release( weak_src ); + ok( hr == S_OK, "got hr %#lx\n", hr ); + hr = IWeakReference_Resolve( weak_ref, &IID_IDeviceWatcher, (IInspectable **)&watcher ); + IWeakReference_Release( weak_ref ); + ok( hr == S_OK, "got hr %#lx\n", hr ); + ref = IDeviceWatcher_Release( watcher ); + ok( ref == 1, "got ref %lu\n", ref );
hr = IDeviceWatcher_add_Added( device_watcher, (void *)&added_handler.ITypedEventHandler_DeviceWatcher_IInspectable_iface, &added_token ); ok( hr == S_OK, "got hr %#lx\n", hr ); diff --git a/dlls/windows.devices.enumeration/weakref.c b/dlls/windows.devices.enumeration/weakref.c new file mode 100644 index 00000000000..6a10390dd4c --- /dev/null +++ b/dlls/windows.devices.enumeration/weakref.c @@ -0,0 +1,175 @@ +/* WinRT weak reference helpers + * + * Copyright 2025 Zhiyi Zhang 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 "weakref.h" + +/* The control block is contained in struct weak_reference so that we don't have to allocate a + * separate struct for it */ +struct weak_reference +{ + IWeakReference IWeakReference_iface; + IUnknown *object; + /* control block */ + LONG ref_strong; + LONG ref_weak; +}; + +static inline struct weak_reference *impl_from_IWeakReference( IWeakReference *iface ) +{ + return CONTAINING_RECORD(iface, struct weak_reference, IWeakReference_iface); +} + +static HRESULT WINAPI weak_reference_QueryInterface( IWeakReference *iface, REFIID iid, void **out ) +{ + struct weak_reference *impl = impl_from_IWeakReference( iface ); + + if (IsEqualGUID( iid, &IID_IUnknown ) || IsEqualGUID( iid, &IID_IWeakReference )) + { + *out = &impl->IWeakReference_iface; + IWeakReference_AddRef( *out ); + return S_OK; + } + + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI weak_reference_AddRef( IWeakReference *iface ) +{ + struct weak_reference *impl = impl_from_IWeakReference( iface ); + return InterlockedIncrement( &impl->ref_weak ); +} + +static ULONG WINAPI weak_reference_Release( IWeakReference *iface ) +{ + struct weak_reference *impl = impl_from_IWeakReference( iface ); + ULONG ref = InterlockedDecrement( &impl->ref_weak ); + + if (!ref) + free( impl ); + return ref; +} + +static HRESULT WINAPI weak_reference_Resolve( IWeakReference *iface, REFIID iid, IInspectable **out ) +{ + struct weak_reference *impl = impl_from_IWeakReference( iface ); + HRESULT hr; + LONG ref; + + *out = NULL; + do + { + if (!(ref = ReadNoFence( &impl->ref_strong ))) + return S_OK; + } while (ref != InterlockedCompareExchange( &impl->ref_strong, ref + 1, ref )); + + hr = IUnknown_QueryInterface( impl->object, iid, (void **)out ); + IUnknown_Release( impl->object ); + return hr; +} + +static const struct IWeakReferenceVtbl weak_reference_vtbl = +{ + weak_reference_QueryInterface, + weak_reference_AddRef, + weak_reference_Release, + weak_reference_Resolve, +}; + +static inline struct weak_reference_source *impl_from_IWeakReferenceSource( IWeakReferenceSource *iface ) +{ + return CONTAINING_RECORD(iface, struct weak_reference_source, IWeakReferenceSource_iface); +} + +static HRESULT WINAPI weak_reference_source_QueryInterface( IWeakReferenceSource *iface, REFIID iid, void **out ) +{ + struct weak_reference_source *weak_reference_source = impl_from_IWeakReferenceSource( iface ); + struct weak_reference *weak_reference = impl_from_IWeakReference( weak_reference_source->weak_reference ); + return IUnknown_QueryInterface( weak_reference->object, iid, out ); +} + +static ULONG WINAPI weak_reference_source_AddRef( IWeakReferenceSource *iface ) +{ + struct weak_reference_source *weak_reference_source = impl_from_IWeakReferenceSource( iface ); + struct weak_reference *weak_reference = impl_from_IWeakReference( weak_reference_source->weak_reference ); + return IUnknown_AddRef( weak_reference->object ); +} + +static ULONG WINAPI weak_reference_source_Release( IWeakReferenceSource *iface ) +{ + struct weak_reference_source *weak_reference_source = impl_from_IWeakReferenceSource( iface ); + struct weak_reference *weak_reference = impl_from_IWeakReference( weak_reference_source->weak_reference ); + return IUnknown_Release( weak_reference->object ); +} + +static HRESULT WINAPI weak_reference_source_GetWeakReference( IWeakReferenceSource *iface, + IWeakReference **weak_reference ) +{ + struct weak_reference_source *impl = impl_from_IWeakReferenceSource( iface ); + + *weak_reference = impl->weak_reference; + IWeakReference_AddRef( *weak_reference ); + return S_OK; +} + +static const struct IWeakReferenceSourceVtbl weak_reference_source_vtbl = +{ + weak_reference_source_QueryInterface, + weak_reference_source_AddRef, + weak_reference_source_Release, + weak_reference_source_GetWeakReference, +}; + +static HRESULT weak_reference_create( IUnknown *object, IWeakReference **out ) +{ + struct weak_reference *weak_reference; + + if (!(weak_reference = calloc( 1, sizeof(*weak_reference) ))) + return E_OUTOFMEMORY; + + weak_reference->IWeakReference_iface.lpVtbl = &weak_reference_vtbl; + weak_reference->ref_strong = 1; + weak_reference->ref_weak = 1; + weak_reference->object = object; + *out = &weak_reference->IWeakReference_iface; + return S_OK; +} + +HRESULT weak_reference_source_init( struct weak_reference_source *source, IUnknown *object ) +{ + source->IWeakReferenceSource_iface.lpVtbl = &weak_reference_source_vtbl; + return weak_reference_create( object, &source->weak_reference ); +} + +ULONG weak_reference_strong_add_ref( struct weak_reference_source *source ) +{ + struct weak_reference *impl = impl_from_IWeakReference( source->weak_reference ); + return InterlockedIncrement( &impl->ref_strong ); +} + +ULONG weak_reference_strong_release( struct weak_reference_source *source ) +{ + struct weak_reference *impl = impl_from_IWeakReference( source->weak_reference ); + ULONG ref = InterlockedDecrement( &impl->ref_strong ); + + if (!ref) + IWeakReference_Release( source->weak_reference ); + return ref; +} diff --git a/dlls/windows.devices.enumeration/weakref.h b/dlls/windows.devices.enumeration/weakref.h new file mode 100644 index 00000000000..7d4bc22b087 --- /dev/null +++ b/dlls/windows.devices.enumeration/weakref.h @@ -0,0 +1,38 @@ +/* WinRT weak reference helpers + * + * Copyright 2025 Zhiyi Zhang 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 + */ + +#ifndef __WINE_WEAKREF_H +#define __WINE_WEAKREF_H + +#include "weakreference.h" + +struct weak_reference_source +{ + IWeakReferenceSource IWeakReferenceSource_iface; + IWeakReference *weak_reference; +}; + +/* Initialize a IWeakReferenceSource with the object to manage */ +HRESULT weak_reference_source_init( struct weak_reference_source *source, IUnknown *object ); +/* Add a strong reference to the managed object */ +ULONG weak_reference_strong_add_ref( struct weak_reference_source *source ); +/* Release a strong reference to the managed object */ +ULONG weak_reference_strong_release( struct weak_reference_source *source ); + +#endif /* __WINE_WEAKREF_H */