From: Zebediah Figura zfigura@codeweavers.com
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/dsdmo/Makefile.in | 4 + dlls/dsdmo/dsdmo.idl | 27 +++ dlls/dsdmo/main.c | 429 +++++++++++++++++++++++++++++++++++++-- dlls/dsdmo/tests/dsdmo.c | 42 ++-- 4 files changed, 462 insertions(+), 40 deletions(-) create mode 100644 dlls/dsdmo/dsdmo.idl
diff --git a/dlls/dsdmo/Makefile.in b/dlls/dsdmo/Makefile.in index 99816ae0c08..3787415abd6 100644 --- a/dlls/dsdmo/Makefile.in +++ b/dlls/dsdmo/Makefile.in @@ -1,6 +1,10 @@ MODULE = dsdmo.dll +IMPORTS = dmoguids uuid
EXTRADLLFLAGS = -mno-cygwin
C_SRCS = \ main.c + +IDL_SRCS = \ + dsdmo.idl diff --git a/dlls/dsdmo/dsdmo.idl b/dlls/dsdmo/dsdmo.idl new file mode 100644 index 00000000000..a967186af3f --- /dev/null +++ b/dlls/dsdmo/dsdmo.idl @@ -0,0 +1,27 @@ +/* + * Copyright 2020 Zebediah Figura + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#pragma makedep register + +[ + threading(both), + progid("Microsoft.DirectSoundWavesReverbDMO.1"), + vi_progid("Microsoft.DirectSoundWavesReverbDMO"), + uuid(87fc0268-9a55-4360-95aa-004a1d9de26c) +] +coclass DirectSoundWavesReverbDMO {} diff --git a/dlls/dsdmo/main.c b/dlls/dsdmo/main.c index 788381b7a45..44915ca8566 100644 --- a/dlls/dsdmo/main.c +++ b/dlls/dsdmo/main.c @@ -15,9 +15,13 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#define COBJMACROS
-#include "ole2.h" +#define COBJMACROS +#include "dmo.h" +#include "mmreg.h" +#include "mmsystem.h" +#include "initguid.h" +#include "dsound.h" #include "rpcproxy.h"
#include "wine/debug.h" @@ -26,19 +30,318 @@ WINE_DEFAULT_DEBUG_CHANNEL(dsdmo);
static HINSTANCE dsdmo_instance;
-/****************************************************************** - * DllMain - */ -BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, void *reserved) +struct effect +{ + IMediaObject IMediaObject_iface; + IUnknown IUnknown_inner; + IUnknown *outer_unk; + LONG refcount; + + const struct effect_ops *ops; +}; + +struct effect_ops +{ + void *(*query_interface)(struct effect *effect, REFIID iid); + void (*destroy)(struct effect *effect); +}; + +static struct effect *impl_from_IUnknown(IUnknown *iface) +{ + return CONTAINING_RECORD(iface, struct effect, IUnknown_inner); +} + +static HRESULT WINAPI effect_inner_QueryInterface(IUnknown *iface, REFIID iid, void **out) +{ + struct effect *effect = impl_from_IUnknown(iface); + + TRACE("effect %p, iid %s, out %p.\n", effect, debugstr_guid(iid), out); + + if (IsEqualGUID(iid, &IID_IUnknown)) + *out = iface; + else if (IsEqualGUID(iid, &IID_IMediaObject)) + *out = &effect->IMediaObject_iface; + else if (!(*out = effect->ops->query_interface(effect, iid))) + { + WARN("%s not implemented; returning E_NOINTERFACE.\n", debugstr_guid(iid)); + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown *)*out); + return S_OK; +} + +static ULONG WINAPI effect_inner_AddRef(IUnknown *iface) +{ + struct effect *effect = impl_from_IUnknown(iface); + ULONG refcount = InterlockedIncrement(&effect->refcount); + + TRACE("%p increasing refcount to %u.\n", effect, refcount); + return refcount; +} + +static ULONG WINAPI effect_inner_Release(IUnknown *iface) { - TRACE("(%p %d %p)\n", inst, reason, reserved); + struct effect *effect = impl_from_IUnknown(iface); + ULONG refcount = InterlockedDecrement(&effect->refcount); + + TRACE("%p decreasing refcount to %u.\n", effect, refcount); + + if (!refcount) + { + effect->ops->destroy(effect); + } + return refcount; +} + +static const IUnknownVtbl effect_inner_vtbl = +{ + effect_inner_QueryInterface, + effect_inner_AddRef, + effect_inner_Release, +}; + +static struct effect *impl_from_IMediaObject(IMediaObject *iface) +{ + return CONTAINING_RECORD(iface, struct effect, IMediaObject_iface); +} + +static HRESULT WINAPI effect_QueryInterface(IMediaObject *iface, REFIID iid, void **out) +{ + struct effect *effect = impl_from_IMediaObject(iface); + return IUnknown_QueryInterface(effect->outer_unk, iid, out); +} + +static ULONG WINAPI effect_AddRef(IMediaObject *iface) +{ + struct effect *effect = impl_from_IMediaObject(iface); + return IUnknown_AddRef(effect->outer_unk); +} + +static ULONG WINAPI effect_Release(IMediaObject *iface) +{ + struct effect *effect = impl_from_IMediaObject(iface); + return IUnknown_Release(effect->outer_unk); +} + +static HRESULT WINAPI effect_GetStreamCount(IMediaObject *iface, DWORD *input, DWORD *output) +{ + FIXME("iface %p, input %p, output %p, stub!\n", iface, input, output); + return E_NOTIMPL; +}
+static HRESULT WINAPI effect_GetInputStreamInfo(IMediaObject *iface, DWORD index, DWORD *flags) +{ + FIXME("iface %p, index %u, flags %p, stub!\n", iface, index, flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI effect_GetOutputStreamInfo(IMediaObject *iface, DWORD index, DWORD *flags) +{ + FIXME("iface %p, index %u, flags %p, stub!\n", iface, index, flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI effect_GetInputType(IMediaObject *iface, DWORD index, DWORD type_index, DMO_MEDIA_TYPE *type) +{ + FIXME("iface %p, index %u, type_index %u, type %p, stub!\n", iface, index, type_index, type); + return E_NOTIMPL; +} + +static HRESULT WINAPI effect_GetOutputType(IMediaObject *iface, DWORD index, DWORD type_index, DMO_MEDIA_TYPE *type) +{ + FIXME("iface %p, index %u, type_index %u, type %p, stub!\n", iface, index, type_index, type); + return E_NOTIMPL; +} + +static HRESULT WINAPI effect_SetInputType(IMediaObject *iface, DWORD index, const DMO_MEDIA_TYPE *type, DWORD flags) +{ + FIXME("iface %p, index %u, type %p, flags %#x, stub!\n", iface, index, type, flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI effect_SetOutputType(IMediaObject *iface, DWORD index, const DMO_MEDIA_TYPE *type, DWORD flags) +{ + FIXME("iface %p, index %u, type %p, flags %#x, stub!\n", iface, index, type, flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI effect_GetInputCurrentType(IMediaObject *iface, DWORD index, DMO_MEDIA_TYPE *type) +{ + FIXME("iface %p, index %u, type %p, stub!\n", iface, index, type); + return E_NOTIMPL; +} + +static HRESULT WINAPI effect_GetOutputCurrentType(IMediaObject *iface, DWORD index, DMO_MEDIA_TYPE *type) +{ + FIXME("iface %p, index %u, type %p, stub!\n", iface, index, type); + return E_NOTIMPL; +} + +static HRESULT WINAPI effect_GetInputSizeInfo(IMediaObject *iface, DWORD index, + DWORD *size, DWORD *lookahead, DWORD *alignment) +{ + FIXME("iface %p, index %u, size %p, lookahead %p, alignment %p, stub!\n", iface, index, size, lookahead, alignment); + return E_NOTIMPL; +} + +static HRESULT WINAPI effect_GetOutputSizeInfo(IMediaObject *iface, DWORD index, DWORD *size, DWORD *alignment) +{ + FIXME("iface %p, index %u, size %p, alignment %p, stub!\n", iface, index, size, alignment); + return E_NOTIMPL; +} + +static HRESULT WINAPI effect_GetInputMaxLatency(IMediaObject *iface, DWORD index, REFERENCE_TIME *latency) +{ + FIXME("iface %p, index %u, latency %p, stub!\n", iface, index, latency); + return E_NOTIMPL; +} + +static HRESULT WINAPI effect_SetInputMaxLatency(IMediaObject *iface, DWORD index, REFERENCE_TIME latency) +{ + FIXME("iface %p, index %u, latency %s, stub!\n", iface, index, wine_dbgstr_longlong(latency)); + return E_NOTIMPL; +} + +static HRESULT WINAPI effect_Flush(IMediaObject *iface) +{ + FIXME("iface %p, stub!\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI effect_Discontinuity(IMediaObject *iface, DWORD index) +{ + FIXME("iface %p, index %u, stub!\n", iface, index); + return E_NOTIMPL; +} + +static HRESULT WINAPI effect_AllocateStreamingResources(IMediaObject *iface) +{ + FIXME("iface %p, stub!\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI effect_FreeStreamingResources(IMediaObject *iface) +{ + FIXME("iface %p, stub!\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI effect_GetInputStatus(IMediaObject *iface, DWORD index, DWORD *flags) +{ + FIXME("iface %p, index %u, flags %p, stub!\n", iface, index, flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI effect_ProcessInput(IMediaObject *iface, DWORD index, + IMediaBuffer *buffer, DWORD flags, REFERENCE_TIME timestamp, REFERENCE_TIME timelength) +{ + FIXME("iface %p, index %u, buffer %p, flags %#x, timestamp %s, timelength %s, stub!\n", + iface, index, buffer, flags, wine_dbgstr_longlong(timestamp), wine_dbgstr_longlong(timelength)); + return E_NOTIMPL; +} + +static HRESULT WINAPI effect_ProcessOutput(IMediaObject *iface, DWORD flags, + DWORD count, DMO_OUTPUT_DATA_BUFFER *buffers, DWORD *status) +{ + FIXME("iface %p, flags %#x, count %u, buffers %p, status %p, stub!\n", iface, flags, count, buffers, status); + return E_NOTIMPL; +} + +static HRESULT WINAPI effect_Lock(IMediaObject *iface, LONG lock) +{ + FIXME("iface %p, lock %d, stub!\n", iface, lock); + return E_NOTIMPL; +} + +static const IMediaObjectVtbl effect_vtbl = +{ + effect_QueryInterface, + effect_AddRef, + effect_Release, + effect_GetStreamCount, + effect_GetInputStreamInfo, + effect_GetOutputStreamInfo, + effect_GetInputType, + effect_GetOutputType, + effect_SetInputType, + effect_SetOutputType, + effect_GetInputCurrentType, + effect_GetOutputCurrentType, + effect_GetInputSizeInfo, + effect_GetOutputSizeInfo, + effect_GetInputMaxLatency, + effect_SetInputMaxLatency, + effect_Flush, + effect_Discontinuity, + effect_AllocateStreamingResources, + effect_FreeStreamingResources, + effect_GetInputStatus, + effect_ProcessInput, + effect_ProcessOutput, + effect_Lock, +}; + +static void effect_init(struct effect *effect, IUnknown *outer, const struct effect_ops *ops) +{ + effect->outer_unk = outer ? outer : &effect->IUnknown_inner; + effect->refcount = 1; + effect->IUnknown_inner.lpVtbl = &effect_inner_vtbl; + effect->IMediaObject_iface.lpVtbl = &effect_vtbl; + + effect->ops = ops; +} + +struct waves_reverb +{ + struct effect effect; +}; + +static struct waves_reverb *impl_waves_reverb_from_effect(struct effect *iface) +{ + return CONTAINING_RECORD(iface, struct waves_reverb, effect); +} + +static void *waves_reverb_query_interface(struct effect *iface, REFIID iid) +{ + return NULL; +} + +static void waves_reverb_destroy(struct effect *iface) +{ + struct waves_reverb *effect = impl_waves_reverb_from_effect(iface); + + free(effect); +} + +static const struct effect_ops waves_reverb_ops = +{ + .destroy = waves_reverb_destroy, + .query_interface = waves_reverb_query_interface, +}; + +static HRESULT waves_reverb_create(IUnknown *outer, IUnknown **out) +{ + struct waves_reverb *object; + + if (!(object = calloc(1, sizeof(*object)))) + return E_OUTOFMEMORY; + + effect_init(&object->effect, outer, &waves_reverb_ops); + + TRACE("Created waves reverb effect %p.\n", object); + *out = &object->effect.IUnknown_inner; + return S_OK; +} + +BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) +{ switch(reason) { case DLL_WINE_PREATTACH: return FALSE; /* prefer native version */ case DLL_PROCESS_ATTACH: - dsdmo_instance = inst; + dsdmo_instance = instance; DisableThreadLibraryCalls(dsdmo_instance); break; } @@ -46,35 +349,117 @@ BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, void *reserved) return TRUE; }
-/*********************************************************************** - * DllGetClassObject - */ -HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) +struct class_factory { - FIXME("%s %s %p\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); + IClassFactory IClassFactory_iface; + HRESULT (*create_instance)(IUnknown *outer, IUnknown **out); +}; + +static struct class_factory *impl_from_IClassFactory(IClassFactory *iface) +{ + return CONTAINING_RECORD(iface, struct class_factory, IClassFactory_iface); +} + +static HRESULT WINAPI class_factory_QueryInterface(IClassFactory *iface, REFIID iid, void **out) +{ + TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); + + if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IClassFactory)) + { + IClassFactory_AddRef(iface); + *out = iface; + return S_OK; + } + + *out = NULL; + WARN("%s not implemented, returning E_NOINTERFACE\n", debugstr_guid(iid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI class_factory_AddRef(IClassFactory *iface) +{ + return 2; +} + +static ULONG WINAPI class_factory_Release(IClassFactory *iface) +{ + return 1; +} + +static HRESULT WINAPI class_factory_CreateInstance(IClassFactory *iface, + IUnknown *outer, REFIID iid, void **out) +{ + struct class_factory *factory = impl_from_IClassFactory(iface); + IUnknown *unk; + HRESULT hr; + + TRACE("iface %p, outer %p, iid %s, out %p.\n", iface, outer, debugstr_guid(iid), out); + + *out = NULL; + + if (outer && !IsEqualGUID(iid, &IID_IUnknown)) + return E_NOINTERFACE; + + if (SUCCEEDED(hr = factory->create_instance(outer, &unk))) + { + hr = IUnknown_QueryInterface(unk, iid, out); + IUnknown_Release(unk); + } + return hr; +} + +static HRESULT WINAPI class_factory_LockServer(IClassFactory *iface, BOOL lock) +{ + FIXME("lock %d, stub!\n", lock); + return S_OK; +} + +static const IClassFactoryVtbl class_factory_vtbl = +{ + class_factory_QueryInterface, + class_factory_AddRef, + class_factory_Release, + class_factory_CreateInstance, + class_factory_LockServer, +}; + +static struct +{ + const GUID *clsid; + struct class_factory factory; +} +class_factories[] = +{ + {&GUID_DSFX_WAVES_REVERB, {{&class_factory_vtbl}, waves_reverb_create}}, +}; + +HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID iid, void **out) +{ + unsigned int i; + + TRACE("clsid %s, iid %s, out %p.\n", debugstr_guid(clsid), debugstr_guid(iid), out); + + for (i = 0; i < ARRAY_SIZE(class_factories); ++i) + { + if (IsEqualGUID(clsid, class_factories[i].clsid)) + return IClassFactory_QueryInterface(&class_factories[i].factory.IClassFactory_iface, iid, out); + } + + FIXME("%s not available, returning CLASS_E_CLASSNOTAVAILABLE.\n", debugstr_guid(clsid)); return CLASS_E_CLASSNOTAVAILABLE; }
-/*********************************************************************** - * DllCanUnloadNow - */ HRESULT WINAPI DllCanUnloadNow(void) { return S_FALSE; }
-/*********************************************************************** - * DllRegisterServer - */ HRESULT WINAPI DllRegisterServer(void) { TRACE("()\n"); return __wine_register_resources(dsdmo_instance); }
-/*********************************************************************** - * DllUnregisterServer - */ HRESULT WINAPI DllUnregisterServer(void) { TRACE("()\n"); diff --git a/dlls/dsdmo/tests/dsdmo.c b/dlls/dsdmo/tests/dsdmo.c index b8f0932790b..f236c95d43c 100644 --- a/dlls/dsdmo/tests/dsdmo.c +++ b/dlls/dsdmo/tests/dsdmo.c @@ -80,9 +80,7 @@ static void test_aggregation(const GUID *clsid) dmo = (IMediaObject *)0xdeadbeef; hr = CoCreateInstance(clsid, &test_outer, CLSCTX_INPROC_SERVER, &IID_IMediaObject, (void **)&dmo); - todo_wine ok(hr == E_NOINTERFACE, "Got hr %#x.\n", hr); - if (hr != E_NOINTERFACE) - return; + ok(hr == E_NOINTERFACE, "Got hr %#x.\n", hr); ok(!dmo, "Got interface %p.\n", dmo);
hr = CoCreateInstance(clsid, &test_outer, CLSCTX_INPROC_SERVER, @@ -138,9 +136,7 @@ static void test_interfaces(const GUID *clsid, const GUID *iid) ULONG ref;
hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, iid, (void **)&unk); - todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); - if (hr != S_OK) - return; + ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IUnknown_QueryInterface(unk, &IID_IMediaObject, (void **)&unk2); ok(hr == S_OK, "Got hr %#x.\n", hr); @@ -204,9 +200,7 @@ static void test_media_types(const GUID *clsid) };
hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IMediaObject, (void **)&dmo); - todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); - if (hr != S_OK) - return; + ok(hr == S_OK, "Got hr %#x.\n", hr);
build_pcm_format(&wfx, WAVE_FORMAT_PCM, 16, 44100, 2);
@@ -508,18 +502,19 @@ START_TEST(dsdmo) { const GUID *clsid; const GUID *iid; + BOOL todo; } tests[] = { - {&GUID_DSFX_STANDARD_CHORUS, &IID_IDirectSoundFXChorus}, - {&GUID_DSFX_STANDARD_COMPRESSOR, &IID_IDirectSoundFXCompressor}, - {&GUID_DSFX_STANDARD_DISTORTION, &IID_IDirectSoundFXDistortion}, - {&GUID_DSFX_STANDARD_ECHO, &IID_IDirectSoundFXEcho}, - {&GUID_DSFX_STANDARD_FLANGER, &IID_IDirectSoundFXFlanger}, - {&GUID_DSFX_STANDARD_GARGLE, &IID_IDirectSoundFXGargle}, - {&GUID_DSFX_STANDARD_I3DL2REVERB, &IID_IDirectSoundFXI3DL2Reverb}, - {&GUID_DSFX_STANDARD_PARAMEQ, &IID_IDirectSoundFXParamEq}, - {&GUID_DSFX_WAVES_REVERB, &IID_IDirectSoundFXWavesReverb}, + {&GUID_DSFX_STANDARD_CHORUS, &IID_IDirectSoundFXChorus, TRUE}, + {&GUID_DSFX_STANDARD_COMPRESSOR, &IID_IDirectSoundFXCompressor, TRUE}, + {&GUID_DSFX_STANDARD_DISTORTION, &IID_IDirectSoundFXDistortion, TRUE}, + {&GUID_DSFX_STANDARD_ECHO, &IID_IDirectSoundFXEcho, TRUE}, + {&GUID_DSFX_STANDARD_FLANGER, &IID_IDirectSoundFXFlanger, TRUE}, + {&GUID_DSFX_STANDARD_GARGLE, &IID_IDirectSoundFXGargle, TRUE}, + {&GUID_DSFX_STANDARD_I3DL2REVERB, &IID_IDirectSoundFXI3DL2Reverb, TRUE}, + {&GUID_DSFX_STANDARD_PARAMEQ, &IID_IDirectSoundFXParamEq, TRUE}, + {&GUID_DSFX_WAVES_REVERB, &IID_IDirectSoundFXWavesReverb, TRUE}, }; unsigned int i;
@@ -527,6 +522,17 @@ START_TEST(dsdmo)
for (i = 0; i < ARRAY_SIZE(tests); ++i) { + IUnknown *unk; + HRESULT hr; + + hr = CoCreateInstance(tests[i].clsid, NULL, CLSCTX_INPROC_SERVER, tests[i].iid, (void **)&unk); + todo_wine_if(tests[i].todo) ok(hr == S_OK, "Failed to create %s, hr %#x.\n", + debugstr_guid(tests[i].clsid), hr); + if (hr == S_OK) + IUnknown_Release(unk); + else + continue; + test_aggregation(tests[i].clsid); test_interfaces(tests[i].clsid, tests[i].iid); test_media_types(tests[i].clsid);