[PATCH v2 2/2] windows.media.speech: Add stub SpeechSynthesizer class.
Paul Gofman
pgofman at codeweavers.com
Tue Nov 23 14:02:47 CST 2021
Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
v2:
- use calloc / free instead of heap helpers;
- validate supported class name in DllGetActivationFactory and add a test for that;
- also add stub IClosable interface and test querying it.
dlls/windows.media.speech/main.c | 244 ++++++++++++++++++++++-
dlls/windows.media.speech/tests/speech.c | 73 ++++++-
2 files changed, 311 insertions(+), 6 deletions(-)
diff --git a/dlls/windows.media.speech/main.c b/dlls/windows.media.speech/main.c
index e34fa9d16b8..d23b8686f69 100644
--- a/dlls/windows.media.speech/main.c
+++ b/dlls/windows.media.speech/main.c
@@ -171,6 +171,226 @@ static struct voice_information_vector all_voices =
0
};
+struct speech_synthesizer
+{
+ ISpeechSynthesizer ISpeechSynthesizer_iface;
+ IClosable IClosable_iface;
+ LONG ref;
+};
+
+static inline struct speech_synthesizer *impl_from_ISpeechSynthesizer(ISpeechSynthesizer *iface)
+{
+ return CONTAINING_RECORD(iface, struct speech_synthesizer, ISpeechSynthesizer_iface);
+}
+
+static inline struct speech_synthesizer *impl_from_IClosable(IClosable *iface)
+{
+ return CONTAINING_RECORD(iface, struct speech_synthesizer, IClosable_iface);
+}
+
+static HRESULT STDMETHODCALLTYPE speech_synthesizer_QueryInterface(
+ ISpeechSynthesizer *iface, REFIID iid, void **out)
+{
+ struct speech_synthesizer *impl = impl_from_ISpeechSynthesizer(iface);
+
+ TRACE("iface %p, iid %s, out %p stub!\n", iface, debugstr_guid(iid), out);
+
+ if (IsEqualGUID(iid, &IID_IUnknown) ||
+ IsEqualGUID(iid, &IID_IInspectable) ||
+ IsEqualGUID(iid, &IID_ISpeechSynthesizer))
+ {
+ IUnknown_AddRef(iface);
+ *out = iface;
+ return S_OK;
+ }
+
+ if (IsEqualGUID(iid, &IID_IClosable))
+ {
+ IUnknown_AddRef(iface);
+ *out = &impl->IClosable_iface;
+ return S_OK;
+ }
+
+ FIXME("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
+ *out = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG STDMETHODCALLTYPE speech_synthesizer_AddRef(
+ ISpeechSynthesizer *iface)
+{
+ struct speech_synthesizer *impl = impl_from_ISpeechSynthesizer(iface);
+ ULONG ref = InterlockedIncrement(&impl->ref);
+
+ TRACE("iface %p, ref %u.\n", iface, ref);
+
+ return ref;
+}
+
+static ULONG STDMETHODCALLTYPE speech_synthesizer_Release(
+ ISpeechSynthesizer *iface)
+{
+ struct speech_synthesizer *impl = impl_from_ISpeechSynthesizer(iface);
+ ULONG ref = InterlockedDecrement(&impl->ref);
+
+ TRACE("iface %p, ref %u.\n", iface, ref);
+
+ if (!ref)
+ free(impl);
+
+ return ref;
+}
+
+static HRESULT STDMETHODCALLTYPE speech_synthesizer_GetIids(
+ ISpeechSynthesizer *iface, ULONG *iid_count, IID **iids)
+{
+ FIXME("iface %p, iid_count %p, iids %p stub.\n", iface, iid_count, iids);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE speech_synthesizer_GetRuntimeClassName(
+ ISpeechSynthesizer *iface, HSTRING *class_name)
+{
+ FIXME("iface %p, class_name %p stub.\n", iface, class_name);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE speech_synthesizer_GetTrustLevel(
+ ISpeechSynthesizer *iface, TrustLevel *trust_level)
+{
+ FIXME("iface %p, trust_level %p stub.\n", iface, trust_level);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE speech_synthesizer_SynthesizeTextToStreamAsync(ISpeechSynthesizer *iface,
+ HSTRING text, IAsyncOperation_SpeechSynthesisStream **operation)
+{
+ FIXME("iface %p, text %p, operation %p stub.\n", iface, text, operation);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE speech_synthesizer_SynthesizeSsmlToStreamAsync(ISpeechSynthesizer *iface,
+ HSTRING ssml, IAsyncOperation_SpeechSynthesisStream **operation)
+{
+ FIXME("iface %p, text %p, operation %p stub.\n", iface, ssml, operation);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE speech_synthesizer_put_Voice(ISpeechSynthesizer *iface, IVoiceInformation *value)
+{
+ FIXME("iface %p, value %p stub.\n", iface, value);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE speech_synthesizer_get_Voice(ISpeechSynthesizer *iface, IVoiceInformation **value)
+{
+ FIXME("iface %p, value %p stub.\n", iface, value);
+
+ return E_NOTIMPL;
+}
+
+static const struct ISpeechSynthesizerVtbl speech_synthesizer_vtbl =
+{
+ /* IUnknown methods */
+ speech_synthesizer_QueryInterface,
+ speech_synthesizer_AddRef,
+ speech_synthesizer_Release,
+ /* IInspectable methods */
+ speech_synthesizer_GetIids,
+ speech_synthesizer_GetRuntimeClassName,
+ speech_synthesizer_GetTrustLevel,
+ /* ISpeechSynthesizer methods */
+ speech_synthesizer_SynthesizeTextToStreamAsync,
+ speech_synthesizer_SynthesizeSsmlToStreamAsync,
+ speech_synthesizer_put_Voice,
+ speech_synthesizer_get_Voice,
+};
+
+static HRESULT STDMETHODCALLTYPE closable_QueryInterface(
+ IClosable *iface, REFIID iid, void **out)
+{
+ struct speech_synthesizer *impl = impl_from_IClosable(iface);
+
+ return speech_synthesizer_QueryInterface(&impl->ISpeechSynthesizer_iface, iid, out);
+}
+
+static ULONG STDMETHODCALLTYPE closable_AddRef(
+ IClosable *iface)
+{
+ struct speech_synthesizer *impl = impl_from_IClosable(iface);
+ ULONG ref = InterlockedIncrement(&impl->ref);
+
+ TRACE("iface %p, ref %u.\n", iface, ref);
+
+ return ref;
+}
+
+static ULONG STDMETHODCALLTYPE closable_Release(
+ IClosable *iface)
+{
+ struct speech_synthesizer *impl = impl_from_IClosable(iface);
+ ULONG ref = InterlockedDecrement(&impl->ref);
+
+ TRACE("iface %p, ref %u.\n", iface, ref);
+
+ if (!ref)
+ free(impl);
+
+ return ref;
+}
+
+static HRESULT STDMETHODCALLTYPE closable_GetIids(
+ IClosable *iface, ULONG *iid_count, IID **iids)
+{
+ FIXME("iface %p, iid_count %p, iids %p stub.\n", iface, iid_count, iids);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE closable_GetRuntimeClassName(
+ IClosable *iface, HSTRING *class_name)
+{
+ FIXME("iface %p, class_name %p stub.\n", iface, class_name);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE closable_GetTrustLevel(
+ IClosable *iface, TrustLevel *trust_level)
+{
+ FIXME("iface %p, trust_level %p stub.\n", iface, trust_level);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE closable_Close(
+ IClosable *iface)
+{
+ FIXME("iface %p stub.\n", iface);
+
+ return E_NOTIMPL;
+}
+
+static const struct IClosableVtbl closable_vtbl =
+{
+ /* IUnknown methods */
+ closable_QueryInterface,
+ closable_AddRef,
+ closable_Release,
+ /* IInspectable methods */
+ closable_GetIids,
+ closable_GetRuntimeClassName,
+ closable_GetTrustLevel,
+ /* IClosable methods */
+ closable_Close,
+};
+
struct windows_media_speech
{
IActivationFactory IActivationFactory_iface;
@@ -259,8 +479,21 @@ static HRESULT STDMETHODCALLTYPE windows_media_speech_GetTrustLevel(
static HRESULT STDMETHODCALLTYPE windows_media_speech_ActivateInstance(
IActivationFactory *iface, IInspectable **instance)
{
- FIXME("iface %p, instance %p stub!\n", iface, instance);
- return E_NOTIMPL;
+ struct speech_synthesizer *obj;
+
+ TRACE("iface %p, instance %p.\n", iface, instance);
+
+ if (!(obj = calloc(1, sizeof(*obj))))
+ {
+ *instance = NULL;
+ return E_OUTOFMEMORY;
+ }
+
+ obj->ISpeechSynthesizer_iface.lpVtbl = &speech_synthesizer_vtbl;
+ obj->IClosable_iface.lpVtbl = &closable_vtbl;
+ obj->ref = 1;
+ *instance = (IInspectable *)&obj->ISpeechSynthesizer_iface;
+ return S_OK;
}
static const struct IActivationFactoryVtbl activation_factory_vtbl =
@@ -364,6 +597,13 @@ HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **out)
HRESULT WINAPI DllGetActivationFactory(HSTRING classid, IActivationFactory **factory)
{
TRACE("classid %s, factory %p.\n", debugstr_hstring(classid), factory);
+
+ if (lstrcmpW(WindowsGetStringRawBuffer(classid, NULL), L"Windows.Media.SpeechSynthesis.SpeechSynthesizer"))
+ {
+ ERR("Unknown classid %s.\n", debugstr_hstring(classid));
+ return CLASS_E_CLASSNOTAVAILABLE;
+ }
+
*factory = &windows_media_speech.IActivationFactory_iface;
IUnknown_AddRef(*factory);
return S_OK;
diff --git a/dlls/windows.media.speech/tests/speech.c b/dlls/windows.media.speech/tests/speech.c
index c949b35900b..38fd5c90dd0 100644
--- a/dlls/windows.media.speech/tests/speech.c
+++ b/dlls/windows.media.speech/tests/speech.c
@@ -34,19 +34,26 @@
#include "wine/test.h"
+HRESULT WINAPI (*pDllGetActivationFactory)(HSTRING, IActivationFactory **);
+
static void test_SpeechSynthesizer(void)
{
static const WCHAR *speech_synthesizer_name = L"Windows.Media.SpeechSynthesis.SpeechSynthesizer";
-
+ static const WCHAR *speech_synthesizer_name2 = L"windows.media.speechsynthesis.speechsynthesizer";
+ static const WCHAR *unknown_class_name = L"Unknown.Class";
+ IActivationFactory *factory = NULL, *factory2 = NULL;
IVectorView_VoiceInformation *voices = NULL;
IInstalledVoicesStatic *voices_static = NULL;
- IActivationFactory *factory = NULL;
IVoiceInformation *voice;
IInspectable *inspectable = NULL, *tmp_inspectable = NULL;
IAgileObject *agile_object = NULL, *tmp_agile_object = NULL;
- HSTRING str;
+ ISpeechSynthesizer *synthesizer;
+ IClosable *closable;
+ HMODULE hdll;
+ HSTRING str, str2;
HRESULT hr;
UINT32 size;
+ ULONG ref;
hr = RoInitialize(RO_INIT_MULTITHREADED);
ok(hr == S_OK, "RoInitialize failed, hr %#x\n", hr);
@@ -54,9 +61,46 @@ static void test_SpeechSynthesizer(void)
hr = WindowsCreateString(speech_synthesizer_name, wcslen(speech_synthesizer_name), &str);
ok(hr == S_OK, "WindowsCreateString failed, hr %#x\n", hr);
+ hdll = LoadLibraryW(L"windows.media.speech.dll");
+ if (hdll)
+ {
+ pDllGetActivationFactory = (void *)GetProcAddress(hdll, "DllGetActivationFactory");
+ ok(!!pDllGetActivationFactory, "DllGetActivationFactory not found.\n");
+
+ hr = WindowsCreateString(unknown_class_name, wcslen(unknown_class_name), &str2);
+ ok(hr == S_OK, "WindowsCreateString failed, hr %#x\n", hr);
+
+ hr = pDllGetActivationFactory(str2, &factory);
+ ok(hr == CLASS_E_CLASSNOTAVAILABLE, "Got unexpected hr %#x.\n", hr);
+
+ WindowsDeleteString(str2);
+
+ hr = WindowsCreateString(speech_synthesizer_name2, wcslen(speech_synthesizer_name2), &str2);
+ ok(hr == S_OK, "WindowsCreateString failed, hr %#x\n", hr);
+
+ hr = pDllGetActivationFactory(str2, &factory2);
+ ok(hr == CLASS_E_CLASSNOTAVAILABLE, "Got unexpected hr %#x.\n", hr);
+
+ WindowsDeleteString(str2);
+
+ hr = pDllGetActivationFactory(str, &factory2);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ }
+ else
+ {
+ win_skip("Failed to load library, err %u.\n", GetLastError());
+ }
+
hr = RoGetActivationFactory(str, &IID_IActivationFactory, (void **)&factory);
ok(hr == S_OK, "RoGetActivationFactory failed, hr %#x\n", hr);
+ if (hdll)
+ {
+ ok(factory == factory2, "Got unexpected factory %p, factory2 %p.\n", factory, factory2);
+ IActivationFactory_Release(factory2);
+ FreeLibrary(hdll);
+ }
+
hr = IActivationFactory_QueryInterface(factory, &IID_IInspectable, (void **)&inspectable);
ok(hr == S_OK, "IActivationFactory_QueryInterface IID_IInspectable failed, hr %#x\n", hr);
@@ -107,8 +151,29 @@ static void test_SpeechSynthesizer(void)
IAgileObject_Release(agile_object);
IInspectable_Release(inspectable);
- IActivationFactory_Release(factory);
+ hr = IActivationFactory_QueryInterface(factory, &IID_ISpeechSynthesizer, (void **)&synthesizer);
+ ok(hr == E_NOINTERFACE, "Got unexpected hr %#x.\n", hr);
+
+ hr = RoActivateInstance(str, &inspectable);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+
+ hr = IInspectable_QueryInterface(inspectable, &IID_ISpeechSynthesizer, (void **)&synthesizer);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+
+ hr = IInspectable_QueryInterface(inspectable, &IID_IClosable, (void **)&closable);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+
+ ref = IClosable_Release(closable);
+ ok(ref == 2, "Got unexpected ref %u.\n", ref);
+
+ ref = ISpeechSynthesizer_Release(synthesizer);
+ ok(ref == 1, "Got unexpected ref %u.\n", ref);
+
+ ref = IInspectable_Release(inspectable);
+ ok(!ref, "Got unexpected ref %u.\n", ref);
+
+ IActivationFactory_Release(factory);
WindowsDeleteString(str);
RoUninitialize();
--
2.33.1
More information about the wine-devel
mailing list