Signed-off-by: Zebediah Figura z.figura12@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();