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
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
Loading…
Reference in New Issue