Superseded patch 173709.
Signed-off-by: Jactry Zeng <jzeng(a)codeweavers.com>
---
dlls/sapi/tests/tts.c | 24 ++-
dlls/sapi/tts.c | 329 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 352 insertions(+), 1 deletion(-)
diff --git a/dlls/sapi/tests/tts.c b/dlls/sapi/tests/tts.c
index 3b71e933a2..e4b4e79943 100644
--- a/dlls/sapi/tests/tts.c
+++ b/dlls/sapi/tests/tts.c
@@ -36,7 +36,8 @@ static void _expect_ref(IUnknown *obj, ULONG ref, int line)
static void test_interfaces(void)
{
- ISpeechVoice *speech_voice;
+ ISpeechVoice *speech_voice, *speech_voice2;
+ ISpVoice *spvoice, *spvoice2;
IDispatch *dispatch;
IUnknown *unk;
HRESULT hr;
@@ -60,6 +61,27 @@ static void test_interfaces(void)
EXPECT_REF(speech_voice, 1);
IUnknown_Release(unk);
+ hr = CoCreateInstance(&CLSID_SpVoice, NULL, CLSCTX_INPROC_SERVER,
+ &IID_ISpVoice, (void **)&spvoice);
+ ok(hr == S_OK, "Failed to create ISpVoice interface: %#x.\n", hr);
+ EXPECT_REF(spvoice, 1);
+ EXPECT_REF(speech_voice, 1);
+
+ hr = ISpVoice_QueryInterface(spvoice, &IID_ISpeechVoice, (void **)&speech_voice2);
+ ok(hr == S_OK, "ISpVoice_QueryInterface failed: %#x.\n", hr);
+ EXPECT_REF(speech_voice2, 2);
+ EXPECT_REF(spvoice, 2);
+ EXPECT_REF(speech_voice, 1);
+ ISpeechVoice_Release(speech_voice2);
+
+ hr = ISpeechVoice_QueryInterface(speech_voice, &IID_ISpVoice, (void **)&spvoice2);
+ ok(hr == S_OK, "ISpeechVoice_QueryInterface failed: %#x.\n", hr);
+ EXPECT_REF(speech_voice, 2);
+ EXPECT_REF(spvoice2, 2);
+ EXPECT_REF(spvoice, 1);
+ ISpVoice_Release(spvoice2);
+ ISpVoice_Release(spvoice);
+
ISpeechVoice_Release(speech_voice);
}
diff --git a/dlls/sapi/tts.c b/dlls/sapi/tts.c
index 4000db11f5..8f1ecd1894 100644
--- a/dlls/sapi/tts.c
+++ b/dlls/sapi/tts.c
@@ -37,6 +37,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(sapi);
struct speech_voice
{
ISpeechVoice ISpeechVoice_iface;
+ ISpVoice ISpVoice_iface;
LONG ref;
};
@@ -45,6 +46,11 @@ static inline struct speech_voice *impl_from_ISpeechVoice(ISpeechVoice *iface)
return CONTAINING_RECORD(iface, struct speech_voice, ISpeechVoice_iface);
}
+static inline struct speech_voice *impl_from_ISpVoice(ISpVoice *iface)
+{
+ return CONTAINING_RECORD(iface, struct speech_voice, ISpVoice_iface);
+}
+
/* ISpeechVoice interface */
static HRESULT WINAPI speech_voice_QueryInterface(ISpeechVoice *iface, REFIID iid, void **obj)
{
@@ -56,6 +62,8 @@ static HRESULT WINAPI speech_voice_QueryInterface(ISpeechVoice *iface, REFIID ii
IsEqualIID(iid, &IID_IDispatch) ||
IsEqualIID(iid, &IID_ISpeechVoice))
*obj = &This->ISpeechVoice_iface;
+ else if (IsEqualIID(iid, &IID_ISpVoice))
+ *obj = &This->ISpVoice_iface;
else
{
*obj = NULL;
@@ -398,6 +406,326 @@ static const ISpeechVoiceVtbl speech_voice_vtbl =
speech_voice_DisplayUI,
};
+/* ISpVoice interface */
+static HRESULT WINAPI spvoice_QueryInterface(ISpVoice *iface, REFIID iid, void **obj)
+{
+ struct speech_voice *This = impl_from_ISpVoice(iface);
+
+ TRACE("(%p, %s %p).\n", iface, debugstr_guid(iid), obj);
+
+ return ISpeechVoice_QueryInterface(&This->ISpeechVoice_iface, iid, obj);
+}
+
+static ULONG WINAPI spvoice_AddRef(ISpVoice *iface)
+{
+ struct speech_voice *This = impl_from_ISpVoice(iface);
+
+ TRACE("(%p).\n", iface);
+
+ return ISpeechVoice_AddRef(&This->ISpeechVoice_iface);
+}
+
+static ULONG WINAPI spvoice_Release(ISpVoice *iface)
+{
+ struct speech_voice *This = impl_from_ISpVoice(iface);
+
+ TRACE("(%p).\n", iface);
+
+ return ISpeechVoice_Release(&This->ISpeechVoice_iface);
+}
+
+static HRESULT WINAPI spvoice_SetNotifySink(ISpVoice *iface, ISpNotifySink *sink)
+{
+ FIXME("(%p, %p): stub.\n", iface, sink);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI spvoice_SetNotifyWindowMessage(ISpVoice *iface, HWND hwnd, UINT msg,
+ WPARAM wparam, LPARAM lparam)
+{
+ FIXME("(%p, %p, %u, %lx, %lx): stub.\n", iface, hwnd, msg, wparam, lparam);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI spvoice_SetNotifyCallbackFunction(ISpVoice *iface, SPNOTIFYCALLBACK *callback,
+ WPARAM wparam, LPARAM lparam)
+{
+ FIXME("(%p, %p, %lx, %lx): stub.\n", iface, callback, wparam, lparam);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI spvoice_SetNotifyCallbackInterface(ISpVoice *iface, ISpNotifyCallback *callback,
+ WPARAM wparam, LPARAM lparam)
+{
+ FIXME("(%p, %p, %lx, %lx): stub.\n", iface, callback, wparam, lparam);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI spvoice_SetNotifyWin32Event(ISpVoice *iface)
+{
+ FIXME("(%p): stub.\n", iface);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI spvoice_WaitForNotifyEvent(ISpVoice *iface, DWORD milliseconds)
+{
+ FIXME("(%p, %d): stub.\n", iface, milliseconds);
+
+ return E_NOTIMPL;
+}
+
+static HANDLE WINAPI spvoice_GetNotifyEventHandle(ISpVoice *iface)
+{
+ FIXME("(%p): stub.\n", iface);
+
+ return NULL;
+}
+
+static HRESULT WINAPI spvoice_SetInterest(ISpVoice *iface, ULONGLONG event, ULONGLONG queued)
+{
+ FIXME("(%p, %s, %s): stub.\n", iface, wine_dbgstr_longlong(event), wine_dbgstr_longlong(queued));
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI spvoice_GetEvents(ISpVoice *iface, ULONG count, SPEVENT *array, ULONG *fetched)
+{
+ FIXME("(%p, %u, %p, %p): stub.\n", iface, count, array, fetched);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI spvoice_GetInfo(ISpVoice *iface, SPEVENTSOURCEINFO *info)
+{
+ FIXME("(%p, %p): stub.\n", iface, info);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI spvoice_SetOutput(ISpVoice *iface, IUnknown *unk, BOOL changes)
+{
+ FIXME("(%p, %p, %d: stub.\n)", iface, unk, changes);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI spvoice_GetOutputObjectToken(ISpVoice *iface, ISpObjectToken **token)
+{
+ FIXME("(%p, %p): stub.\n", iface, token);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI spvoice_GetOutputStream(ISpVoice *iface, ISpStreamFormat **stream)
+{
+ FIXME("(%p, %p): stub.\n", iface, stream);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI spvoice_Pause(ISpVoice *iface)
+{
+ FIXME("(%p): stub.\n", iface);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI spvoice_Resume(ISpVoice *iface)
+{
+ FIXME("(%p): stub.\n", iface);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI spvoice_SetVoice(ISpVoice *iface, ISpObjectToken *token)
+{
+ FIXME("(%p, %p): stub.\n", iface, token);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI spvoice_GetVoice(ISpVoice *iface, ISpObjectToken **token)
+{
+ FIXME("(%p, %p): stub.\n", iface, token);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI spvoice_Speak(ISpVoice *iface, const WCHAR *contents, DWORD flags, ULONG *number)
+{
+ FIXME("(%p, %p, %#x, %p): stub.\n", iface, contents, flags, number);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI spvoice_SpeakStream(ISpVoice *iface, IStream *stream, DWORD flags, ULONG *number)
+{
+ FIXME("(%p, %p, %#x, %p): stub.\n", iface, stream, flags, number);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI spvoice_GetStatus(ISpVoice *iface, SPVOICESTATUS *status, WCHAR **bookmark)
+{
+ FIXME("(%p, %p, %p): stub.\n", iface, status, bookmark);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI spvoice_Skip(ISpVoice *iface, const WCHAR *type, LONG items, ULONG *skipped)
+{
+ FIXME("(%p, %s, %d, %p): stub.\n", iface, debugstr_w(type), items, skipped);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI spvoice_SetPriority(ISpVoice *iface, SPVPRIORITY priority)
+{
+ FIXME("(%p, %d): stub.\n", iface, priority);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI spvoice_GetPriority(ISpVoice *iface, SPVPRIORITY *priority)
+{
+ FIXME("(%p, %p): stub.\n", iface, priority);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI spvoice_SetAlertBoundary(ISpVoice *iface, SPEVENTENUM boundary)
+{
+ FIXME("(%p, %d): stub.\n", iface, boundary);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI spvoice_GetAlertBoundary(ISpVoice *iface, SPEVENTENUM *boundary)
+{
+ FIXME("(%p, %p): stub.\n", iface, boundary);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI spvoice_SetRate(ISpVoice *iface, LONG adjust)
+{
+ FIXME("(%p, %d): stub.\n", iface, adjust);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI spvoice_GetRate(ISpVoice *iface, LONG *adjust)
+{
+ FIXME("(%p, %p): stub.\n", iface, adjust);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI spvoice_SetVolume(ISpVoice *iface, USHORT volume)
+{
+ FIXME("(%p, %d): stub.\n", iface, volume);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI spvoice_GetVolume(ISpVoice *iface, USHORT *volume)
+{
+ FIXME("(%p, %p): stub.\n", iface, volume);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI spvoice_WaitUntilDone(ISpVoice *iface, ULONG timeout)
+{
+ FIXME("(%p, %d): stub.\n", iface, timeout);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI spvoice_SetSyncSpeakTimeout(ISpVoice *iface, ULONG timeout)
+{
+ FIXME("(%p, %d): stub.\n", iface, timeout);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI spvoice_GetSyncSpeakTimeout(ISpVoice *iface, ULONG *timeout)
+{
+ FIXME("(%p, %p): stub.\n", iface, timeout);
+
+ return E_NOTIMPL;
+}
+
+static HANDLE WINAPI spvoice_SpeakCompleteEvent(ISpVoice *iface)
+{
+ FIXME("(%p): stub.\n", iface);
+
+ return NULL;
+}
+
+static HRESULT WINAPI spvoice_IsUISupported(ISpVoice *iface, const WCHAR *type, void *extra,
+ ULONG count, BOOL *supported)
+{
+ FIXME("(%p, %p, %p, %d, %p): stub.\n", iface, type, extra, count, supported);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI spvoice_DisplayUI(ISpVoice *iface, HWND parent, const WCHAR *title,
+ const WCHAR *type, void *extra, ULONG count)
+{
+ FIXME("(%p, %p, %p, %p, %p, %d): stub.\n", iface, parent, title, type, extra, count);
+
+ return E_NOTIMPL;
+}
+
+static const ISpVoiceVtbl spvoice_vtbl =
+{
+ spvoice_QueryInterface,
+ spvoice_AddRef,
+ spvoice_Release,
+ spvoice_SetNotifySink,
+ spvoice_SetNotifyWindowMessage,
+ spvoice_SetNotifyCallbackFunction,
+ spvoice_SetNotifyCallbackInterface,
+ spvoice_SetNotifyWin32Event,
+ spvoice_WaitForNotifyEvent,
+ spvoice_GetNotifyEventHandle,
+ spvoice_SetInterest,
+ spvoice_GetEvents,
+ spvoice_GetInfo,
+ spvoice_SetOutput,
+ spvoice_GetOutputObjectToken,
+ spvoice_GetOutputStream,
+ spvoice_Pause,
+ spvoice_Resume,
+ spvoice_SetVoice,
+ spvoice_GetVoice,
+ spvoice_Speak,
+ spvoice_SpeakStream,
+ spvoice_GetStatus,
+ spvoice_Skip,
+ spvoice_SetPriority,
+ spvoice_GetPriority,
+ spvoice_SetAlertBoundary,
+ spvoice_GetAlertBoundary,
+ spvoice_SetRate,
+ spvoice_GetRate,
+ spvoice_SetVolume,
+ spvoice_GetVolume,
+ spvoice_WaitUntilDone,
+ spvoice_SetSyncSpeakTimeout,
+ spvoice_GetSyncSpeakTimeout,
+ spvoice_SpeakCompleteEvent,
+ spvoice_IsUISupported,
+ spvoice_DisplayUI
+};
+
HRESULT speech_voice_create(IUnknown *outer, REFIID iid, void **obj)
{
struct speech_voice *This = heap_alloc(sizeof(*This));
@@ -405,6 +733,7 @@ HRESULT speech_voice_create(IUnknown *outer, REFIID iid, void **obj)
if (!This) return E_OUTOFMEMORY;
This->ISpeechVoice_iface.lpVtbl = &speech_voice_vtbl;
+ This->ISpVoice_iface.lpVtbl = &spvoice_vtbl;
This->ref = 1;
hr = ISpeechVoice_QueryInterface(&This->ISpeechVoice_iface, iid, obj);
--
2.24.0