Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55126
-- v10: windows.devices.geolocation.geolocator: Implement IWeakReference.
From: Fabian Maurer dark.shadow4@web.de
--- include/windows.foundation.idl | 1 + 1 file changed, 1 insertion(+)
diff --git a/include/windows.foundation.idl b/include/windows.foundation.idl index d89541740a7..281b51d0d6c 100644 --- a/include/windows.foundation.idl +++ b/include/windows.foundation.idl @@ -87,6 +87,7 @@ namespace Windows.Foundation { interface Windows.Foundation.IAsyncOperation<IInspectable *>; interface Windows.Foundation.IAsyncOperation<boolean>; interface Windows.Foundation.IReference<INT32>; + interface Windows.Foundation.IReference<DOUBLE>; interface Windows.Foundation.TypedEventHandler<IInspectable *, IInspectable *>; interface Windows.Foundation.TypedEventHandler<Windows.Foundation.IMemoryBufferReference *, IInspectable *>; }
From: Fabian Maurer dark.shadow4@web.de
--- include/Makefile.in | 1 + include/windows.devices.geolocation.idl | 223 ++++++++++++++++++++++++ 2 files changed, 224 insertions(+) create mode 100644 include/windows.devices.geolocation.idl
diff --git a/include/Makefile.in b/include/Makefile.in index e9f0aa8d5fb..94e733cc61c 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -808,6 +808,7 @@ SOURCES = \ windns.h \ windot11.h \ windows.devices.enumeration.idl \ + windows.devices.geolocation.idl \ windows.devices.haptics.idl \ windows.devices.power.idl \ windows.foundation.collections.idl \ diff --git a/include/windows.devices.geolocation.idl b/include/windows.devices.geolocation.idl new file mode 100644 index 00000000000..9d0033503e3 --- /dev/null +++ b/include/windows.devices.geolocation.idl @@ -0,0 +1,223 @@ +/* + * Copyright 2023 Fabian Maurer + * + * 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 + */ + +#ifdef __WIDL__ +#pragma winrt ns_prefix +#endif + +#ifndef DO_NO_IMPORTS +import "inspectable.idl"; +import "asyncinfo.idl"; +import "eventtoken.idl"; +import "windowscontracts.idl"; +import "windows.foundation.idl"; +#endif + +namespace Windows.Devices.Geolocation { + + typedef enum PositionAccuracy PositionAccuracy; + typedef enum PositionStatus PositionStatus; + + interface IGeolocator; + interface IGeoposition; + interface IGeocoordinate; + interface IPositionChangedEventArgs; + interface IStatusChangedEventArgs; + interface ICivicAddress; + + runtimeclass Geolocator; + runtimeclass Geoposition; + runtimeclass Geocoordinate; + runtimeclass PositionChangedEventArgs; + runtimeclass StatusChangedEventArgs; + runtimeclass CivicAddress; + + declare { + interface Windows.Foundation.AsyncOperationCompletedHandler<Windows.Devices.Geolocation.Geoposition*>; + interface Windows.Foundation.IAsyncOperation<Windows.Devices.Geolocation.Geoposition*>; + interface Windows.Foundation.TypedEventHandler<Windows.Devices.Geolocation.Geolocator*, Windows.Devices.Geolocation.PositionChangedEventArgs*>; + interface Windows.Foundation.TypedEventHandler<Windows.Devices.Geolocation.Geolocator*, Windows.Devices.Geolocation.StatusChangedEventArgs*>; + } + + [contract(Windows.Foundation.UniversalApiContract, 1.0)] + enum PositionAccuracy + { + Default = 0, + High = 1, + }; + + [contract(Windows.Foundation.UniversalApiContract, 1.0)] + enum PositionStatus + { + Ready = 0, + Initializing = 1, + NoData = 2, + Disabled = 3, + NotInitialized = 4, + NotAvailable = 5, + }; + + /* Interfaces */ + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + exclusiveto(Windows.Devices.Geolocation.Geolocator), + uuid(a9c3bf62-4524-4989-8aa9-de019d2e551f) + ] + interface IGeolocator : IInspectable + { + [propget] HRESULT DesiredAccuracy([out, retval] Windows.Devices.Geolocation.PositionAccuracy *value); + [propput] HRESULT DesiredAccuracy([in] Windows.Devices.Geolocation.PositionAccuracy value); + [propget] HRESULT MovementThreshold([out, retval] DOUBLE *value); + [propput] HRESULT MovementThreshold([in] DOUBLE value); + [propget] HRESULT ReportInterval([out, retval] UINT32 *value); + [propput] HRESULT ReportInterval([in] UINT32 value); + [propget] HRESULT LocationStatus([out, retval] Windows.Devices.Geolocation.PositionStatus *value); + [overload("GetGeopositionAsync")] + HRESULT GetGeopositionAsync([out, retval] Windows.Foundation.IAsyncOperation<Windows.Devices.Geolocation.Geoposition*> **value); + [overload("GetGeopositionAsync")] + HRESULT GetGeopositionAsyncWithAgeAndTimeout([in] Windows.Foundation.TimeSpan maximum_age, + [in] Windows.Foundation.TimeSpan timeout, + [out, retval] Windows.Foundation.IAsyncOperation<Windows.Devices.Geolocation.Geoposition*> **value); + [eventadd] HRESULT PositionChanged([in] Windows.Foundation.TypedEventHandler<Windows.Devices.Geolocation.Geolocator*, Windows.Devices.Geolocation.PositionChangedEventArgs*> *handler, + [out, retval] EventRegistrationToken *token); + [eventremove] HRESULT PositionChanged([in] EventRegistrationToken token); + [eventadd] HRESULT StatusChanged([in] Windows.Foundation.TypedEventHandler<Windows.Devices.Geolocation.Geolocator*, Windows.Devices.Geolocation.StatusChangedEventArgs*> *handler, + [out, retval] EventRegistrationToken *token); + [eventremove] HRESULT StatusChanged([in] EventRegistrationToken token); + } + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + exclusiveto(Windows.Devices.Geolocation.Geoposition), + uuid(c18d0454-7d41-4ff7-a957-9dffb4ef7f5b) + ] + interface IGeoposition : IInspectable + { + [propget] HRESULT Coordinate([out, retval] Windows.Devices.Geolocation.Geocoordinate **value); + [propget] HRESULT CivicAddress([out, retval] Windows.Devices.Geolocation.CivicAddress **value); + } + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + exclusiveto(Windows.Devices.Geolocation.Geocoordinate), + uuid(ee21a3aa-976a-ac70-803d-083ea55bcbc4) + ] + interface IGeocoordinate : IInspectable + { + [propget] HRESULT Latitude([out, retval] DOUBLE *value); + [propget] HRESULT Longitude([out, retval] DOUBLE *value); + [propget] HRESULT Altitude([out, retval] Windows.Foundation.IReference<DOUBLE> **value); + [propget] HRESULT Accuracy([out, retval] DOUBLE *value); + [propget] HRESULT AltitudeAccuracy([out, retval] Windows.Foundation.IReference<DOUBLE> **value); + [propget] HRESULT Heading([out, retval] Windows.Foundation.IReference<DOUBLE> **value); + [propget] HRESULT Speed([out, retval] Windows.Foundation.IReference<DOUBLE> **value); + [propget] HRESULT Timestamp([out, retval] Windows.Foundation.DateTime *value); + } + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + exclusiveto(Windows.Devices.Geolocation.PositionChangedEventArgs), + uuid(37859ce5-9d1e-46c5-bf3b-6ad8cac1a093) + ] + interface IPositionChangedEventArgs : IInspectable + { + [propget] HRESULT Position([out, retval] Windows.Devices.Geolocation.Geoposition **value); + } + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + exclusiveto(Windows.Devices.Geolocation.StatusChangedEventArgs), + uuid(3453d2da-8c93-4111-a205-9aecfc9be5c0) + ] + interface IStatusChangedEventArgs : IInspectable + { + [propget] HRESULT Status([out, retval] Windows.Devices.Geolocation.PositionStatus *value); + } + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + exclusiveto(Windows.Devices.Geolocation.CivicAddress), + uuid(a8567a1a-64f4-4d48-bcea-f6b008eca34c) + ] + interface ICivicAddress : IInspectable + { + [propget] HRESULT Country([out, retval] HSTRING *value); + [propget] HRESULT State([out, retval] HSTRING *value); + [propget] HRESULT City([out, retval] HSTRING *value); + [propget] HRESULT PostalCode([out, retval] HSTRING *value); + [propget] HRESULT Timestamp([out, retval] Windows.Foundation.DateTime *value); + } + + /* Runtime Classes */ + + [ + activatable(Windows.Foundation.UniversalApiContract, 1.0), + contract(Windows.Foundation.UniversalApiContract, 1.0), + marshaling_behavior(agile), + threading(both) + ] + runtimeclass Geolocator + { + [default] interface Windows.Devices.Geolocation.IGeolocator; + } + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + marshaling_behavior(agile) + ] + runtimeclass Geoposition + { + [default] interface Windows.Devices.Geolocation.IGeoposition; + } + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + marshaling_behavior(agile) + ] + runtimeclass Geocoordinate + { + [default] interface Windows.Devices.Geolocation.IGeocoordinate; + } + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + marshaling_behavior(agile) + ] + runtimeclass PositionChangedEventArgs + { + [default] interface Windows.Devices.Geolocation.IPositionChangedEventArgs; + } + + [ + marshaling_behavior(agile) + ] + runtimeclass StatusChangedEventArgs + { + [default] interface Windows.Devices.Geolocation.IStatusChangedEventArgs; + } + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + marshaling_behavior(agile) + ] + runtimeclass CivicAddress + { + [default] interface Windows.Devices.Geolocation.ICivicAddress; + } +}
From: Fabian Maurer dark.shadow4@web.de
--- .../Makefile.in | 7 + .../classes.idl | 26 +++ .../main.c | 148 ++++++++++++++++++ .../private.h | 38 +++++ .../tests/Makefile.in | 5 + .../tests/geolocator.c | 87 ++++++++++ ...indows.devices.geolocation.geolocator.spec | 3 + 7 files changed, 314 insertions(+) create mode 100644 dlls/windows.devices.geolocation.geolocator/Makefile.in create mode 100644 dlls/windows.devices.geolocation.geolocator/classes.idl create mode 100644 dlls/windows.devices.geolocation.geolocator/main.c create mode 100644 dlls/windows.devices.geolocation.geolocator/private.h create mode 100644 dlls/windows.devices.geolocation.geolocator/tests/Makefile.in create mode 100644 dlls/windows.devices.geolocation.geolocator/tests/geolocator.c create mode 100644 dlls/windows.devices.geolocation.geolocator/windows.devices.geolocation.geolocator.spec
diff --git a/dlls/windows.devices.geolocation.geolocator/Makefile.in b/dlls/windows.devices.geolocation.geolocator/Makefile.in new file mode 100644 index 00000000000..42b5e50442b --- /dev/null +++ b/dlls/windows.devices.geolocation.geolocator/Makefile.in @@ -0,0 +1,7 @@ +MODULE = windows.devices.geolocation.geolocator.dll +IMPORTS = combase uuid + +C_SRCS = \ + main.c + +IDL_SRCS = classes.idl diff --git a/dlls/windows.devices.geolocation.geolocator/classes.idl b/dlls/windows.devices.geolocation.geolocator/classes.idl new file mode 100644 index 00000000000..9c55cf20446 --- /dev/null +++ b/dlls/windows.devices.geolocation.geolocator/classes.idl @@ -0,0 +1,26 @@ +/* Runtime Classes for windows.devices.geolocation.geolocator.dll + * + * Copyright 2023 Fabian Maurer + * + * 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 + */ + +#pragma makedep register + +#ifdef __WIDL__ +#pragma winrt ns_prefix +#endif + +#include "windows.devices.geolocation.idl" diff --git a/dlls/windows.devices.geolocation.geolocator/main.c b/dlls/windows.devices.geolocation.geolocator/main.c new file mode 100644 index 00000000000..0a8a46f262f --- /dev/null +++ b/dlls/windows.devices.geolocation.geolocator/main.c @@ -0,0 +1,148 @@ +/* WinRT Windows.Devices.Geolocation.Geolocator Implementation + * + * Copyright 2023 Fabian Maurer + * + * 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 + */ + +#include "initguid.h" +#include "private.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(geolocator); + +static const char *debugstr_hstring(HSTRING hstr) +{ + const WCHAR *str; + UINT32 len; + if (hstr && !((ULONG_PTR)hstr >> 16)) return "(invalid)"; + str = WindowsGetStringRawBuffer(hstr, &len); + return wine_dbgstr_wn(str, len); +} + +struct geolocator_statics +{ + IActivationFactory IActivationFactory_iface; + LONG ref; +}; + +static inline struct geolocator_statics *impl_from_IActivationFactory(IActivationFactory *iface) +{ + return CONTAINING_RECORD(iface, struct geolocator_statics, IActivationFactory_iface); +} + +static HRESULT WINAPI factory_QueryInterface(IActivationFactory *iface, REFIID iid, void **out) +{ + struct geolocator_statics *impl = impl_from_IActivationFactory(iface); + + TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); + + if (IsEqualGUID(iid, &IID_IUnknown) || + IsEqualGUID(iid, &IID_IInspectable) || + IsEqualGUID(iid, &IID_IAgileObject) || + IsEqualGUID(iid, &IID_IActivationFactory)) + { + *out = &impl->IActivationFactory_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 factory_AddRef(IActivationFactory *iface) +{ + struct geolocator_statics *impl = impl_from_IActivationFactory(iface); + ULONG ref = InterlockedIncrement(&impl->ref); + TRACE("iface %p increasing refcount to %lu.\n", iface, ref); + return ref; +} + +static ULONG WINAPI factory_Release(IActivationFactory *iface) +{ + struct geolocator_statics *impl = impl_from_IActivationFactory(iface); + ULONG ref = InterlockedDecrement(&impl->ref); + TRACE("iface %p decreasing refcount to %lu.\n", iface, ref); + return ref; +} + +static HRESULT WINAPI factory_GetIids(IActivationFactory *iface, ULONG *iid_count, IID **iids) +{ + FIXME("iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids); + return E_NOTIMPL; +} + +static HRESULT WINAPI factory_GetRuntimeClassName(IActivationFactory *iface, HSTRING *class_name) +{ + FIXME("iface %p, class_name %p stub!\n", iface, class_name); + return E_NOTIMPL; +} + +static HRESULT WINAPI factory_GetTrustLevel(IActivationFactory *iface, TrustLevel *trust_level) +{ + FIXME("iface %p, trust_level %p stub!\n", iface, trust_level); + return E_NOTIMPL; +} + +static HRESULT WINAPI factory_ActivateInstance(IActivationFactory *iface, IInspectable **instance) +{ + FIXME("iface %p, instance %p stub!\n", iface, instance); + return E_NOTIMPL; +} + +static const struct IActivationFactoryVtbl factory_vtbl = +{ + factory_QueryInterface, + factory_AddRef, + factory_Release, + /* IInspectable methods */ + factory_GetIids, + factory_GetRuntimeClassName, + factory_GetTrustLevel, + /* IActivationFactory methods */ + factory_ActivateInstance, +}; + +static struct geolocator_statics geolocator_statics = +{ + {&factory_vtbl}, + 1, +}; + +static IActivationFactory *geolocator_factory = &geolocator_statics.IActivationFactory_iface; + +HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **out) +{ + FIXME("clsid %s, riid %s, out %p stub!\n", debugstr_guid(clsid), debugstr_guid(riid), out); + return CLASS_E_CLASSNOTAVAILABLE; +} + +HRESULT WINAPI DllGetActivationFactory(HSTRING classid, IActivationFactory **factory) +{ + const WCHAR *name = WindowsGetStringRawBuffer(classid, NULL); + + TRACE("classid %s, factory %p.\n", debugstr_hstring(classid), factory); + + *factory = NULL; + + if (!wcscmp(name, RuntimeClass_Windows_Devices_Geolocation_Geolocator)) + IActivationFactory_QueryInterface(geolocator_factory, &IID_IActivationFactory, (void **)factory); + + if (*factory) return S_OK; + return CLASS_E_CLASSNOTAVAILABLE; +} diff --git a/dlls/windows.devices.geolocation.geolocator/private.h b/dlls/windows.devices.geolocation.geolocator/private.h new file mode 100644 index 00000000000..b03c6cfc9d0 --- /dev/null +++ b/dlls/windows.devices.geolocation.geolocator/private.h @@ -0,0 +1,38 @@ +/* WinRT Windows.Devices.Geolocation.Geolocator Implementation + * + * Copyright 2023 Fabian Maurer + * + * 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_WINDOWS_DEVICES_GEOLOCATION_GEOLOCATOR_PRIVATE_H +#define __WINE_WINDOWS_DEVICES_GEOLOCATION_GEOLOCATOR_PRIVATE_H + +#include <stdarg.h> + +#define COBJMACROS +#include "windef.h" +#include "winbase.h" +#include "winstring.h" + +#include "activation.h" + +#define WIDL_using_Windows_Foundation +#define WIDL_using_Windows_Foundation_Collections +#include "windows.foundation.h" +#define WIDL_using_Windows_Devices_Geolocation +#include "windows.devices.geolocation.h" + +#endif diff --git a/dlls/windows.devices.geolocation.geolocator/tests/Makefile.in b/dlls/windows.devices.geolocation.geolocator/tests/Makefile.in new file mode 100644 index 00000000000..1be5ca78258 --- /dev/null +++ b/dlls/windows.devices.geolocation.geolocator/tests/Makefile.in @@ -0,0 +1,5 @@ +TESTDLL = windows.devices.geolocation.geolocator.dll +IMPORTS = combase uuid + +C_SRCS = \ + geolocator.c diff --git a/dlls/windows.devices.geolocation.geolocator/tests/geolocator.c b/dlls/windows.devices.geolocation.geolocator/tests/geolocator.c new file mode 100644 index 00000000000..84ec361ea7b --- /dev/null +++ b/dlls/windows.devices.geolocation.geolocator/tests/geolocator.c @@ -0,0 +1,87 @@ +/* + * Copyright 2023 Fabian Maurer + * + * 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 <stdarg.h> + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winstring.h" + +#include "initguid.h" +#include "roapi.h" + +#define WIDL_using_Windows_Foundation +#define WIDL_using_Windows_Foundation_Collections +#include "windows.foundation.h" +#define WIDL_using_Windows_Devices_Geolocation +#include "windows.devices.geolocation.h" + +#include "wine/test.h" + +#define check_interface(obj, iid) check_interface_(__LINE__, obj, iid) +static void check_interface_(unsigned int line, void *obj, const IID *iid) +{ + IUnknown *iface = obj; + IUnknown *unk; + HRESULT hr; + + hr = IUnknown_QueryInterface(iface, iid, (void **)&unk); + ok_(__FILE__, line)(hr == S_OK, "got hr %#lx.\n", hr); + if (hr == S_OK) + IUnknown_Release(unk); +} + +void test_basic(void) +{ + static const WCHAR *geolocator_name = L"Windows.Devices.Geolocation.Geolocator"; + IActivationFactory *factory; + HSTRING str; + HRESULT hr; + + hr = WindowsCreateString(geolocator_name, wcslen(geolocator_name), &str); + ok(hr == S_OK, "got hr %#lx.\n", hr); + + hr = RoGetActivationFactory(str, &IID_IActivationFactory, (void **)&factory); + WindowsDeleteString(str); + ok(hr == S_OK || broken(hr == REGDB_E_CLASSNOTREG), "got hr %#lx.\n", hr); + if (hr == REGDB_E_CLASSNOTREG) + { + win_skip("%s runtimeclass not registered, skipping tests.\n", wine_dbgstr_w(geolocator_name)); + return; + } + + /* Don't check IID_IAgileObject since it's ignored on win 8 */ + check_interface(factory, &IID_IUnknown); + check_interface(factory, &IID_IInspectable); + check_interface(factory, &IID_IActivationFactory); + + IActivationFactory_Release(factory); +} + +START_TEST(geolocator) +{ + HRESULT hr; + + hr = RoInitialize(RO_INIT_MULTITHREADED); + ok(hr == S_OK, "RoInitialize failed, hr %#lx\n", hr); + + test_basic(); + + RoUninitialize(); +} diff --git a/dlls/windows.devices.geolocation.geolocator/windows.devices.geolocation.geolocator.spec b/dlls/windows.devices.geolocation.geolocator/windows.devices.geolocation.geolocator.spec new file mode 100644 index 00000000000..721493229c2 --- /dev/null +++ b/dlls/windows.devices.geolocation.geolocator/windows.devices.geolocation.geolocator.spec @@ -0,0 +1,3 @@ +1 stdcall -private DllCanUnloadNow() +2 stdcall -private DllGetActivationFactory(ptr ptr) +3 stdcall -private DllGetClassObject(ptr ptr ptr)
From: Fabian Maurer dark.shadow4@web.de
--- .../main.c | 188 +++++++++++++++++- .../tests/geolocator.c | 17 ++ 2 files changed, 203 insertions(+), 2 deletions(-)
diff --git a/dlls/windows.devices.geolocation.geolocator/main.c b/dlls/windows.devices.geolocation.geolocator/main.c index 0a8a46f262f..624c0bfd591 100644 --- a/dlls/windows.devices.geolocation.geolocator/main.c +++ b/dlls/windows.devices.geolocation.geolocator/main.c @@ -39,6 +39,175 @@ struct geolocator_statics LONG ref; };
+struct geolocator +{ + IGeolocator IGeolocator_iface; + LONG ref; +}; + +static inline struct geolocator *impl_from_IGeolocator(IGeolocator *iface) +{ + return CONTAINING_RECORD(iface, struct geolocator, IGeolocator_iface); +} + +static HRESULT WINAPI geolocator_QueryInterface(IGeolocator *iface, REFIID iid, void **out) +{ + struct geolocator *impl = impl_from_IGeolocator(iface); + + TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); + + if (IsEqualGUID(iid, &IID_IUnknown) || + IsEqualGUID(iid, &IID_IInspectable) || + IsEqualGUID(iid, &IID_IAgileObject) || + IsEqualGUID(iid, &IID_IGeolocator)) + { + *out = &impl->IGeolocator_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 geolocator_AddRef(IGeolocator *iface) +{ + struct geolocator *impl = impl_from_IGeolocator(iface); + ULONG ref = InterlockedIncrement(&impl->ref); + TRACE("iface %p increasing refcount to %lu.\n", iface, ref); + return ref; +} + +static ULONG WINAPI geolocator_Release(IGeolocator *iface) +{ + struct geolocator *impl = impl_from_IGeolocator(iface); + ULONG ref = InterlockedDecrement(&impl->ref); + TRACE("iface %p decreasing refcount to %lu.\n", iface, ref); + return ref; +} + +static HRESULT WINAPI geolocator_GetIids(IGeolocator *iface, ULONG *iid_count, IID **iids) +{ + FIXME("iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids); + return E_NOTIMPL; +} + +static HRESULT WINAPI geolocator_GetRuntimeClassName(IGeolocator *iface, HSTRING *class_name) +{ + FIXME("iface %p, class_name %p stub!\n", iface, class_name); + return E_NOTIMPL; +} + +static HRESULT WINAPI geolocator_GetTrustLevel(IGeolocator *iface, TrustLevel *trust_level) +{ + FIXME("iface %p, trust_level %p stub!\n", iface, trust_level); + return E_NOTIMPL; +} + +HRESULT WINAPI geolocator_get_DesiredAccuracy(IGeolocator *iface, PositionAccuracy *value) +{ + FIXME("iface %p, value %p stub.\n", iface, value); + return E_NOTIMPL; +} + +HRESULT WINAPI geolocator_set_DesiredAccuracy(IGeolocator *iface, PositionAccuracy value) +{ + FIXME("iface %p, value %d stub.\n", iface, value); + return E_NOTIMPL; +} + +HRESULT WINAPI geolocator_get_MovementThreshold(IGeolocator *iface, DOUBLE *value) +{ + FIXME("iface %p, value %p stub.\n", iface, value); + return E_NOTIMPL; +} + +HRESULT WINAPI geolocator_set_MovementThreshold(IGeolocator *iface, DOUBLE value) +{ + FIXME("iface %p, value %f stub.\n", iface, value); + return E_NOTIMPL; +} + +HRESULT WINAPI geolocator_get_ReportInterval(IGeolocator *iface, UINT32 *value) +{ + FIXME("iface %p, value %p stub.\n", iface, value); + return E_NOTIMPL; +} + +HRESULT WINAPI geolocator_set_ReportInterval(IGeolocator *iface, UINT32 value) +{ + FIXME("iface %p, value %u stub.\n", iface, value); + return E_NOTIMPL; +} + +HRESULT WINAPI geolocator_LocationStatus(IGeolocator *iface, PositionStatus *value) +{ + FIXME("iface %p, value %p stub.\n", iface, value); + return E_NOTIMPL; +} + +HRESULT WINAPI geolocator_GetGeopositionAsync(IGeolocator *iface, IAsyncOperation_Geoposition **value) +{ + FIXME("iface %p, value %p stub.\n", iface, value); + return E_NOTIMPL; +} + +HRESULT WINAPI geolocator_GetGeopositionAsyncWithAgeAndTimeout(IGeolocator *iface, TimeSpan maximum_age, TimeSpan timeout, IAsyncOperation_Geoposition **value) +{ + FIXME("iface %p, maximum_age %#I64x, timeout %#I64x, value %p stub.\n", iface, maximum_age.Duration, timeout.Duration, value); + return E_NOTIMPL; +} + +HRESULT WINAPI geolocator_add_PositionChanged(IGeolocator *iface, ITypedEventHandler_Geolocator_PositionChangedEventArgs *handler, EventRegistrationToken *token) +{ + FIXME("iface %p, handler %p, token %p stub.\n", iface, handler, token); + return E_NOTIMPL; +} + +HRESULT WINAPI geolocator_remove_PositionChanged(IGeolocator *iface, EventRegistrationToken token) +{ + FIXME("iface %p, token %#I64x stub.\n", iface, token.value); + return E_NOTIMPL; +} + +HRESULT WINAPI geolocator_add_StatusChanged(IGeolocator *iface, ITypedEventHandler_Geolocator_StatusChangedEventArgs *handler, EventRegistrationToken *token) +{ + FIXME("iface %p, handler %p, token %p stub.\n", iface, handler, token); + return E_NOTIMPL; +} + +HRESULT WINAPI geolocator_remove_StatusChanged(IGeolocator *iface, EventRegistrationToken token) +{ + FIXME("iface %p, token %#I64x stub.\n", iface, token.value); + return E_NOTIMPL; +} + +static const struct IGeolocatorVtbl geolocator_vtbl = +{ + geolocator_QueryInterface, + geolocator_AddRef, + geolocator_Release, + /* IInspectable methods */ + geolocator_GetIids, + geolocator_GetRuntimeClassName, + geolocator_GetTrustLevel, + /* IGeolocator methods */ + geolocator_get_DesiredAccuracy, + geolocator_set_DesiredAccuracy, + geolocator_get_MovementThreshold, + geolocator_set_MovementThreshold, + geolocator_get_ReportInterval, + geolocator_set_ReportInterval, + geolocator_LocationStatus, + geolocator_GetGeopositionAsync, + geolocator_GetGeopositionAsyncWithAgeAndTimeout, + geolocator_add_PositionChanged, + geolocator_remove_PositionChanged, + geolocator_add_StatusChanged, + geolocator_remove_StatusChanged, +}; + static inline struct geolocator_statics *impl_from_IActivationFactory(IActivationFactory *iface) { return CONTAINING_RECORD(iface, struct geolocator_statics, IActivationFactory_iface); @@ -99,10 +268,25 @@ static HRESULT WINAPI factory_GetTrustLevel(IActivationFactory *iface, TrustLeve return E_NOTIMPL; }
+static const struct IActivationFactoryVtbl factory_vtbl; + static HRESULT WINAPI factory_ActivateInstance(IActivationFactory *iface, IInspectable **instance) { - FIXME("iface %p, instance %p stub!\n", iface, instance); - return E_NOTIMPL; + struct geolocator *impl; + + TRACE("iface %p, instance %p.\n", iface, instance); + + if (!(impl = calloc(1, sizeof(*impl)))) + { + *instance = NULL; + return E_OUTOFMEMORY; + } + + impl->IGeolocator_iface.lpVtbl = &geolocator_vtbl; + impl->ref = 1; + + *instance = (IInspectable *)&impl->IGeolocator_iface; + return S_OK; }
static const struct IActivationFactoryVtbl factory_vtbl = diff --git a/dlls/windows.devices.geolocation.geolocator/tests/geolocator.c b/dlls/windows.devices.geolocation.geolocator/tests/geolocator.c index 84ec361ea7b..4aa3cc35413 100644 --- a/dlls/windows.devices.geolocation.geolocator/tests/geolocator.c +++ b/dlls/windows.devices.geolocation.geolocator/tests/geolocator.c @@ -51,6 +51,8 @@ void test_basic(void) { static const WCHAR *geolocator_name = L"Windows.Devices.Geolocation.Geolocator"; IActivationFactory *factory; + IInspectable *inspectable; + IGeolocator *geolocator; HSTRING str; HRESULT hr;
@@ -71,6 +73,21 @@ void test_basic(void) check_interface(factory, &IID_IInspectable); check_interface(factory, &IID_IActivationFactory);
+ hr = IActivationFactory_ActivateInstance(factory, &inspectable); + ok(hr == S_OK && inspectable, "got hr %#lx.\n", hr); + + check_interface(inspectable, &IID_IUnknown); + check_interface(inspectable, &IID_IInspectable); + check_interface(inspectable, &IID_IAgileObject); + + hr = IInspectable_QueryInterface(inspectable, &IID_IGeolocator, (void **)&geolocator); + ok(hr == S_OK && geolocator, "got hr %#lx.\n", hr); + ok((void *)inspectable == (void *)geolocator, "Interfaces are not the same\n"); + + IInspectable_Release(inspectable); + inspectable = 0; + + IGeolocator_Release(geolocator); IActivationFactory_Release(factory); }
From: Fabian Maurer dark.shadow4@web.de
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55126 --- dlls/windows.devices.geolocation.geolocator/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/windows.devices.geolocation.geolocator/main.c b/dlls/windows.devices.geolocation.geolocator/main.c index 624c0bfd591..65a73ae9e2f 100644 --- a/dlls/windows.devices.geolocation.geolocator/main.c +++ b/dlls/windows.devices.geolocation.geolocator/main.c @@ -162,7 +162,7 @@ HRESULT WINAPI geolocator_GetGeopositionAsyncWithAgeAndTimeout(IGeolocator *ifac HRESULT WINAPI geolocator_add_PositionChanged(IGeolocator *iface, ITypedEventHandler_Geolocator_PositionChangedEventArgs *handler, EventRegistrationToken *token) { FIXME("iface %p, handler %p, token %p stub.\n", iface, handler, token); - return E_NOTIMPL; + return S_OK; }
HRESULT WINAPI geolocator_remove_PositionChanged(IGeolocator *iface, EventRegistrationToken token)
From: Fabian Maurer dark.shadow4@web.de
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55126 --- .../main.c | 47 +++++++++++++++++++ .../private.h | 1 + .../tests/geolocator.c | 6 +++ 3 files changed, 54 insertions(+)
diff --git a/dlls/windows.devices.geolocation.geolocator/main.c b/dlls/windows.devices.geolocation.geolocator/main.c index 65a73ae9e2f..96af2713f93 100644 --- a/dlls/windows.devices.geolocation.geolocator/main.c +++ b/dlls/windows.devices.geolocation.geolocator/main.c @@ -42,6 +42,7 @@ struct geolocator_statics struct geolocator { IGeolocator IGeolocator_iface; + IWeakReferenceSource IWeakReferenceSource_iface; LONG ref; };
@@ -66,6 +67,13 @@ static HRESULT WINAPI geolocator_QueryInterface(IGeolocator *iface, REFIID iid, return S_OK; }
+ if (IsEqualGUID(iid, &IID_IWeakReferenceSource)) + { + *out = &impl->IWeakReferenceSource_iface; + IInspectable_AddRef(*out); + return S_OK; + } + FIXME("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); *out = NULL; return E_NOINTERFACE; @@ -208,6 +216,44 @@ static const struct IGeolocatorVtbl geolocator_vtbl = geolocator_remove_StatusChanged, };
+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) +{ + FIXME("iface %p, ref %p stub.\n", iface, ref); + return E_NOTIMPL; +} + +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); @@ -283,6 +329,7 @@ static HRESULT WINAPI factory_ActivateInstance(IActivationFactory *iface, IInspe }
impl->IGeolocator_iface.lpVtbl = &geolocator_vtbl; + impl->IWeakReferenceSource_iface.lpVtbl = &weak_reference_source_vtbl; impl->ref = 1;
*instance = (IInspectable *)&impl->IGeolocator_iface; diff --git a/dlls/windows.devices.geolocation.geolocator/private.h b/dlls/windows.devices.geolocation.geolocator/private.h index b03c6cfc9d0..7250bc1fe36 100644 --- a/dlls/windows.devices.geolocation.geolocator/private.h +++ b/dlls/windows.devices.geolocation.geolocator/private.h @@ -28,6 +28,7 @@ #include "winstring.h"
#include "activation.h" +#include "weakreference.h"
#define WIDL_using_Windows_Foundation #define WIDL_using_Windows_Foundation_Collections diff --git a/dlls/windows.devices.geolocation.geolocator/tests/geolocator.c b/dlls/windows.devices.geolocation.geolocator/tests/geolocator.c index 4aa3cc35413..058098a5946 100644 --- a/dlls/windows.devices.geolocation.geolocator/tests/geolocator.c +++ b/dlls/windows.devices.geolocation.geolocator/tests/geolocator.c @@ -26,6 +26,7 @@ #include "initguid.h" #include "roapi.h"
+#include "weakreference.h" #define WIDL_using_Windows_Foundation #define WIDL_using_Windows_Foundation_Collections #include "windows.foundation.h" @@ -53,6 +54,7 @@ void test_basic(void) IActivationFactory *factory; IInspectable *inspectable; IGeolocator *geolocator; + IWeakReferenceSource *weak_reference_source; HSTRING str; HRESULT hr;
@@ -87,6 +89,10 @@ void test_basic(void) IInspectable_Release(inspectable); inspectable = 0;
+ hr = IGeolocator_QueryInterface(geolocator, &IID_IWeakReferenceSource, (void **)&weak_reference_source); + ok(hr == S_OK && weak_reference_source, "got hr %#lx.\n", hr); + IWeakReferenceSource_Release(weak_reference_source); + IGeolocator_Release(geolocator); IActivationFactory_Release(factory); }
From: Fabian Maurer dark.shadow4@web.de
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55126 --- .../main.c | 92 +++++++++++++++++-- .../tests/geolocator.c | 42 +++++++++ 2 files changed, 128 insertions(+), 6 deletions(-)
diff --git a/dlls/windows.devices.geolocation.geolocator/main.c b/dlls/windows.devices.geolocation.geolocator/main.c index 96af2713f93..1772bcd8138 100644 --- a/dlls/windows.devices.geolocation.geolocator/main.c +++ b/dlls/windows.devices.geolocation.geolocator/main.c @@ -43,7 +43,9 @@ struct geolocator { IGeolocator IGeolocator_iface; IWeakReferenceSource IWeakReferenceSource_iface; - LONG ref; + IWeakReference IWeakReference_iface; + LONG ref_public; + LONG ref_weak; };
static inline struct geolocator *impl_from_IGeolocator(IGeolocator *iface) @@ -82,16 +84,18 @@ 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); + ULONG ref = InterlockedIncrement(&impl->ref_public); 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); + ULONG ref = InterlockedDecrement(&impl->ref_public); TRACE("iface %p decreasing refcount to %lu.\n", iface, ref); + IWeakReference_Release(&impl->IWeakReference_iface); return ref; }
@@ -216,6 +220,76 @@ 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) +{ + HRESULT hr; + struct geolocator *impl = impl_from_IWeakReference(iface); + TRACE("iface %p, iid %s, out %p stub.\n", iface, debugstr_guid(iid), out); + + *out = 0; + + if (InterlockedIncrement(&impl->ref_public) > 1) + hr = IGeolocator_QueryInterface(&impl->IGeolocator_iface, iid, (void **)out); + else /* invalid object */ + { + *out = NULL; + hr = S_OK; + } + 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); @@ -241,8 +315,12 @@ static ULONG WINAPI weak_reference_source_Release(IWeakReferenceSource *iface)
static HRESULT WINAPI weak_reference_source_GetWeakReference(IWeakReferenceSource *iface, IWeakReference **ref) { - FIXME("iface %p, ref %p stub.\n", iface, ref); - return E_NOTIMPL; + 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 = @@ -330,7 +408,9 @@ static HRESULT WINAPI factory_ActivateInstance(IActivationFactory *iface, IInspe
impl->IGeolocator_iface.lpVtbl = &geolocator_vtbl; impl->IWeakReferenceSource_iface.lpVtbl = &weak_reference_source_vtbl; - impl->ref = 1; + impl->IWeakReference_iface.lpVtbl = &weak_reference_vtbl; + impl->ref_public = 1; + impl->ref_weak = 1;
*instance = (IInspectable *)&impl->IGeolocator_iface; return S_OK; diff --git a/dlls/windows.devices.geolocation.geolocator/tests/geolocator.c b/dlls/windows.devices.geolocation.geolocator/tests/geolocator.c index 058098a5946..ca12f0d3a9d 100644 --- a/dlls/windows.devices.geolocation.geolocator/tests/geolocator.c +++ b/dlls/windows.devices.geolocation.geolocator/tests/geolocator.c @@ -54,7 +54,11 @@ void test_basic(void) IActivationFactory *factory; IInspectable *inspectable; IGeolocator *geolocator; + IGeolocator *geolocator2; IWeakReferenceSource *weak_reference_source; + IWeakReference *weak_reference; + IUnknown* unknown; + void *dummy; HSTRING str; HRESULT hr;
@@ -91,9 +95,47 @@ void test_basic(void)
hr = IGeolocator_QueryInterface(geolocator, &IID_IWeakReferenceSource, (void **)&weak_reference_source); ok(hr == S_OK && weak_reference_source, "got hr %#lx.\n", hr); + + hr = IWeakReferenceSource_GetWeakReference(weak_reference_source, &weak_reference); + ok(hr == S_OK && weak_reference, "got hr %#lx.\n", hr); IWeakReferenceSource_Release(weak_reference_source);
+ hr = IWeakReference_Resolve(weak_reference, &IID_IUnknown, (IInspectable **)&unknown); + ok(hr == S_OK && unknown, "got hr %#lx.\n", hr); + hr = IWeakReference_Resolve(weak_reference, &IID_IGeolocator, (IInspectable **)&geolocator2); + ok(hr == S_OK && geolocator2, "got hr %#lx.\n", hr); + hr = IWeakReference_Resolve(weak_reference, &IID_IInspectable, &inspectable); + ok(hr == S_OK && inspectable, "got hr %#lx.\n", hr); + ok((void *)inspectable == (void *)geolocator, "Interfaces are not the same\n"); + ok((void *)unknown == (void *)geolocator, "Interfaces are not the same\n"); + IUnknown_Release(unknown); + IGeolocator_Release(geolocator2); + geolocator2 = 0; + IInspectable_Release(inspectable); + inspectable = 0; + + dummy = (void *)0xdeadbeef; + hr = IWeakReference_Resolve(weak_reference, &IID_IWeakReference, (IInspectable **)&dummy); + ok(hr == E_NOINTERFACE && !dummy, "got hr %#lx.\n", hr); + + check_interface(weak_reference, &IID_IUnknown); + check_interface(weak_reference, &IID_IWeakReference); + hr = IWeakReference_QueryInterface(weak_reference, &IID_IGeolocator, &dummy); + ok(hr == E_NOINTERFACE && !dummy, "got hr %#lx.\n", hr); + hr = IWeakReference_QueryInterface(weak_reference, &IID_IAgileObject, &dummy); + ok(hr == E_NOINTERFACE && !dummy, "got hr %#lx.\n", hr); + hr = IWeakReference_QueryInterface(weak_reference, &IID_IInspectable, &dummy); + ok(hr == E_NOINTERFACE && !dummy, "got hr %#lx.\n", hr); + + /* Free geolocator, weak reference should fail to resolve now */ IGeolocator_Release(geolocator); + + hr = IWeakReference_Resolve(weak_reference, &IID_IGeolocator, (IInspectable **)&geolocator2); + ok(hr == S_OK && !geolocator2, "got hr %#lx.\n", hr); + hr = IWeakReference_Resolve(weak_reference, &IID_IWeakReference, (IInspectable **)&dummy); + ok(hr == S_OK && !dummy, "got hr %#lx.\n", hr); + + IWeakReference_Release(weak_reference); IActivationFactory_Release(factory); }
On Mon Jul 3 09:42:28 2023 +0000, Rémi Bernon wrote:
This will need to be done in an atomic way. You also probably need to respect the iid that is passed. I also suggest to rename `ref` parameter to out, as `ref` is often used for refcount values. You may have a thread B currently releasing the last public reference on the object right after the current thread A checks this. This would result in the thread B seeing Release return 0, indicating the object is now invalid, while the thread A increasing the public ref again to 1, receiving a valid object, which is incorrect. I think this will need to be done this way:
- in Resolve:
if ((ref = InterlockedIncrement(&impl->ref_public)) > 1) hr = IGeolocator_QueryInterface(&impl->IGeolocator_iface, iid, out); else /* invalid object */ { *out = NULL; hr = S_OK; } InterlockedDecrement(&impl->ref_public);
Also now there's an issue as we increase the public refcount here, and we may end up releasing the last public ref. It could either also include the same check as in `geolocator_Release` and release a weak ref as well. Or, perhaps better as it would be more consistent, change `geolocator_AddRef` / `geolocator_Release` to also always add/release a weak reference: 2) in geolocator_AddRef / geolocator_Release:
static ULONG WINAPI geolocator_AddRef(IGeolocator *iface) { struct geolocator *impl = impl_from_IGeolocator(iface); ULONG ref = InterlockedIncrement(&impl->ref_public); 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); TRACE("iface %p decreasing refcount to %lu.\n", iface, ref); IWeakReference_Release(&impl->IWeakReference_iface); return ref; }
I'm a bit tired and this is kinda complicated, so please don't mind if I just rehash the issues real quick to avoid misunderstanding.
You may have a thread B currently releasing the last public reference on the object right after the current thread A checks this. This would result in the thread B seeing Release return 0, indicating the object is now invalid, while the thread A increasing the public ref again to 1, receiving a valid object, which is incorrect.
For clarification, you mean A passing the check `!impl->ref_public` in `Resolve`, then B calling `Release` and getting a 0, while A gets a valid Object. We need to have both calls either fail or succeed. Correct?
Second problem is, when incrementing the count in `Resolve` we could miss that `if (!ref)` in `geolocator_Release`. Right? So we could just always add/release the weak reference in the geolocator.
If I understood all that correctly, that seems reasonable to me. Thanks!
I'm a bit tired and this is kinda complicated, so please don't mind if I just rehash the issues real quick to avoid misunderstanding.
No worries at all.
For clarification, you mean A passing the check `!impl->ref_public` in `Resolve`, then B calling `Release` and getting a 0, while A gets a valid Object. We need to have both calls either fail or succeed. Correct?
Correct.
Second problem is, when incrementing the count in `Resolve` we could miss that `if (!ref)` in `geolocator_Release`. Right? So we could just always add/release the weak reference in the geolocator.
Yes, the alternative solution would be to duplicate the `geolocator_Release` check in `Resolve`, but it gets a bit awkward and error prone.
On Mon Jul 3 19:55:43 2023 +0000, Rémi Bernon wrote:
I'm a bit tired and this is kinda complicated, so please don't mind if
I just rehash the issues real quick to avoid misunderstanding. No worries at all.
For clarification, you mean A passing the check `!impl->ref_public` in
`Resolve`, then B calling `Release` and getting a 0, while A gets a valid Object. We need to have both calls either fail or succeed. Correct? Correct.
Second problem is, when incrementing the count in `Resolve` we could
miss that `if (!ref)` in `geolocator_Release`. Right? So we could just always add/release the weak reference in the geolocator. Yes, the alternative solution would be to duplicate the `geolocator_Release` check in `Resolve`, but it gets a bit awkward and error prone.
Actually I think I missed the case where multiple threads are calling IWeakReference_Resolve concurrently. My suggestion is not behaving correctly there, as increasing public refcount by 1 may make other threads to succeed. Maybe a separate "invalid" field would be better but I need to think about it.
I suggest to leave this aside for now and only include the changes that do not touch weak references yet, I think they look good now.
On Mon Jul 3 20:02:17 2023 +0000, Rémi Bernon wrote:
Actually I think I missed the case where multiple threads are calling IWeakReference_Resolve concurrently. My suggestion is not behaving correctly there, as increasing public refcount by 1 may make other threads to succeed. Maybe a separate "invalid" field would be better but I need to think about it. I suggest to leave this aside for now and only include the changes that do not touch weak references yet, I think they look good now.
What about something like this?
``` for (;;) { ref = impl->ref_public; if (!ref) { *out = NULL; return S_OK; }
/* Only increment when it didn't change since last check */ ref2 = InterlockedCompareExchange(&impl->ref_public, ref + 1, ref);
/* Value change since last check, try again */ if (ref2 != ref) continue;
hr = IGeolocator_QueryInterface(&impl->IGeolocator_iface, iid, (void **)out); InterlockedDecrement(&impl->ref_public); return hr; } ```
This should catch the case where another thread decrements after our check (since the compare exchange fails), the increment only happens when the ref really isn't 0.
On Mon Jul 3 18:25:02 2023 +0000, Fabian Maurer wrote:
Fixed now
Fwiw I only meant that for `configure` changes. You may commit `configure.ac` changes as needed, (although they also can be regenerated by `make_makefiles`).
On Mon Jul 3 20:37:17 2023 +0000, Fabian Maurer wrote:
What about something like this?
for (;;) { ref = impl->ref_public; if (!ref) { *out = NULL; return S_OK; } /* Only increment when it didn't change since last check */ ref2 = InterlockedCompareExchange(&impl->ref_public, ref + 1, ref); /* Value change since last check, try again */ if (ref2 != ref) continue; hr = IGeolocator_QueryInterface(&impl->IGeolocator_iface, iid, (void **)out); InterlockedDecrement(&impl->ref_public); return hr; }
This should catch the case where another thread decrements after our check (since the compare exchange fails), the increment only happens when the ref really isn't 0.
Yes, that should work. I'd avoid unnecessary local variables and compare `InterlockedCompareExchange` result with ref directly. You should also probably do:
`if (!(ref = InterlockedOr(&impl->ref_public, 0)))`
Instead of reading the variable, as it'd otherwise not be an atomic operation.
Note that ideally a weak reference should not own the object data, and the object should be freed as soon as the last public reference is released. As we're implementing it on the same object here it is not possible to release the memory separately, but it's perhaps something to keep in mind.
Especially, if the object keeps any reference to other objects, it should release them in the public `geolocator_Release`, not in `weak_reference_Release`. Only freeing the memory would be delayed.