quartz/systemclock: Support COM aggregation.

Signed-off-by: Zebediah Figura <z.figura12@gmail.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Zebediah Figura 2019-11-28 17:35:38 -06:00 committed by Alexandre Julliard
parent 292d62e3bb
commit d21dbf960b
2 changed files with 186 additions and 43 deletions

View File

@ -38,7 +38,9 @@ struct advise_sink
struct system_clock struct system_clock
{ {
IReferenceClock IReferenceClock_iface; IReferenceClock IReferenceClock_iface;
LONG ref; IUnknown IUnknown_inner;
IUnknown *outer_unk;
LONG refcount;
BOOL thread_created; BOOL thread_created;
HANDLE thread, notify_event, stop_event; HANDLE thread, notify_event, stop_event;
@ -48,6 +50,72 @@ struct system_clock
struct list sinks; 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) static inline struct system_clock *impl_from_IReferenceClock(IReferenceClock *iface)
{ {
return CONTAINING_RECORD(iface, struct system_clock, 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) static HRESULT WINAPI SystemClockImpl_QueryInterface(IReferenceClock *iface, REFIID iid, void **out)
{ {
struct system_clock *clock = impl_from_IReferenceClock(iface); struct system_clock *clock = impl_from_IReferenceClock(iface);
TRACE("clock %p, iid %s, out %p.\n", clock, debugstr_guid(iid), out); return IUnknown_QueryInterface(clock->outer_unk, 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;
} }
static ULONG WINAPI SystemClockImpl_AddRef(IReferenceClock *iface) static ULONG WINAPI SystemClockImpl_AddRef(IReferenceClock *iface)
{ {
struct system_clock *clock = impl_from_IReferenceClock(iface); struct system_clock *clock = impl_from_IReferenceClock(iface);
ULONG refcount = InterlockedIncrement(&clock->ref); return IUnknown_AddRef(clock->outer_unk);
TRACE("%p increasing refcount to %u.\n", clock, refcount);
return refcount;
} }
static ULONG WINAPI SystemClockImpl_Release(IReferenceClock *iface) static ULONG WINAPI SystemClockImpl_Release(IReferenceClock *iface)
{ {
struct system_clock *clock = impl_from_IReferenceClock(iface); struct system_clock *clock = impl_from_IReferenceClock(iface);
ULONG refcount = InterlockedDecrement(&clock->ref); return IUnknown_Release(clock->outer_unk);
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 HRESULT WINAPI SystemClockImpl_GetTime(IReferenceClock *iface, REFERENCE_TIME *time) 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; return S_FALSE;
} }
static const IReferenceClockVtbl SystemClock_Vtbl = static const IReferenceClockVtbl SystemClock_vtbl =
{ {
SystemClockImpl_QueryInterface, SystemClockImpl_QueryInterface,
SystemClockImpl_AddRef, SystemClockImpl_AddRef,
@ -304,10 +339,16 @@ HRESULT QUARTZ_CreateSystemClock(IUnknown *outer, void **out)
return E_OUTOFMEMORY; 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); list_init(&object->sinks);
InitializeCriticalSection(&object->cs); InitializeCriticalSection(&object->cs);
object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": SystemClockImpl.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;
} }

View File

@ -26,11 +26,18 @@ static ULONGLONG (WINAPI *pGetTickCount64)(void);
static IReferenceClock *create_system_clock(void) static IReferenceClock *create_system_clock(void)
{ {
IReferenceClock *filter = NULL; IReferenceClock *clock = NULL;
HRESULT hr = CoCreateInstance(&CLSID_SystemClock, NULL, CLSCTX_INPROC_SERVER, 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); 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) #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); 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) static void test_get_time(void)
{ {
IReferenceClock *clock = create_system_clock(); IReferenceClock *clock = create_system_clock();
@ -185,6 +286,7 @@ START_TEST(systemclock)
pGetTickCount64 = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetTickCount64"); pGetTickCount64 = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetTickCount64");
test_interfaces(); test_interfaces();
test_aggregation();
test_get_time(); test_get_time();
test_advise(); test_advise();