The object reference is actually held by ref_weak.
-- v6: geolocation: Use helpers to implement IWeakReference. windows.ui: Use helpers to implement IWeakReference.
From: Zhiyi Zhang zzhang@codeweavers.com
Return a newer IUISettings5 interface in factory_ActivateInstance(). Returning IUISettings3 is not wrong but it's not consistent now that IUISettings5 is available. --- dlls/windows.ui/uisettings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/windows.ui/uisettings.c b/dlls/windows.ui/uisettings.c index a2b59c46cdf..d5eae44b797 100644 --- a/dlls/windows.ui/uisettings.c +++ b/dlls/windows.ui/uisettings.c @@ -681,7 +681,7 @@ static HRESULT WINAPI factory_ActivateInstance( IActivationFactory *iface, IInsp impl->ref_strong = 1; impl->ref_weak = 1;
- *instance = (IInspectable *)&impl->IUISettings3_iface; + *instance = (IInspectable *)&impl->IUISettings5_iface; return S_OK; }
From: Zhiyi Zhang zzhang@codeweavers.com
This also fix a double free in uisettings_Release(). --- dlls/windows.ui/Makefile.in | 3 +- dlls/windows.ui/uisettings.c | 142 +++------------------------- dlls/windows.ui/weakref.c | 175 +++++++++++++++++++++++++++++++++++ dlls/windows.ui/weakref.h | 38 ++++++++ 4 files changed, 229 insertions(+), 129 deletions(-) create mode 100644 dlls/windows.ui/weakref.c create mode 100644 dlls/windows.ui/weakref.h
diff --git a/dlls/windows.ui/Makefile.in b/dlls/windows.ui/Makefile.in index 953991cafba..e88a40188b1 100644 --- a/dlls/windows.ui/Makefile.in +++ b/dlls/windows.ui/Makefile.in @@ -6,4 +6,5 @@ SOURCES = \ inputpane.c \ main.c \ uisettings.c \ - uiviewsettings.c + uiviewsettings.c \ + weakref.c diff --git a/dlls/windows.ui/uisettings.c b/dlls/windows.ui/uisettings.c index d5eae44b797..a58becf3555 100644 --- a/dlls/windows.ui/uisettings.c +++ b/dlls/windows.ui/uisettings.c @@ -19,7 +19,7 @@
#include "private.h" #include "initguid.h" -#include "weakreference.h" +#include "weakref.h"
#include "wine/debug.h"
@@ -34,10 +34,7 @@ struct uisettings IUISettings3 IUISettings3_iface; IUISettings4 IUISettings4_iface; IUISettings5 IUISettings5_iface; - IWeakReferenceSource IWeakReferenceSource_iface; - IWeakReference IWeakReference_iface; - LONG ref_strong; - LONG ref_weak; + struct weak_reference_source weak_reference_source; };
static inline struct uisettings *impl_from_IUISettings( IUISettings *iface ) @@ -78,7 +75,7 @@ static HRESULT WINAPI uisettings_QueryInterface( IUISettings *iface, REFIID iid, } else if (IsEqualGUID( iid, &IID_IWeakReferenceSource )) { - *out = &impl->IWeakReferenceSource_iface; + *out = &impl->weak_reference_source.IWeakReferenceSource_iface; }
if (!*out) @@ -94,20 +91,18 @@ static HRESULT WINAPI uisettings_QueryInterface( IUISettings *iface, REFIID iid, static ULONG WINAPI uisettings_AddRef( IUISettings *iface ) { struct uisettings *impl = impl_from_IUISettings( iface ); - ULONG ref = InterlockedIncrement( &impl->ref_strong ); + ULONG ref = weak_reference_strong_add_ref( &impl->weak_reference_source ); TRACE( "iface %p, ref %lu.\n", iface, ref ); - IWeakReference_AddRef( &impl->IWeakReference_iface ); return ref; }
static ULONG WINAPI uisettings_Release( IUISettings *iface ) { struct uisettings *impl = impl_from_IUISettings( iface ); - ULONG ref = InterlockedDecrement( &impl->ref_strong ); + ULONG ref = weak_reference_strong_release( &impl->weak_reference_source );
TRACE( "iface %p, ref %lu.\n", iface, ref );
- IWeakReference_Release( &impl->IWeakReference_iface ); if (!ref) free( impl ); return ref; } @@ -480,120 +475,6 @@ static const struct IUISettings5Vtbl uisettings5_vtbl = uisettings5_remove_AutoHideScrollBarsChanged, };
-static inline struct uisettings *impl_from_IWeakReference( IWeakReference *iface ) -{ - return CONTAINING_RECORD( iface, struct uisettings, IWeakReference_iface ); -} - -static HRESULT WINAPI weak_reference_QueryInterface( IWeakReference *iface, REFIID iid, void **out ) -{ - struct uisettings *impl = impl_from_IWeakReference( iface ); - - TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out ); - - if (IsEqualGUID( iid, &IID_IUnknown ) || - IsEqualGUID( iid, &IID_IWeakReference )) - { - *out = &impl->IWeakReference_iface; - IInspectable_AddRef( *out ); - return S_OK; - } - - FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid) ); - *out = NULL; - return E_NOINTERFACE; -} - -static ULONG WINAPI weak_reference_AddRef( IWeakReference *iface ) -{ - struct uisettings *impl = impl_from_IWeakReference( iface ); - ULONG ref = InterlockedIncrement( &impl->ref_weak ); - TRACE("iface %p increasing refcount to %lu.\n", iface, ref); - return ref; -} - -static ULONG WINAPI weak_reference_Release( IWeakReference *iface ) -{ - struct uisettings *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 uisettings *impl = impl_from_IWeakReference( iface ); - HRESULT hr; - LONG ref; - - TRACE( "iface %p, iid %s, out %p stub.\n", iface, debugstr_guid(iid), out ); - - *out = NULL; - - do - { - if (!(ref = ReadNoFence( &impl->ref_strong ))) - return S_OK; - } while (ref != InterlockedCompareExchange( &impl->ref_strong, ref + 1, ref )); - - hr = IUISettings_QueryInterface( &impl->IUISettings_iface, iid, (void **)out ); - InterlockedDecrement( &impl->ref_strong ); - return hr; -} - -static const struct IWeakReferenceVtbl weak_reference_vtbl = -{ - weak_reference_QueryInterface, - weak_reference_AddRef, - weak_reference_Release, - /* IWeakReference methods */ - weak_reference_Resolve, -}; - -static inline struct uisettings *impl_from_IWeakReferenceSource( IWeakReferenceSource *iface ) -{ - return CONTAINING_RECORD( iface, struct uisettings, IWeakReferenceSource_iface ); -} - -static HRESULT WINAPI weak_reference_source_QueryInterface( IWeakReferenceSource *iface, REFIID iid, void **out ) -{ - struct uisettings *impl = impl_from_IWeakReferenceSource( iface ); - return uisettings_QueryInterface( &impl->IUISettings_iface, iid, out ); -} - -static ULONG WINAPI weak_reference_source_AddRef( IWeakReferenceSource *iface ) -{ - struct uisettings *impl = impl_from_IWeakReferenceSource( iface ); - return uisettings_AddRef( &impl->IUISettings_iface ); -} - -static ULONG WINAPI weak_reference_source_Release( IWeakReferenceSource *iface ) -{ - struct uisettings *impl = impl_from_IWeakReferenceSource( iface ); - return uisettings_Release( &impl->IUISettings_iface ); -} - -static HRESULT WINAPI weak_reference_source_GetWeakReference( IWeakReferenceSource *iface, IWeakReference **ref ) -{ - struct uisettings *impl = impl_from_IWeakReferenceSource(iface); - - TRACE("iface %p, ref %p stub.\n", iface, ref); - - *ref = &impl->IWeakReference_iface; - IWeakReference_AddRef( *ref ); - return S_OK; -} - -static const struct IWeakReferenceSourceVtbl weak_reference_source_vtbl = -{ - weak_reference_source_QueryInterface, - weak_reference_source_AddRef, - weak_reference_source_Release, - /* IWeakReferenceSource methods */ - weak_reference_source_GetWeakReference, -}; - struct uisettings_statics { IActivationFactory IActivationFactory_iface; @@ -662,6 +543,7 @@ static HRESULT WINAPI factory_GetTrustLevel( IActivationFactory *iface, TrustLev static HRESULT WINAPI factory_ActivateInstance( IActivationFactory *iface, IInspectable **instance ) { struct uisettings *impl; + HRESULT hr;
TRACE( "iface %p, instance %p.\n", iface, instance );
@@ -676,10 +558,14 @@ static HRESULT WINAPI factory_ActivateInstance( IActivationFactory *iface, IInsp impl->IUISettings3_iface.lpVtbl = &uisettings3_vtbl; impl->IUISettings4_iface.lpVtbl = &uisettings4_vtbl; impl->IUISettings5_iface.lpVtbl = &uisettings5_vtbl; - impl->IWeakReferenceSource_iface.lpVtbl = &weak_reference_source_vtbl; - impl->IWeakReference_iface.lpVtbl = &weak_reference_vtbl; - impl->ref_strong = 1; - impl->ref_weak = 1; + + if (FAILED(hr = weak_reference_source_init( &impl->weak_reference_source, + (IUnknown *)&impl->IUISettings_iface ))) + { + *instance = NULL; + free( impl ); + return hr; + }
*instance = (IInspectable *)&impl->IUISettings5_iface; return S_OK; diff --git a/dlls/windows.ui/weakref.c b/dlls/windows.ui/weakref.c new file mode 100644 index 00000000000..6a10390dd4c --- /dev/null +++ b/dlls/windows.ui/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.ui/weakref.h b/dlls/windows.ui/weakref.h new file mode 100644 index 00000000000..7d4bc22b087 --- /dev/null +++ b/dlls/windows.ui/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 */
From: Zhiyi Zhang zzhang@codeweavers.com
--- dlls/geolocation/Makefile.in | 3 +- dlls/geolocation/main.c | 142 +++------------------------- dlls/geolocation/private.h | 1 - dlls/geolocation/weakref.c | 175 +++++++++++++++++++++++++++++++++++ dlls/geolocation/weakref.h | 38 ++++++++ 5 files changed, 230 insertions(+), 129 deletions(-) create mode 100644 dlls/geolocation/weakref.c create mode 100644 dlls/geolocation/weakref.h
diff --git a/dlls/geolocation/Makefile.in b/dlls/geolocation/Makefile.in index 283806d14bf..3afaae6d017 100644 --- a/dlls/geolocation/Makefile.in +++ b/dlls/geolocation/Makefile.in @@ -3,4 +3,5 @@ IMPORTS = combase uuid
SOURCES = \ classes.idl \ - main.c + main.c \ + weakref.c diff --git a/dlls/geolocation/main.c b/dlls/geolocation/main.c index 92c62c0feb7..b5f8ed0e130 100644 --- a/dlls/geolocation/main.c +++ b/dlls/geolocation/main.c @@ -19,6 +19,7 @@
#include "initguid.h" #include "private.h" +#include "weakref.h"
#include "wine/debug.h"
@@ -33,10 +34,7 @@ struct geolocator_statics struct geolocator { IGeolocator IGeolocator_iface; - IWeakReferenceSource IWeakReferenceSource_iface; - IWeakReference IWeakReference_iface; - LONG ref_public; - LONG ref_weak; + struct weak_reference_source weak_reference_source; };
static inline struct geolocator *impl_from_IGeolocator(IGeolocator *iface) @@ -62,8 +60,8 @@ static HRESULT WINAPI geolocator_QueryInterface(IGeolocator *iface, REFIID iid,
if (IsEqualGUID(iid, &IID_IWeakReferenceSource)) { - *out = &impl->IWeakReferenceSource_iface; - IInspectable_AddRef(*out); + *out = &impl->weak_reference_source.IWeakReferenceSource_iface; + IWeakReferenceSource_AddRef(*out); return S_OK; }
@@ -75,18 +73,17 @@ static HRESULT WINAPI geolocator_QueryInterface(IGeolocator *iface, REFIID iid, static ULONG WINAPI geolocator_AddRef(IGeolocator *iface) { struct geolocator *impl = impl_from_IGeolocator(iface); - ULONG ref = InterlockedIncrement(&impl->ref_public); + ULONG ref = weak_reference_strong_add_ref(&impl->weak_reference_source); TRACE("iface %p increasing refcount to %lu.\n", iface, ref); - IWeakReference_AddRef(&impl->IWeakReference_iface); return ref; }
static ULONG WINAPI geolocator_Release(IGeolocator *iface) { struct geolocator *impl = impl_from_IGeolocator(iface); - ULONG ref = InterlockedDecrement(&impl->ref_public); + ULONG ref = weak_reference_strong_release(&impl->weak_reference_source); TRACE("iface %p decreasing refcount to %lu.\n", iface, ref); - IWeakReference_Release(&impl->IWeakReference_iface); + if (!ref) free( impl ); return ref; }
@@ -211,119 +208,6 @@ static const struct IGeolocatorVtbl geolocator_vtbl = geolocator_remove_StatusChanged, };
-static inline struct geolocator *impl_from_IWeakReference(IWeakReference *iface) -{ - return CONTAINING_RECORD(iface, struct geolocator, IWeakReference_iface); -} - -static HRESULT WINAPI weak_reference_QueryInterface(IWeakReference *iface, REFIID iid, void **out) -{ - struct geolocator *impl = impl_from_IWeakReference(iface); - - TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); - - if (IsEqualGUID(iid, &IID_IUnknown) || - IsEqualGUID(iid, &IID_IWeakReference)) - { - *out = &impl->IWeakReference_iface; - IInspectable_AddRef(*out); - return S_OK; - } - - FIXME("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); - *out = NULL; - return E_NOINTERFACE; -} - -static ULONG WINAPI weak_reference_AddRef(IWeakReference *iface) -{ - struct geolocator *impl = impl_from_IWeakReference(iface); - ULONG ref = InterlockedIncrement(&impl->ref_weak); - TRACE("iface %p increasing refcount to %lu.\n", iface, ref); - return ref; -} - -static ULONG WINAPI weak_reference_Release(IWeakReference *iface) -{ - struct geolocator *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 geolocator *impl = impl_from_IWeakReference(iface); - HRESULT hr; - LONG ref; - - TRACE("iface %p, iid %s, out %p stub.\n", iface, debugstr_guid(iid), out); - - *out = NULL; - - do - { - if (!(ref = ReadNoFence(&impl->ref_public))) - return S_OK; - } while (ref != InterlockedCompareExchange(&impl->ref_public, ref + 1, ref)); - - hr = IGeolocator_QueryInterface(&impl->IGeolocator_iface, iid, (void **)out); - InterlockedDecrement(&impl->ref_public); - return hr; -} - -static const struct IWeakReferenceVtbl weak_reference_vtbl = -{ - weak_reference_QueryInterface, - weak_reference_AddRef, - weak_reference_Release, - /* IWeakReference methods */ - weak_reference_Resolve, -}; - -static inline struct geolocator *impl_from_IWeakReferenceSource(IWeakReferenceSource *iface) -{ - return CONTAINING_RECORD(iface, struct geolocator, IWeakReferenceSource_iface); -} - -static HRESULT WINAPI weak_reference_source_QueryInterface(IWeakReferenceSource *iface, REFIID iid, void **out) -{ - struct geolocator *impl = impl_from_IWeakReferenceSource(iface); - return geolocator_QueryInterface(&impl->IGeolocator_iface, iid, out); -} - -static ULONG WINAPI weak_reference_source_AddRef(IWeakReferenceSource *iface) -{ - struct geolocator *impl = impl_from_IWeakReferenceSource(iface); - return geolocator_AddRef(&impl->IGeolocator_iface); -} - -static ULONG WINAPI weak_reference_source_Release(IWeakReferenceSource *iface) -{ - struct geolocator *impl = impl_from_IWeakReferenceSource(iface); - return geolocator_Release(&impl->IGeolocator_iface); -} - -static HRESULT WINAPI weak_reference_source_GetWeakReference(IWeakReferenceSource *iface, IWeakReference **ref) -{ - struct geolocator *impl = impl_from_IWeakReferenceSource(iface); - - TRACE("iface %p, ref %p stub.\n", iface, ref); - *ref = &impl->IWeakReference_iface; - IWeakReference_AddRef(*ref); - return S_OK; -} - -static const struct IWeakReferenceSourceVtbl weak_reference_source_vtbl = -{ - weak_reference_source_QueryInterface, - weak_reference_source_AddRef, - weak_reference_source_Release, - /* IWeakReferenceSource methods */ - weak_reference_source_GetWeakReference, -}; - static inline struct geolocator_statics *impl_from_IActivationFactory(IActivationFactory *iface) { return CONTAINING_RECORD(iface, struct geolocator_statics, IActivationFactory_iface); @@ -389,6 +273,7 @@ static const struct IActivationFactoryVtbl factory_vtbl; static HRESULT WINAPI factory_ActivateInstance(IActivationFactory *iface, IInspectable **instance) { struct geolocator *impl; + HRESULT hr;
TRACE("iface %p, instance %p.\n", iface, instance);
@@ -399,10 +284,13 @@ static HRESULT WINAPI factory_ActivateInstance(IActivationFactory *iface, IInspe }
impl->IGeolocator_iface.lpVtbl = &geolocator_vtbl; - impl->IWeakReferenceSource_iface.lpVtbl = &weak_reference_source_vtbl; - impl->IWeakReference_iface.lpVtbl = &weak_reference_vtbl; - impl->ref_public = 1; - impl->ref_weak = 1; + if (FAILED(hr = weak_reference_source_init( &impl->weak_reference_source, + (IUnknown *)&impl->IGeolocator_iface ))) + { + *instance = NULL; + free( impl ); + return hr; + }
*instance = (IInspectable *)&impl->IGeolocator_iface; return S_OK; diff --git a/dlls/geolocation/private.h b/dlls/geolocation/private.h index a188b5dacf3..44060ae21b0 100644 --- a/dlls/geolocation/private.h +++ b/dlls/geolocation/private.h @@ -28,7 +28,6 @@ #include "winstring.h"
#include "activation.h" -#include "weakreference.h"
#define WIDL_using_Windows_Foundation #define WIDL_using_Windows_Foundation_Collections diff --git a/dlls/geolocation/weakref.c b/dlls/geolocation/weakref.c new file mode 100644 index 00000000000..6a10390dd4c --- /dev/null +++ b/dlls/geolocation/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/geolocation/weakref.h b/dlls/geolocation/weakref.h new file mode 100644 index 00000000000..7d4bc22b087 --- /dev/null +++ b/dlls/geolocation/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 */
On Fri May 23 06:50:04 2025 +0000, Zhiyi Zhang wrote:
changed this line in [version 6 of the diff](/wine/wine/-/merge_requests/8078/diffs?diff_id=180100&start_sha=01a26ac47bf54de26f9dd954eb330858d69067c8#c768d923584588db48bc05b028c56ebad4850e35_30_36)
Thanks. I submitted a new version with your suggestions. I kept `IUnknown *object` in `struct weak_reference` because weak_reference_Resolve() needs access to the managed object.
On Fri May 23 07:06:20 2025 +0000, Zhiyi Zhang wrote:
Thanks. I submitted a new version with your suggestions. I kept `IUnknown *object` in `struct weak_reference` because weak_reference_Resolve() needs access to the managed object.
Oh yes, I did mean to duplicate it but we can indeed use it through the weak reference like you did instead, thanks!
This merge request was approved by Rémi Bernon.