From: Zhiyi Zhang <zzhang(a)codeweavers.com> --- dlls/windows.ui.core.textinput/Makefile.in | 3 +- dlls/windows.ui.core.textinput/main.c | 21 ++- .../tests/textinput.c | 2 + dlls/windows.ui.core.textinput/weakref.c | 175 ++++++++++++++++++ dlls/windows.ui.core.textinput/weakref.h | 38 ++++ 5 files changed, 234 insertions(+), 5 deletions(-) create mode 100644 dlls/windows.ui.core.textinput/weakref.c create mode 100644 dlls/windows.ui.core.textinput/weakref.h diff --git a/dlls/windows.ui.core.textinput/Makefile.in b/dlls/windows.ui.core.textinput/Makefile.in index 02cd358ce37..38d07a5a5c0 100644 --- a/dlls/windows.ui.core.textinput/Makefile.in +++ b/dlls/windows.ui.core.textinput/Makefile.in @@ -4,4 +4,5 @@ IMPORTS = combase SOURCES = \ classes.idl \ main.c \ - vector.c + vector.c \ + weakref.c diff --git a/dlls/windows.ui.core.textinput/main.c b/dlls/windows.ui.core.textinput/main.c index 6ca81dc0e3c..25110e09be9 100644 --- a/dlls/windows.ui.core.textinput/main.c +++ b/dlls/windows.ui.core.textinput/main.c @@ -19,6 +19,7 @@ #include "initguid.h" #include "private.h" +#include "weakref.h" WINE_DEFAULT_DEBUG_CHANNEL(coreinputview); @@ -28,7 +29,7 @@ struct core_input_view ICoreInputView2 ICoreInputView2_iface; ICoreInputView3 ICoreInputView3_iface; ICoreInputView4 ICoreInputView4_iface; - LONG ref; + struct weak_reference_source weak_reference_source; }; static inline struct core_input_view *impl_from_ICoreInputView(ICoreInputView *iface) @@ -63,6 +64,10 @@ static HRESULT WINAPI core_input_view_QueryInterface(ICoreInputView *iface, REFI { *out = &impl->ICoreInputView4_iface; } + else if (IsEqualGUID(iid, &IID_IWeakReferenceSource)) + { + *out = &impl->weak_reference_source.IWeakReferenceSource_iface; + } if (*out) { @@ -77,7 +82,7 @@ static HRESULT WINAPI core_input_view_QueryInterface(ICoreInputView *iface, REFI static ULONG WINAPI core_input_view_AddRef(ICoreInputView *iface) { struct core_input_view *impl = impl_from_ICoreInputView(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; } @@ -85,7 +90,7 @@ static ULONG WINAPI core_input_view_AddRef(ICoreInputView *iface) static ULONG WINAPI core_input_view_Release(ICoreInputView *iface) { struct core_input_view *impl = impl_from_ICoreInputView(iface); - ULONG ref = InterlockedDecrement(&impl->ref); + ULONG ref = weak_reference_strong_release(&impl->weak_reference_source); TRACE("iface %p, ref %lu.\n", iface, ref); @@ -424,6 +429,7 @@ static HRESULT WINAPI core_input_view_statics_GetForCurrentView(ICoreInputViewSt ICoreInputView **result) { struct core_input_view *view; + HRESULT hr; FIXME("iface %p, result %p semi-stub.\n", iface, result); @@ -437,7 +443,14 @@ static HRESULT WINAPI core_input_view_statics_GetForCurrentView(ICoreInputViewSt view->ICoreInputView2_iface.lpVtbl = &core_input_view2_vtbl; view->ICoreInputView3_iface.lpVtbl = &core_input_view3_vtbl; view->ICoreInputView4_iface.lpVtbl = &core_input_view4_vtbl; - view->ref = 1; + + if (FAILED(hr = weak_reference_source_init(&view->weak_reference_source, + (IUnknown *)&view->ICoreInputView_iface))) + { + *result = NULL; + free(view); + return hr; + } *result = &view->ICoreInputView_iface; return S_OK; diff --git a/dlls/windows.ui.core.textinput/tests/textinput.c b/dlls/windows.ui.core.textinput/tests/textinput.c index b2e7cd4e8c9..1c83d56f070 100644 --- a/dlls/windows.ui.core.textinput/tests/textinput.c +++ b/dlls/windows.ui.core.textinput/tests/textinput.c @@ -23,6 +23,7 @@ #include "winbase.h" #include "winstring.h" #include "roapi.h" +#include "weakreference.h" #include "wine/test.h" #define WIDL_using_Windows_UI_ViewManagement_Core @@ -104,6 +105,7 @@ static void test_CoreInputView(void) check_interface(core_input_view, &IID_IUnknown, TRUE); check_interface(core_input_view, &IID_IInspectable, TRUE); check_interface(core_input_view, &IID_IAgileObject, TRUE); + check_interface(core_input_view, &IID_IWeakReferenceSource, TRUE); check_interface(core_input_view, &IID_ICoreInputView, TRUE); check_interface(core_input_view, &IID_ICoreInputView2, TRUE); check_interface(core_input_view, &IID_ICoreInputView3, TRUE); diff --git a/dlls/windows.ui.core.textinput/weakref.c b/dlls/windows.ui.core.textinput/weakref.c new file mode 100644 index 00000000000..6a10390dd4c --- /dev/null +++ b/dlls/windows.ui.core.textinput/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.core.textinput/weakref.h b/dlls/windows.ui.core.textinput/weakref.h new file mode 100644 index 00000000000..7d4bc22b087 --- /dev/null +++ b/dlls/windows.ui.core.textinput/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 */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9269