From: Fabian Maurer dark.shadow4@web.de
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55126 --- .../main.c | 99 +++++++++++++++++-- .../tests/geolocator.c | 42 ++++++++ 2 files changed, 135 insertions(+), 6 deletions(-)
diff --git a/dlls/windows.devices.geolocation.geolocator/main.c b/dlls/windows.devices.geolocation.geolocator/main.c index 96af2713f93..190d5221b1b 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,7 +84,7 @@ 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); return ref; } @@ -90,7 +92,9 @@ static ULONG WINAPI geolocator_AddRef(IGeolocator *iface) 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); + if (!ref) + IWeakReference_Release(&impl->IWeakReference_iface);; TRACE("iface %p decreasing refcount to %lu.\n", iface, ref); return ref; } @@ -216,6 +220,83 @@ 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); + TRACE("iface %p, iid %s, out %p stub.\n", iface, debugstr_guid(iid), out); + + *out = 0; + + if (!impl->ref_public) + { + return S_OK; + } + else + { + if (IsEqualGUID(iid, &IID_IUnknown) || + IsEqualGUID(iid, &IID_IInspectable) || + IsEqualGUID(iid, &IID_IAgileObject) || + IsEqualGUID(iid, &IID_IGeolocator)) + { + *out = (IInspectable*)&impl->IGeolocator_iface; + IInspectable_AddRef(*out); + return S_OK; + } + } + + return E_NOINTERFACE; +} + +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 +322,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 +415,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); }