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:
parent
292d62e3bb
commit
d21dbf960b
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue