The object reference is actually held by ref_weak.
-- v3: geolocation: Use DEFINE_WEAKREF to implement IWeakReference. windows.ui: Use DEFINE_WEAKREF 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/private.h | 127 ++++++++++++++++++++++++++++++ dlls/windows.ui/uisettings.c | 148 ++++++----------------------------- 2 files changed, 150 insertions(+), 125 deletions(-)
diff --git a/dlls/windows.ui/private.h b/dlls/windows.ui/private.h index 6e611e5d5d3..e8e274111ca 100644 --- a/dlls/windows.ui/private.h +++ b/dlls/windows.ui/private.h @@ -28,6 +28,7 @@ #include "winstring.h"
#include "activation.h" +#include "weakreference.h"
#define WIDL_using_Windows_Foundation #include "windows.foundation.h" @@ -78,4 +79,130 @@ extern IActivationFactory *inputpane_factory; #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 )
+/* WeakReference helper + * + * How to add IWeakReferenceSource and IWeakReference support to an existing COM object: + * 1. Add DEFINE_WEAKREF(pfx, iface_type, struct impl_type); + * 2. Add "IWeakReferenceSource IWeakReferenceSource_iface;" and "struct weakref *weakref;" to the + * object struct definition. + * 3. Support IID_IWeakReferenceSource in object_QueryInterface(). + * 4. Replace ALL object->refcount usage with object->weakref->ref_strong. + * 5. Allocate a struct weakref in the object initialisation function and add the following + * ``` + * object->IWeakReferenceSource_iface.lpVtbl = &pfx##_weakref_source_vtbl; + * weakref->IWeakReference_iface.lpVtbl = &pfx##_weakref_vtbl; + * weakref->ref_strong = 1; + * weakref->ref_weak = 1; + * weakref->object = (IUnknown *)&object->iface_type##_iface; + * object->weakref = weakref; + * ``` + * 6. Call "IWeakReference_Release( &impl->weakref->IWeakReference_iface );" in object_Release() + * when object->weakref->ref_strong reaches zero. + */ + +/* The control block is contained in struct weakref so that we don't have to allocate a separate + * struct for it */ +struct weakref +{ + IWeakReference IWeakReference_iface; + IUnknown *object; + /* control block */ + LONG ref_strong; + LONG ref_weak; +}; + +#define DEFINE_WEAKREF(pfx, iface_type, impl_type) \ +static inline struct weakref *pfx##_impl_from_IWeakReference(IWeakReference *iface) \ +{ \ + return CONTAINING_RECORD(iface, struct weakref, IWeakReference_iface); \ +} \ +static HRESULT WINAPI pfx##_weakref_QueryInterface(IWeakReference *iface, REFIID iid, void **out) \ +{ \ + struct weakref *impl = pfx##_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; \ + IWeakReference_AddRef(*out); \ + return S_OK; \ + } \ + FIXME("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); \ + *out = NULL; \ + return E_NOINTERFACE; \ +} \ +static ULONG WINAPI pfx##_weakref_AddRef(IWeakReference *iface) \ +{ \ + struct weakref *impl = pfx##_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 pfx##_weakref_Release(IWeakReference *iface) \ +{ \ + struct weakref *impl = pfx##_impl_from_IWeakReference(iface); \ + ULONG ref = InterlockedDecrement(&impl->ref_weak); \ + TRACE("iface %p, ref %lu.\n", iface, ref); \ + if (!ref) free(impl); \ + return ref; \ +} \ +static HRESULT WINAPI pfx##_weakref_Resolve(IWeakReference *iface, REFIID iid, IInspectable **out) \ +{ \ + struct weakref *impl = pfx##_impl_from_IWeakReference(iface); \ + HRESULT hr; \ + LONG ref; \ + TRACE("iface %p, iid %s, out %p.\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 = IUnknown_QueryInterface(impl->object, iid, (void **)out); \ + IUnknown_Release(impl->object); \ + return hr; \ +} \ +static const struct IWeakReferenceVtbl pfx##_weakref_vtbl = \ +{ \ + pfx##_weakref_QueryInterface, \ + pfx##_weakref_AddRef, \ + pfx##_weakref_Release, \ + pfx##_weakref_Resolve, \ +}; \ +static inline impl_type *pfx##_impl_from_IWeakReferenceSource(IWeakReferenceSource *iface) \ +{ \ + return CONTAINING_RECORD(iface, impl_type, IWeakReferenceSource_iface); \ +} \ +static HRESULT WINAPI pfx##_weakref_source_QueryInterface(IWeakReferenceSource *iface, \ + REFIID iid, void **out) \ +{ \ + impl_type *impl = pfx##_impl_from_IWeakReferenceSource(iface); \ + return pfx##_QueryInterface(&impl->iface_type##_iface, iid, out); \ +} \ +static ULONG WINAPI pfx##_weakref_source_AddRef(IWeakReferenceSource *iface) \ +{ \ + impl_type *impl = pfx##_impl_from_IWeakReferenceSource(iface); \ + return pfx##_AddRef(&impl->iface_type##_iface); \ +} \ +static ULONG WINAPI pfx##_weakref_source_Release(IWeakReferenceSource *iface) \ +{ \ + impl_type *impl = pfx##_impl_from_IWeakReferenceSource(iface); \ + return pfx##_Release(&impl->iface_type##_iface); \ +} \ +static HRESULT WINAPI pfx##_weakref_source_GetWeakReference(IWeakReferenceSource *iface, \ + IWeakReference **ref) \ +{ \ + impl_type *impl = pfx##_impl_from_IWeakReferenceSource(iface); \ + TRACE("iface %p, ref %p stub.\n", iface, ref); \ + *ref = &impl->weakref->IWeakReference_iface; \ + IWeakReference_AddRef(*ref); \ + return S_OK; \ +} \ +static const struct IWeakReferenceSourceVtbl pfx##_weakref_source_vtbl = \ +{ \ + pfx##_weakref_source_QueryInterface, \ + pfx##_weakref_source_AddRef, \ + pfx##_weakref_source_Release, \ + pfx##_weakref_source_GetWeakReference, \ +}; + #endif diff --git a/dlls/windows.ui/uisettings.c b/dlls/windows.ui/uisettings.c index d5eae44b797..720e5add4cf 100644 --- a/dlls/windows.ui/uisettings.c +++ b/dlls/windows.ui/uisettings.c @@ -35,9 +35,7 @@ struct uisettings IUISettings4 IUISettings4_iface; IUISettings5 IUISettings5_iface; IWeakReferenceSource IWeakReferenceSource_iface; - IWeakReference IWeakReference_iface; - LONG ref_strong; - LONG ref_weak; + struct weakref *weakref; };
static inline struct uisettings *impl_from_IUISettings( IUISettings *iface ) @@ -94,21 +92,23 @@ 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 = InterlockedIncrement( &impl->weakref->ref_strong ); 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 = InterlockedDecrement( &impl->weakref->ref_strong );
TRACE( "iface %p, ref %lu.\n", iface, ref );
- IWeakReference_Release( &impl->IWeakReference_iface ); - if (!ref) free( impl ); + if (!ref) + { + IWeakReference_Release( &impl->weakref->IWeakReference_iface ); + free( impl ); + } return ref; }
@@ -480,119 +480,7 @@ 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, -}; +DEFINE_WEAKREF(uisettings, IUISettings, struct uisettings);
struct uisettings_statics { @@ -662,6 +550,7 @@ static HRESULT WINAPI factory_GetTrustLevel( IActivationFactory *iface, TrustLev static HRESULT WINAPI factory_ActivateInstance( IActivationFactory *iface, IInspectable **instance ) { struct uisettings *impl; + struct weakref *weakref;
TRACE( "iface %p, instance %p.\n", iface, instance );
@@ -671,15 +560,24 @@ static HRESULT WINAPI factory_ActivateInstance( IActivationFactory *iface, IInsp return E_OUTOFMEMORY; }
+ if (!(weakref = calloc( 1, sizeof(*weakref) ))) + { + *instance = NULL; + free( impl ); + return E_OUTOFMEMORY; + } + impl->IUISettings_iface.lpVtbl = &uisettings_vtbl; impl->IUISettings2_iface.lpVtbl = &uisettings2_vtbl; 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; + impl->IWeakReferenceSource_iface.lpVtbl = &uisettings_weakref_source_vtbl; + weakref->IWeakReference_iface.lpVtbl = &uisettings_weakref_vtbl; + weakref->ref_strong = 1; + weakref->ref_weak = 1; + weakref->object = (IUnknown *)&impl->IUISettings5_iface; + impl->weakref = weakref;
*instance = (IInspectable *)&impl->IUISettings5_iface; return S_OK;
From: Zhiyi Zhang zzhang@codeweavers.com
--- dlls/geolocation/main.c | 145 ++++++------------------------------- dlls/geolocation/private.h | 126 ++++++++++++++++++++++++++++++++ 2 files changed, 149 insertions(+), 122 deletions(-)
diff --git a/dlls/geolocation/main.c b/dlls/geolocation/main.c index 92c62c0feb7..7adacebc8fd 100644 --- a/dlls/geolocation/main.c +++ b/dlls/geolocation/main.c @@ -35,8 +35,7 @@ struct geolocator IGeolocator IGeolocator_iface; IWeakReferenceSource IWeakReferenceSource_iface; IWeakReference IWeakReference_iface; - LONG ref_public; - LONG ref_weak; + struct weakref *weakref; };
static inline struct geolocator *impl_from_IGeolocator(IGeolocator *iface) @@ -75,18 +74,21 @@ 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 = InterlockedIncrement(&impl->weakref->ref_strong); 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 = InterlockedDecrement(&impl->weakref->ref_strong); TRACE("iface %p decreasing refcount to %lu.\n", iface, ref); - IWeakReference_Release(&impl->IWeakReference_iface); + if (!ref) + { + IWeakReference_Release(&impl->weakref->IWeakReference_iface); + free(impl); + } return ref; }
@@ -211,118 +213,7 @@ 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, -}; +DEFINE_WEAKREF(geolocator, IGeolocator, struct geolocator);
static inline struct geolocator_statics *impl_from_IActivationFactory(IActivationFactory *iface) { @@ -388,6 +279,7 @@ static const struct IActivationFactoryVtbl factory_vtbl;
static HRESULT WINAPI factory_ActivateInstance(IActivationFactory *iface, IInspectable **instance) { + struct weakref *weakref; struct geolocator *impl;
TRACE("iface %p, instance %p.\n", iface, instance); @@ -398,11 +290,20 @@ static HRESULT WINAPI factory_ActivateInstance(IActivationFactory *iface, IInspe return E_OUTOFMEMORY; }
+ if (!(weakref = calloc(1, sizeof(*weakref)))) + { + *instance = NULL; + free(impl); + return E_OUTOFMEMORY; + } + 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; + impl->IWeakReferenceSource_iface.lpVtbl = &geolocator_weakref_source_vtbl; + weakref->IWeakReference_iface.lpVtbl = &geolocator_weakref_vtbl; + weakref->ref_strong = 1; + weakref->ref_weak = 1; + weakref->object = (IUnknown *)&impl->IGeolocator_iface; + impl->weakref = weakref;
*instance = (IInspectable *)&impl->IGeolocator_iface; return S_OK; diff --git a/dlls/geolocation/private.h b/dlls/geolocation/private.h index a188b5dacf3..401bf60a291 100644 --- a/dlls/geolocation/private.h +++ b/dlls/geolocation/private.h @@ -36,4 +36,130 @@ #define WIDL_using_Windows_Devices_Geolocation #include "windows.devices.geolocation.h"
+/* WeakReference helper + * + * How to add IWeakReferenceSource and IWeakReference support to an existing COM object: + * 1. Add DEFINE_WEAKREF(pfx, iface_type, struct impl_type); + * 2. Add "IWeakReferenceSource IWeakReferenceSource_iface;" and "struct weakref *weakref;" to the + * object struct definition. + * 3. Support IID_IWeakReferenceSource in object_QueryInterface(). + * 4. Replace ALL object->refcount usage with object->weakref->ref_strong. + * 5. Allocate a struct weakref in the object initialisation function and add the following + * ``` + * object->IWeakReferenceSource_iface.lpVtbl = &pfx##_weakref_source_vtbl; + * weakref->IWeakReference_iface.lpVtbl = &pfx##_weakref_vtbl; + * weakref->ref_strong = 1; + * weakref->ref_weak = 1; + * weakref->object = (IUnknown *)&object->iface_type##_iface; + * object->weakref = weakref; + * ``` + * 6. Call "IWeakReference_Release( &impl->weakref->IWeakReference_iface );" in object_Release() + * when object->weakref->ref_strong reaches zero. + */ + +/* The control block is contained in struct weakref so that we don't have to allocate a separate + * struct for it */ +struct weakref +{ + IWeakReference IWeakReference_iface; + IUnknown *object; + /* control block */ + LONG ref_strong; + LONG ref_weak; +}; + +#define DEFINE_WEAKREF(pfx, iface_type, impl_type) \ +static inline struct weakref *pfx##_impl_from_IWeakReference(IWeakReference *iface) \ +{ \ + return CONTAINING_RECORD(iface, struct weakref, IWeakReference_iface); \ +} \ +static HRESULT WINAPI pfx##_weakref_QueryInterface(IWeakReference *iface, REFIID iid, void **out) \ +{ \ + struct weakref *impl = pfx##_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; \ + IWeakReference_AddRef(*out); \ + return S_OK; \ + } \ + FIXME("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); \ + *out = NULL; \ + return E_NOINTERFACE; \ +} \ +static ULONG WINAPI pfx##_weakref_AddRef(IWeakReference *iface) \ +{ \ + struct weakref *impl = pfx##_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 pfx##_weakref_Release(IWeakReference *iface) \ +{ \ + struct weakref *impl = pfx##_impl_from_IWeakReference(iface); \ + ULONG ref = InterlockedDecrement(&impl->ref_weak); \ + TRACE("iface %p, ref %lu.\n", iface, ref); \ + if (!ref) free(impl); \ + return ref; \ +} \ +static HRESULT WINAPI pfx##_weakref_Resolve(IWeakReference *iface, REFIID iid, IInspectable **out) \ +{ \ + struct weakref *impl = pfx##_impl_from_IWeakReference(iface); \ + HRESULT hr; \ + LONG ref; \ + TRACE("iface %p, iid %s, out %p.\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 = IUnknown_QueryInterface(impl->object, iid, (void **)out); \ + IUnknown_Release(impl->object); \ + return hr; \ +} \ +static const struct IWeakReferenceVtbl pfx##_weakref_vtbl = \ +{ \ + pfx##_weakref_QueryInterface, \ + pfx##_weakref_AddRef, \ + pfx##_weakref_Release, \ + pfx##_weakref_Resolve, \ +}; \ +static inline impl_type *pfx##_impl_from_IWeakReferenceSource(IWeakReferenceSource *iface) \ +{ \ + return CONTAINING_RECORD(iface, impl_type, IWeakReferenceSource_iface); \ +} \ +static HRESULT WINAPI pfx##_weakref_source_QueryInterface(IWeakReferenceSource *iface, \ + REFIID iid, void **out) \ +{ \ + impl_type *impl = pfx##_impl_from_IWeakReferenceSource(iface); \ + return pfx##_QueryInterface(&impl->iface_type##_iface, iid, out); \ +} \ +static ULONG WINAPI pfx##_weakref_source_AddRef(IWeakReferenceSource *iface) \ +{ \ + impl_type *impl = pfx##_impl_from_IWeakReferenceSource(iface); \ + return pfx##_AddRef(&impl->iface_type##_iface); \ +} \ +static ULONG WINAPI pfx##_weakref_source_Release(IWeakReferenceSource *iface) \ +{ \ + impl_type *impl = pfx##_impl_from_IWeakReferenceSource(iface); \ + return pfx##_Release(&impl->iface_type##_iface); \ +} \ +static HRESULT WINAPI pfx##_weakref_source_GetWeakReference(IWeakReferenceSource *iface, \ + IWeakReference **ref) \ +{ \ + impl_type *impl = pfx##_impl_from_IWeakReferenceSource(iface); \ + TRACE("iface %p, ref %p stub.\n", iface, ref); \ + *ref = &impl->weakref->IWeakReference_iface; \ + IWeakReference_AddRef(*ref); \ + return S_OK; \ +} \ +static const struct IWeakReferenceSourceVtbl pfx##_weakref_source_vtbl = \ +{ \ + pfx##_weakref_source_QueryInterface, \ + pfx##_weakref_source_AddRef, \ + pfx##_weakref_source_Release, \ + pfx##_weakref_source_GetWeakReference, \ +}; + #endif
Rémi Bernon (@rbernon) commented about dlls/windows.ui/private.h:
- Call "IWeakReference_Release( &impl->weakref->IWeakReference_iface );" in object_Release()
- when object->weakref->ref_strong reaches zero.
- */
+/* The control block is contained in struct weakref so that we don't have to allocate a separate
- struct for it */
+struct weakref +{
- IWeakReference IWeakReference_iface;
- IUnknown *object;
- /* control block */
- LONG ref_strong;
- LONG ref_weak;
+};
+#define DEFINE_WEAKREF(pfx, iface_type, impl_type) \
It doesn't seem necessary to use a macro for this, a separate file with the implementation and a simple API like:
``` HRESULT weak_reference_create( IUnknown *object, IWeakReference **out ); ULONG weak_reference_strong_add_ref( IWeakReference *iface ); ULONG weak_reference_strong_release( IWeakReference *iface ); ```
Should work and be easily shared across modules.
Also, lets keep the code style consistent with most other WinRT modules (ie: ntdll style).