From: Zebediah Figura Subject: [PATCH v2] mp3dmod: Support COM aggregation. Message-Id: <1529692564-5272-1-git-send-email-zfigura@codeweavers.com> Date: Fri, 22 Jun 2018 13:36:04 -0500 Signed-off-by: Zebediah Figura --- dlls/mp3dmod/mp3dmod.c | 80 ++++++++++++++++++++++++++++++++------------ dlls/mp3dmod/tests/mp3dmod.c | 57 +++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+), 21 deletions(-) diff --git a/dlls/mp3dmod/mp3dmod.c b/dlls/mp3dmod/mp3dmod.c index 4949780..90bcf66 100644 --- a/dlls/mp3dmod/mp3dmod.c +++ b/dlls/mp3dmod/mp3dmod.c @@ -43,7 +43,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(mp3dmod); static HINSTANCE mp3dmod_instance; struct mp3_decoder { + IUnknown IUnknown_inner; IMediaObject IMediaObject_iface; + IUnknown *outer; LONG ref; mpg123_handle *mh; DMO_MEDIA_TYPE outtype; @@ -51,33 +53,35 @@ struct mp3_decoder { REFERENCE_TIME timestamp; }; -static inline struct mp3_decoder *impl_from_IMediaObject(IMediaObject *iface) +static inline struct mp3_decoder *impl_from_IUnknown(IUnknown *iface) { - return CONTAINING_RECORD(iface, struct mp3_decoder, IMediaObject_iface); + return CONTAINING_RECORD(iface, struct mp3_decoder, IUnknown_inner); } -static HRESULT WINAPI MediaObject_QueryInterface(IMediaObject *iface, REFIID iid, void **ppv) +static HRESULT WINAPI Unknown_QueryInterface(IUnknown *iface, REFIID iid, void **obj) { - struct mp3_decoder *This = impl_from_IMediaObject(iface); + struct mp3_decoder *This = impl_from_IUnknown(iface); - TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(iid), ppv); + TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(iid), obj); - if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_IMediaObject)) - *ppv = &This->IMediaObject_iface; + if (IsEqualGUID(iid, &IID_IUnknown)) + *obj = &This->IUnknown_inner; + else if (IsEqualGUID(iid, &IID_IMediaObject)) + *obj = &This->IMediaObject_iface; else { FIXME("no interface for %s\n", debugstr_guid(iid)); - *ppv = NULL; + *obj = NULL; return E_NOINTERFACE; } - IMediaObject_AddRef(iface); + IUnknown_AddRef((IUnknown *)*obj); return S_OK; } -static ULONG WINAPI MediaObject_AddRef(IMediaObject *iface) +static ULONG WINAPI Unknown_AddRef(IUnknown *iface) { - struct mp3_decoder *This = impl_from_IMediaObject(iface); + struct mp3_decoder *This = impl_from_IUnknown(iface); ULONG refcount = InterlockedIncrement(&This->ref); TRACE("(%p) AddRef from %d\n", This, refcount - 1); @@ -85,9 +89,9 @@ static ULONG WINAPI MediaObject_AddRef(IMediaObject *iface) return refcount; } -static ULONG WINAPI MediaObject_Release(IMediaObject *iface) +static ULONG WINAPI Unknown_Release(IUnknown *iface) { - struct mp3_decoder *This = impl_from_IMediaObject(iface); + struct mp3_decoder *This = impl_from_IUnknown(iface); ULONG refcount = InterlockedDecrement(&This->ref); TRACE("(%p) Release from %d\n", This, refcount + 1); @@ -100,6 +104,35 @@ static ULONG WINAPI MediaObject_Release(IMediaObject *iface) return refcount; } +static const IUnknownVtbl Unknown_vtbl = { + Unknown_QueryInterface, + Unknown_AddRef, + Unknown_Release, +}; + +static inline struct mp3_decoder *impl_from_IMediaObject(IMediaObject *iface) +{ + return CONTAINING_RECORD(iface, struct mp3_decoder, IMediaObject_iface); +} + +static HRESULT WINAPI MediaObject_QueryInterface(IMediaObject *iface, REFIID iid, void **obj) +{ + struct mp3_decoder *This = impl_from_IMediaObject(iface); + return IUnknown_QueryInterface(This->outer, iid, obj); +} + +static ULONG WINAPI MediaObject_AddRef(IMediaObject *iface) +{ + struct mp3_decoder *This = impl_from_IMediaObject(iface); + return IUnknown_AddRef(This->outer); +} + +static ULONG WINAPI MediaObject_Release(IMediaObject *iface) +{ + struct mp3_decoder *This = impl_from_IMediaObject(iface); + return IUnknown_Release(This->outer); +} + static HRESULT WINAPI MediaObject_GetStreamCount(IMediaObject *iface, DWORD *input, DWORD *output) { FIXME("(%p)->(%p, %p) stub!\n", iface, input, output); @@ -389,7 +422,7 @@ static HRESULT WINAPI MediaObject_Lock(IMediaObject *iface, LONG lock) return E_NOTIMPL; } -static const IMediaObjectVtbl IMediaObject_vtbl = { +static const IMediaObjectVtbl MediaObject_vtbl = { MediaObject_QueryInterface, MediaObject_AddRef, MediaObject_Release, @@ -416,23 +449,28 @@ static const IMediaObjectVtbl IMediaObject_vtbl = { MediaObject_Lock, }; -static HRESULT create_mp3_decoder(REFIID iid, void **obj) +static HRESULT create_mp3_decoder(IUnknown *outer, REFIID iid, void **obj) { struct mp3_decoder *This; + HRESULT hr; int err; if (!(This = heap_alloc_zero(sizeof(*This)))) return E_OUTOFMEMORY; - This->IMediaObject_iface.lpVtbl = &IMediaObject_vtbl; - This->ref = 0; + This->IUnknown_inner.lpVtbl = &Unknown_vtbl; + This->IMediaObject_iface.lpVtbl = &MediaObject_vtbl; + This->ref = 1; + This->outer = outer ? outer : &This->IUnknown_inner; mpg123_init(); This->mh = mpg123_new(NULL, &err); mpg123_open_feed(This->mh); mpg123_format_none(This->mh); - return IMediaObject_QueryInterface(&This->IMediaObject_iface, iid, obj); + hr = IUnknown_QueryInterface(&This->IUnknown_inner, iid, obj); + IUnknown_Release(&This->IUnknown_inner); + return hr; } static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID iid, void **obj) @@ -466,13 +504,13 @@ static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface, IUnknown { TRACE("(%p, %s, %p)\n", outer, debugstr_guid(iid), obj); - if (outer) + if (outer && !IsEqualGUID(iid, &IID_IUnknown)) { *obj = NULL; - return CLASS_E_NOAGGREGATION; + return E_NOINTERFACE; } - return create_mp3_decoder(iid, obj); + return create_mp3_decoder(outer, iid, obj); } static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL lock) diff --git a/dlls/mp3dmod/tests/mp3dmod.c b/dlls/mp3dmod/tests/mp3dmod.c index 68c6b4d..75fd0e2 100644 --- a/dlls/mp3dmod/tests/mp3dmod.c +++ b/dlls/mp3dmod/tests/mp3dmod.c @@ -230,6 +230,62 @@ static void test_convert(void) IMediaObject_Release(dmo); } +static const GUID IID_test_outer = {0xdeadbeef,0,0,{0,0,0,0,0,0,0,0x66}}; + +static HRESULT WINAPI Outer_QueryInterface(IUnknown *iface, REFIID iid, void **obj) +{ + if (IsEqualGUID(iid, &IID_test_outer)) + { + *obj = (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 2; +} + +static ULONG WINAPI Outer_Release(IUnknown *iface) +{ + return 1; +} + +static IUnknownVtbl Outer_vtbl = { + Outer_QueryInterface, + Outer_AddRef, + Outer_Release, +}; + +static IUnknown Outer = { &Outer_vtbl }; + +static void test_aggregation(void) +{ + IUnknown *unk, *unk2; + IMediaObject *dmo; + HRESULT hr; + + hr = CoCreateInstance(&CLSID_CMP3DecMediaObject, &Outer, CLSCTX_INPROC_SERVER, + &IID_IUnknown, (void **)&unk); + ok(hr == S_OK, "got %#x\n", hr); + + hr = IUnknown_QueryInterface(unk, &IID_IMediaObject, (void **)&dmo); + ok(hr == S_OK, "got %#x\n", hr); + + hr = IMediaObject_QueryInterface(dmo, &IID_test_outer, (void **)&unk2); + ok(hr == S_OK, "got %#x\n", hr); + ok(unk2 == (IUnknown *)0xdeadbeef, "got unk %p\n", unk2); + + IUnknown_Release(dmo); + IUnknown_Release(unk); + + hr = CoCreateInstance(&CLSID_CMP3DecMediaObject, &Outer, CLSCTX_INPROC_SERVER, + &IID_IMediaObject, (void **)&unk); + ok(hr == E_NOINTERFACE, "got %#x\n", hr); +} + START_TEST(mp3dmod) { IMediaObject *dmo; @@ -247,6 +303,7 @@ START_TEST(mp3dmod) IMediaObject_Release(dmo); test_convert(); + test_aggregation(); CoUninitialize(); } -- 2.7.4