[PATCH v7 0/2] MR3988: msttsengine: Add stub dll and ISpTTSEngine stub.
-- v7: msttsengine: Add ISpTTSEngine stub. msttsengine: Add stub dll. https://gitlab.winehq.org/wine/wine/-/merge_requests/3988
From: Shaun Ren <sren(a)codeweavers.com> --- configure.ac | 1 + dlls/msttsengine/Makefile.in | 7 ++ dlls/msttsengine/main.c | 124 +++++++++++++++++++++++++ dlls/msttsengine/msttsengine.spec | 4 + dlls/msttsengine/tts.c | 31 +++++++ dlls/msttsengine/ttsengine_classes.idl | 32 +++++++ dlls/msttsengine/ttsengine_private.h | 34 +++++++ loader/wine.inf.in | 2 + 8 files changed, 235 insertions(+) create mode 100644 dlls/msttsengine/Makefile.in create mode 100644 dlls/msttsengine/main.c create mode 100644 dlls/msttsengine/msttsengine.spec create mode 100644 dlls/msttsengine/tts.c create mode 100644 dlls/msttsengine/ttsengine_classes.idl create mode 100644 dlls/msttsengine/ttsengine_private.h diff --git a/configure.ac b/configure.ac index 7229e25dbed..266be3542ee 100644 --- a/configure.ac +++ b/configure.ac @@ -2804,6 +2804,7 @@ WINE_CONFIG_MAKEFILE(dlls/mssign32) WINE_CONFIG_MAKEFILE(dlls/mssip32) WINE_CONFIG_MAKEFILE(dlls/mstask) WINE_CONFIG_MAKEFILE(dlls/mstask/tests) +WINE_CONFIG_MAKEFILE(dlls/msttsengine) WINE_CONFIG_MAKEFILE(dlls/msv1_0) WINE_CONFIG_MAKEFILE(dlls/msvcirt) WINE_CONFIG_MAKEFILE(dlls/msvcirt/tests) diff --git a/dlls/msttsengine/Makefile.in b/dlls/msttsengine/Makefile.in new file mode 100644 index 00000000000..4a949f1671e --- /dev/null +++ b/dlls/msttsengine/Makefile.in @@ -0,0 +1,7 @@ +MODULE = msttsengine.dll +IMPORTS = ole32 + +SOURCES = \ + main.c \ + tts.c \ + ttsengine_classes.idl diff --git a/dlls/msttsengine/main.c b/dlls/msttsengine/main.c new file mode 100644 index 00000000000..19ac8125260 --- /dev/null +++ b/dlls/msttsengine/main.c @@ -0,0 +1,124 @@ +/* MSTTSEngine main file. + * + * Copyright 2023 Shaun Ren for CodeWeavers + * + * 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 + */ + +#include <stdarg.h> + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "initguid.h" +#include "objbase.h" +#include "sapiddk.h" + +#include "wine/debug.h" + +#include "ttsengine_classes.h" +#include "ttsengine_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msttsengine); + +BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) +{ + if (reason == DLL_PROCESS_ATTACH) + { + DisableThreadLibraryCalls(instance); + __wine_init_unix_call(); + } + return TRUE; +} + +struct class_factory +{ + IClassFactory IClassFactory_iface; + HRESULT (*create_instance)(REFIID iid, void **out); +}; + +static inline 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("(%p, %s, %p).\n", iface, debugstr_guid(iid), out); + + if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IClassFactory)) + { + *out = iface; + IClassFactory_AddRef(iface); + return S_OK; + } + + WARN("%s not implemented.\n", debugstr_guid(iid)); + *out = NULL; + 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 **obj) +{ + struct class_factory *This = impl_from_IClassFactory(iface); + + TRACE("(%p, %p, %s, %p).\n", iface, outer, debugstr_guid(iid), obj); + + *obj = NULL; + if (outer) return CLASS_E_NOAGGREGATION; + return This->create_instance(iid, obj); +} + +static HRESULT WINAPI class_factory_LockServer(IClassFactory *iface, BOOL lock) +{ + FIXME("(%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 class_factory ttsengine_cf = {{&class_factory_vtbl}, ttsengine_create}; + +HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID iid, void **obj) +{ + IClassFactory *cf; + + TRACE("(%s, %s, %p).\n", debugstr_guid(clsid), debugstr_guid(iid), obj); + + if (IsEqualCLSID(clsid, &CLSID_MSTTSEngine)) + cf = &ttsengine_cf.IClassFactory_iface; + else + return CLASS_E_CLASSNOTAVAILABLE; + + return IClassFactory_QueryInterface(cf, iid, obj); +} diff --git a/dlls/msttsengine/msttsengine.spec b/dlls/msttsengine/msttsengine.spec new file mode 100644 index 00000000000..b16365d0c9f --- /dev/null +++ b/dlls/msttsengine/msttsengine.spec @@ -0,0 +1,4 @@ +@ stdcall -private DllCanUnloadNow() +@ stdcall -private DllGetClassObject(ptr ptr ptr) +@ stdcall -private DllRegisterServer() +@ stdcall -private DllUnregisterServer() diff --git a/dlls/msttsengine/tts.c b/dlls/msttsengine/tts.c new file mode 100644 index 00000000000..c5fac6800eb --- /dev/null +++ b/dlls/msttsengine/tts.c @@ -0,0 +1,31 @@ +/* + * MSTTSEngine SAPI engine implementation. + * + * Copyright 2023 Shaun Ren for CodeWeavers + * + * 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 + */ + +#include <stdarg.h> + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" + +HRESULT ttsengine_create(REFIID iid, void **obj) +{ + return E_NOTIMPL; +} diff --git a/dlls/msttsengine/ttsengine_classes.idl b/dlls/msttsengine/ttsengine_classes.idl new file mode 100644 index 00000000000..dec2dd7d72e --- /dev/null +++ b/dlls/msttsengine/ttsengine_classes.idl @@ -0,0 +1,32 @@ +/* + * MSTTSEngine classes. + * + * Copyright 2023 Shaun Ren for CodeWeavers + * + * 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 + +[ + uuid(c64501f6-e6e6-451f-a150-25d0839bc510), + helpstring("Microsoft SAPI/SpeechFX TTS Engine Class"), + threading(both) +] +coclass TTSEngineCom +{ + interface ISpTTSEngine; + interface ISpObjectWithToken; +}; diff --git a/dlls/msttsengine/ttsengine_private.h b/dlls/msttsengine/ttsengine_private.h new file mode 100644 index 00000000000..df1389f6182 --- /dev/null +++ b/dlls/msttsengine/ttsengine_private.h @@ -0,0 +1,34 @@ +/* + * MSTTSEngine private header file. + * + * Copyright 2023 Shaun Ren for CodeWeavers + * + * 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 + */ + +#ifndef __WINE_TTSENGINE_PRIVATE_H +#define __WINE_TTSENGINE_PRIVATE_H + +#include <stdbool.h> +#include <stdint.h> +#include "windef.h" +#include "winternl.h" + +#include "wine/unixlib.h" + + +HRESULT ttsengine_create(REFIID iid, void **obj); + +#endif /* __WINE_TTSENGINE_PRIVATE_H */ diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 382808c4876..2ea4d0b25b4 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2145,6 +2145,7 @@ HKLM,%CurrentVersion%\Telephony\Country List\998,"SameAreaRule",,"G" 11,mui, 11,gecko\plugin,npmshtml.dll 11,Speech\Common,sapi.dll +11,Speech\Engines\TTS,msttsengine.dll 11,wbem,mofcomp.exe 11,wbem,wbemdisp.dll 11,wbem,wbemprox.dll @@ -2230,6 +2231,7 @@ HKLM,%CurrentVersion%\Telephony\Country List\998,"SameAreaRule",,"G" 11,,shdocvw.dll 11,gecko\plugin,npmshtml.dll 11,Speech\Common,sapi.dll +11,Speech\Engines\TTS,msttsengine.dll 11,wbem,mofcomp.exe 11,wbem,wbemdisp.dll 11,wbem,wbemprox.dll -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/3988
From: Shaun Ren <sren(a)codeweavers.com> --- dlls/msttsengine/tts.c | 191 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 190 insertions(+), 1 deletion(-) diff --git a/dlls/msttsengine/tts.c b/dlls/msttsengine/tts.c index c5fac6800eb..5effec0e8cf 100644 --- a/dlls/msttsengine/tts.c +++ b/dlls/msttsengine/tts.c @@ -24,8 +24,197 @@ #include "windef.h" #include "winbase.h" +#include "objbase.h" -HRESULT ttsengine_create(REFIID iid, void **obj) +#include "sapiddk.h" +#include "sperror.h" + +#include "wine/debug.h" +#include "wine/heap.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msttsengine); + +struct ttsengine +{ + ISpTTSEngine ISpTTSEngine_iface; + ISpObjectWithToken ISpObjectWithToken_iface; + LONG ref; + + ISpObjectToken *token; +}; + +static inline struct ttsengine *impl_from_ISpTTSEngine(ISpTTSEngine *iface) +{ + return CONTAINING_RECORD(iface, struct ttsengine, ISpTTSEngine_iface); +} + +static inline struct ttsengine *impl_from_ISpObjectWithToken(ISpObjectWithToken *iface) +{ + return CONTAINING_RECORD(iface, struct ttsengine, ISpObjectWithToken_iface); +} + +static HRESULT WINAPI ttsengine_QueryInterface(ISpTTSEngine *iface, REFIID iid, void **obj) +{ + struct ttsengine *This = impl_from_ISpTTSEngine(iface); + + TRACE("(%p)->(%s %p)\n", This, debugstr_guid(iid), obj); + + if (IsEqualIID(iid, &IID_IUnknown) || + IsEqualIID(iid, &IID_ISpTTSEngine)) + { + *obj = &This->ISpTTSEngine_iface; + } + else if (IsEqualIID(iid, &IID_ISpObjectWithToken)) + *obj = &This->ISpObjectWithToken_iface; + else + { + *obj = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown *)*obj); + return S_OK; +} + +static ULONG WINAPI ttsengine_AddRef(ISpTTSEngine *iface) { + struct ttsengine *This = impl_from_ISpTTSEngine(iface); + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) ref=%lu\n", This, ref); + + return ref; +} + +static ULONG WINAPI ttsengine_Release(ISpTTSEngine *iface) +{ + struct ttsengine *This = impl_from_ISpTTSEngine(iface); + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) ref=%lu\n", This, ref); + + if (!ref) + { + if (This->token) ISpObjectToken_Release(This->token); + heap_free(This); + } + + return ref; +} + +static HRESULT WINAPI ttsengine_Speak(ISpTTSEngine *iface, DWORD flags, REFGUID fmtid, + const WAVEFORMATEX *wfx, const SPVTEXTFRAG *frag_list, + ISpTTSEngineSite *site) +{ + FIXME("(%p, %#lx, %s, %p, %p, %p): stub.\n", iface, flags, debugstr_guid(fmtid), wfx, frag_list, site); + return E_NOTIMPL; } + +static HRESULT WINAPI ttsengine_GetOutputFormat(ISpTTSEngine *iface, const GUID *fmtid, + const WAVEFORMATEX *wfx, GUID *out_fmtid, + WAVEFORMATEX **out_wfx) +{ + FIXME("(%p, %s, %p, %p, %p): stub.\n", iface, debugstr_guid(fmtid), wfx, out_fmtid, out_wfx); + + return E_NOTIMPL; +} + +static ISpTTSEngineVtbl ttsengine_vtbl = +{ + ttsengine_QueryInterface, + ttsengine_AddRef, + ttsengine_Release, + ttsengine_Speak, + ttsengine_GetOutputFormat, +}; + +static HRESULT WINAPI objwithtoken_QueryInterface(ISpObjectWithToken *iface, REFIID iid, void **obj) +{ + struct ttsengine *This = impl_from_ISpObjectWithToken(iface); + + TRACE("(%p, %s, %p).\n", iface, debugstr_guid(iid), obj); + + return ISpTTSEngine_QueryInterface(&This->ISpTTSEngine_iface, iid, obj); +} + +static ULONG WINAPI objwithtoken_AddRef(ISpObjectWithToken *iface) +{ + struct ttsengine *This = impl_from_ISpObjectWithToken(iface); + + TRACE("(%p).\n", iface); + + return ISpTTSEngine_AddRef(&This->ISpTTSEngine_iface); +} + +static ULONG WINAPI objwithtoken_Release(ISpObjectWithToken *iface) +{ + struct ttsengine *This = impl_from_ISpObjectWithToken(iface); + + TRACE("(%p).\n", iface); + + return ISpTTSEngine_Release(&This->ISpTTSEngine_iface); +} + +static HRESULT WINAPI objwithtoken_SetObjectToken(ISpObjectWithToken *iface, ISpObjectToken *token) +{ + struct ttsengine *This = impl_from_ISpObjectWithToken(iface); + + FIXME("(%p, %p): semi-stub.\n", iface, token); + + if (!token) + return E_INVALIDARG; + if (This->token) + return SPERR_ALREADY_INITIALIZED; + + ISpObjectToken_AddRef(token); + This->token = token; + return S_OK; +} + +static HRESULT WINAPI objwithtoken_GetObjectToken(ISpObjectWithToken *iface, ISpObjectToken **token) +{ + struct ttsengine *This = impl_from_ISpObjectWithToken(iface); + + TRACE("(%p, %p).\n", iface, token); + + if (!token) + return E_POINTER; + + *token = This->token; + if (*token) + { + ISpObjectToken_AddRef(*token); + return S_OK; + } + else + return S_FALSE; +} + +static const ISpObjectWithTokenVtbl objwithtoken_vtbl = +{ + objwithtoken_QueryInterface, + objwithtoken_AddRef, + objwithtoken_Release, + objwithtoken_SetObjectToken, + objwithtoken_GetObjectToken +}; + +HRESULT ttsengine_create(REFIID iid, void **obj) +{ + struct ttsengine *This; + HRESULT hr; + + if (!(This = heap_alloc(sizeof(*This)))) + return E_OUTOFMEMORY; + + This->ISpTTSEngine_iface.lpVtbl = &ttsengine_vtbl; + This->ISpObjectWithToken_iface.lpVtbl = &objwithtoken_vtbl; + This->ref = 1; + + This->token = NULL; + + hr = ISpTTSEngine_QueryInterface(&This->ISpTTSEngine_iface, iid, obj); + ISpTTSEngine_Release(&This->ISpTTSEngine_iface); + return hr; +} -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/3988
Hi, It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated. The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=139627 Your paranoid android. === debian11 (build log) === ../wine/dlls/msttsengine/main.c:118:30: error: ���CLSID_MSTTSEngine��� undeclared (first use in this function); did you mean ���CLSID_TTSEngineCom���? Task: The win32 Wine build failed === debian11b (build log) === ../wine/dlls/msttsengine/main.c:118:30: error: ���CLSID_MSTTSEngine��� undeclared (first use in this function); did you mean ���CLSID_TTSEngineCom���? Task: The wow64 Wine build failed
participants (3)
-
Marvin -
Shaun Ren -
Shaun Ren (@shaunren)