[PATCH 1/4] quartz/systemclock: Support COM aggregation.

Zebediah Figura z.figura12 at gmail.com
Thu Nov 28 17:35:38 CST 2019


Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
 dlls/quartz/systemclock.c       | 121 +++++++++++++++++++++-----------
 dlls/quartz/tests/systemclock.c | 108 +++++++++++++++++++++++++++-
 2 files changed, 186 insertions(+), 43 deletions(-)

diff --git a/dlls/quartz/systemclock.c b/dlls/quartz/systemclock.c
index 652008cd01..77e569d437 100644
--- a/dlls/quartz/systemclock.c
+++ b/dlls/quartz/systemclock.c
@@ -38,7 +38,9 @@ struct advise_sink
 struct system_clock
 {
     IReferenceClock IReferenceClock_iface;
-    LONG ref;
+    IUnknown IUnknown_inner;
+    IUnknown *outer_unk;
+    LONG refcount;
 
     BOOL thread_created;
     HANDLE thread, notify_event, stop_event;
@@ -48,6 +50,72 @@ struct system_clock
     struct list sinks;
 };
 
+static inline struct system_clock *impl_from_IUnknown(IUnknown *iface)
+{
+    return CONTAINING_RECORD(iface, struct system_clock, IUnknown_inner);
+}
+
+static HRESULT WINAPI system_clock_inner_QueryInterface(IUnknown *iface, REFIID iid, void **out)
+{
+    struct system_clock *clock = impl_from_IUnknown(iface);
+    TRACE("clock %p, iid %s, out %p.\n", clock, debugstr_guid(iid), out);
+
+    if (IsEqualGUID(iid, &IID_IUnknown))
+        *out = iface;
+    else if (IsEqualGUID(iid, &IID_IReferenceClock))
+        *out = &clock->IReferenceClock_iface;
+    else
+    {
+        WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
+        *out = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown *)*out);
+    return S_OK;
+}
+
+static ULONG WINAPI system_clock_inner_AddRef(IUnknown *iface)
+{
+    struct system_clock *clock = impl_from_IUnknown(iface);
+    ULONG refcount = InterlockedIncrement(&clock->refcount);
+
+    TRACE("%p increasing refcount to %u.\n", clock, refcount);
+
+    return refcount;
+}
+
+static ULONG WINAPI system_clock_inner_Release(IUnknown *iface)
+{
+    struct system_clock *clock = impl_from_IUnknown(iface);
+    ULONG refcount = InterlockedDecrement(&clock->refcount);
+
+    TRACE("%p decreasing refcount to %u.\n", clock, refcount);
+
+    if (!refcount)
+    {
+        if (clock->thread)
+        {
+            SetEvent(clock->stop_event);
+            WaitForSingleObject(clock->thread, INFINITE);
+            CloseHandle(clock->thread);
+            CloseHandle(clock->notify_event);
+            CloseHandle(clock->stop_event);
+        }
+        clock->cs.DebugInfo->Spare[0] = 0;
+        DeleteCriticalSection(&clock->cs);
+        heap_free(clock);
+    }
+    return refcount;
+}
+
+static const IUnknownVtbl system_clock_inner_vtbl =
+{
+    system_clock_inner_QueryInterface,
+    system_clock_inner_AddRef,
+    system_clock_inner_Release,
+};
+
 static inline struct system_clock *impl_from_IReferenceClock(IReferenceClock *iface)
 {
     return CONTAINING_RECORD(iface, struct system_clock, IReferenceClock_iface);
@@ -112,52 +180,19 @@ static void notify_thread(struct system_clock *clock)
 static HRESULT WINAPI SystemClockImpl_QueryInterface(IReferenceClock *iface, REFIID iid, void **out)
 {
     struct system_clock *clock = impl_from_IReferenceClock(iface);
-    TRACE("clock %p, iid %s, out %p.\n", clock, debugstr_guid(iid), out);
-
-    if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IReferenceClock))
-    {
-        IReferenceClock_AddRef(iface);
-        *out = iface;
-        return S_OK;
-    }
-
-    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
-    *out = NULL;
-    return E_NOINTERFACE;
+    return IUnknown_QueryInterface(clock->outer_unk, iid, out);
 }
 
 static ULONG WINAPI SystemClockImpl_AddRef(IReferenceClock *iface)
 {
     struct system_clock *clock = impl_from_IReferenceClock(iface);
-    ULONG refcount = InterlockedIncrement(&clock->ref);
-
-    TRACE("%p increasing refcount to %u.\n", clock, refcount);
-
-    return refcount;
+    return IUnknown_AddRef(clock->outer_unk);
 }
 
 static ULONG WINAPI SystemClockImpl_Release(IReferenceClock *iface)
 {
     struct system_clock *clock = impl_from_IReferenceClock(iface);
-    ULONG refcount = InterlockedDecrement(&clock->ref);
-
-    TRACE("%p decreasing refcount to %u.\n", clock, refcount);
-
-    if (!refcount)
-    {
-        if (clock->thread)
-        {
-            SetEvent(clock->stop_event);
-            WaitForSingleObject(clock->thread, INFINITE);
-            CloseHandle(clock->thread);
-            CloseHandle(clock->notify_event);
-            CloseHandle(clock->stop_event);
-        }
-        clock->cs.DebugInfo->Spare[0] = 0;
-        DeleteCriticalSection(&clock->cs);
-        heap_free(clock);
-    }
-    return refcount;
+    return IUnknown_Release(clock->outer_unk);
 }
 
 static HRESULT WINAPI SystemClockImpl_GetTime(IReferenceClock *iface, REFERENCE_TIME *time)
@@ -281,7 +316,7 @@ static HRESULT WINAPI SystemClockImpl_Unadvise(IReferenceClock *iface, DWORD_PTR
     return S_FALSE;
 }
 
-static const IReferenceClockVtbl SystemClock_Vtbl = 
+static const IReferenceClockVtbl SystemClock_vtbl =
 {
     SystemClockImpl_QueryInterface,
     SystemClockImpl_AddRef,
@@ -304,10 +339,16 @@ HRESULT QUARTZ_CreateSystemClock(IUnknown *outer, void **out)
         return E_OUTOFMEMORY;
     }
 
-    object->IReferenceClock_iface.lpVtbl = &SystemClock_Vtbl;
+    object->IReferenceClock_iface.lpVtbl = &SystemClock_vtbl;
+    object->IUnknown_inner.lpVtbl = &system_clock_inner_vtbl;
+    object->outer_unk = outer ? outer : &object->IUnknown_inner;
+    object->refcount = 1;
     list_init(&object->sinks);
     InitializeCriticalSection(&object->cs);
     object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": SystemClockImpl.cs");
 
-    return SystemClockImpl_QueryInterface(&object->IReferenceClock_iface, &IID_IReferenceClock, out);
+    TRACE("Created system clock %p.\n", object);
+    *out = &object->IUnknown_inner;
+
+    return S_OK;
 }
diff --git a/dlls/quartz/tests/systemclock.c b/dlls/quartz/tests/systemclock.c
index fa1ab6856b..08faa1ef73 100644
--- a/dlls/quartz/tests/systemclock.c
+++ b/dlls/quartz/tests/systemclock.c
@@ -26,11 +26,18 @@ static ULONGLONG (WINAPI *pGetTickCount64)(void);
 
 static IReferenceClock *create_system_clock(void)
 {
-    IReferenceClock *filter = NULL;
+    IReferenceClock *clock = NULL;
     HRESULT hr = CoCreateInstance(&CLSID_SystemClock, NULL, CLSCTX_INPROC_SERVER,
-            &IID_IReferenceClock, (void **)&filter);
+            &IID_IReferenceClock, (void **)&clock);
     ok(hr == S_OK, "Got hr %#x.\n", hr);
-    return filter;
+    return clock;
+}
+
+static ULONG get_refcount(void *iface)
+{
+    IUnknown *unknown = iface;
+    IUnknown_AddRef(unknown);
+    return IUnknown_Release(unknown);
 }
 
 #define check_interface(a, b, c) check_interface_(__LINE__, a, b, c)
@@ -62,6 +69,100 @@ static void test_interfaces(void)
     ok(!ref, "Got outstanding refcount %d.\n", ref);
 }
 
+static const GUID test_iid = {0x33333333};
+static LONG outer_ref = 1;
+
+static HRESULT WINAPI outer_QueryInterface(IUnknown *iface, REFIID iid, void **out)
+{
+    if (IsEqualGUID(iid, &IID_IUnknown)
+            || IsEqualGUID(iid, &IID_IReferenceClock)
+            || IsEqualGUID(iid, &test_iid))
+    {
+        *out = (IUnknown *)0xdeadbeef;
+        return S_OK;
+    }
+    ok(0, "unexpected call %s\n", wine_dbgstr_guid(iid));
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI outer_AddRef(IUnknown *iface)
+{
+    return InterlockedIncrement(&outer_ref);
+}
+
+static ULONG WINAPI outer_Release(IUnknown *iface)
+{
+    return InterlockedDecrement(&outer_ref);
+}
+
+static const IUnknownVtbl outer_vtbl =
+{
+    outer_QueryInterface,
+    outer_AddRef,
+    outer_Release,
+};
+
+static IUnknown test_outer = {&outer_vtbl};
+
+static void test_aggregation(void)
+{
+    IReferenceClock *clock, *clock2;
+    IUnknown *unk, *unk2;
+    HRESULT hr;
+    ULONG ref;
+
+    clock = (IReferenceClock *)0xdeadbeef;
+    hr = CoCreateInstance(&CLSID_SystemClock, &test_outer, CLSCTX_INPROC_SERVER,
+            &IID_IReferenceClock, (void **)&clock);
+    ok(hr == E_NOINTERFACE, "Got hr %#x.\n", hr);
+    ok(!clock, "Got interface %p.\n", clock);
+
+    hr = CoCreateInstance(&CLSID_SystemClock, &test_outer, CLSCTX_INPROC_SERVER,
+            &IID_IUnknown, (void **)&unk);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref);
+    ok(unk != &test_outer, "Returned IUnknown should not be outer IUnknown.\n");
+    ref = get_refcount(unk);
+    ok(ref == 1, "Got unexpected refcount %d.\n", ref);
+
+    ref = IUnknown_AddRef(unk);
+    ok(ref == 2, "Got unexpected refcount %d.\n", ref);
+    ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref);
+
+    ref = IUnknown_Release(unk);
+    ok(ref == 1, "Got unexpected refcount %d.\n", ref);
+    ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref);
+
+    hr = IUnknown_QueryInterface(unk, &IID_IUnknown, (void **)&unk2);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    ok(unk2 == unk, "Got unexpected IUnknown %p.\n", unk2);
+    IUnknown_Release(unk2);
+
+    hr = IUnknown_QueryInterface(unk, &IID_IReferenceClock, (void **)&clock);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+    hr = IReferenceClock_QueryInterface(clock, &IID_IUnknown, (void **)&unk2);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    ok(unk2 == (IUnknown *)0xdeadbeef, "Got unexpected IUnknown %p.\n", unk2);
+
+    hr = IReferenceClock_QueryInterface(clock, &IID_IReferenceClock, (void **)&clock2);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    ok(clock2 == (IReferenceClock *)0xdeadbeef, "Got unexpected IReferenceClock %p.\n", clock2);
+
+    hr = IUnknown_QueryInterface(unk, &test_iid, (void **)&unk2);
+    ok(hr == E_NOINTERFACE, "Got hr %#x.\n", hr);
+    ok(!unk2, "Got unexpected IUnknown %p.\n", unk2);
+
+    hr = IReferenceClock_QueryInterface(clock, &test_iid, (void **)&unk2);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    ok(unk2 == (IUnknown *)0xdeadbeef, "Got unexpected IUnknown %p.\n", unk2);
+
+    IReferenceClock_Release(clock);
+    ref = IUnknown_Release(unk);
+    ok(!ref, "Got unexpected refcount %d.\n", ref);
+    ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref);
+}
+
 static void test_get_time(void)
 {
     IReferenceClock *clock = create_system_clock();
@@ -185,6 +286,7 @@ START_TEST(systemclock)
     pGetTickCount64 = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetTickCount64");
 
     test_interfaces();
+    test_aggregation();
     test_get_time();
     test_advise();
 
-- 
2.24.0




More information about the wine-devel mailing list