Signed-off-by: Bernhard Kölbl besentv@gmail.com --- dlls/windows.media.speech/listconstraint.c | 14 ++++++++++---- dlls/windows.media.speech/tests/speech.c | 8 ++++---- 2 files changed, 14 insertions(+), 8 deletions(-)
diff --git a/dlls/windows.media.speech/listconstraint.c b/dlls/windows.media.speech/listconstraint.c index 33fe9d4ae51..d641902f4bc 100644 --- a/dlls/windows.media.speech/listconstraint.c +++ b/dlls/windows.media.speech/listconstraint.c @@ -34,6 +34,8 @@ struct list_constraint ISpeechRecognitionListConstraint ISpeechRecognitionListConstraint_iface; ISpeechRecognitionConstraint ISpeechRecognitionConstraint_iface; LONG ref; + + BOOLEAN enabled; };
/* @@ -142,14 +144,18 @@ DEFINE_IINSPECTABLE(constraint, ISpeechRecognitionConstraint, struct list_constr
static HRESULT WINAPI constraint_get_IsEnabled( ISpeechRecognitionConstraint *iface, BOOLEAN *value ) { - FIXME("iface %p, value %p stub!\n", iface, value); - return E_NOTIMPL; + struct list_constraint *impl = impl_from_ISpeechRecognitionConstraint(iface); + TRACE("iface %p, value %p.\n", iface, value); + *value = impl->enabled; + return S_OK; }
static HRESULT WINAPI constraint_put_IsEnabled( ISpeechRecognitionConstraint *iface, BOOLEAN value ) { - FIXME("iface %p, value %u stub!\n", iface, value); - return E_NOTIMPL; + struct list_constraint *impl = impl_from_ISpeechRecognitionConstraint(iface); + TRACE("iface %p, value %u.\n", iface, value); + impl->enabled = value; + return S_OK; }
static HRESULT WINAPI constraint_get_Tag( ISpeechRecognitionConstraint *iface, HSTRING *value ) diff --git a/dlls/windows.media.speech/tests/speech.c b/dlls/windows.media.speech/tests/speech.c index a88b8aae3d2..66869a164d2 100644 --- a/dlls/windows.media.speech/tests/speech.c +++ b/dlls/windows.media.speech/tests/speech.c @@ -797,13 +797,13 @@ static void test_SpeechRecognitionListConstraint(void) hr = WindowsDeleteString(tag_out); todo_wine ok(hr == S_OK, "WindowsDeleteString failed, hr %#lx.\n", hr);
+skip_tests: hr = ISpeechRecognitionConstraint_put_IsEnabled(constraint, TRUE); - todo_wine ok(hr == S_OK, "ISpeechRecognitionConstraint_put_IsEnabled failed, hr %#lx.\n", hr); + ok(hr == S_OK, "ISpeechRecognitionConstraint_put_IsEnabled failed, hr %#lx.\n", hr); hr = ISpeechRecognitionConstraint_get_IsEnabled(constraint, &enabled); - todo_wine ok(hr == S_OK, "ISpeechRecognitionConstraint_get_IsEnabled failed, hr %#lx.\n", hr); - todo_wine ok(enabled, "ListConstraint didn't get enabled.\n"); + ok(hr == S_OK, "ISpeechRecognitionConstraint_get_IsEnabled failed, hr %#lx.\n", hr); + ok(enabled, "ListConstraint didn't get enabled.\n");
-skip_tests: ref = ISpeechRecognitionConstraint_Release(constraint); ok(ref == 1, "Got unexpected ref %lu.\n", ref);
Signed-off-by: Bernhard Kölbl besentv@gmail.com --- dlls/windows.media.speech/recognizer.c | 202 ++++++++++++++++++++++++- 1 file changed, 197 insertions(+), 5 deletions(-)
diff --git a/dlls/windows.media.speech/recognizer.c b/dlls/windows.media.speech/recognizer.c index 490493850c8..8819a46d5ba 100644 --- a/dlls/windows.media.speech/recognizer.c +++ b/dlls/windows.media.speech/recognizer.c @@ -23,6 +23,189 @@
WINE_DEFAULT_DEBUG_CHANNEL(speech);
+/* + * + * SpeechContinuousRecognitionSession + * + */ + +struct session +{ + ISpeechContinuousRecognitionSession ISpeechContinuousRecognitionSession_iface; + LONG ref; +}; + +/* + * + * ISpeechContinuousRecognitionSession + * + */ + +static inline struct session *impl_from_ISpeechContinuousRecognitionSession( ISpeechContinuousRecognitionSession *iface ) +{ + return CONTAINING_RECORD(iface, struct session, ISpeechContinuousRecognitionSession_iface); +} + +static HRESULT WINAPI session_QueryInterface( ISpeechContinuousRecognitionSession *iface, REFIID iid, void **out ) +{ + struct session *impl = impl_from_ISpeechContinuousRecognitionSession(iface); + + TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); + + if (IsEqualGUID(iid, &IID_IUnknown) || + IsEqualGUID(iid, &IID_IInspectable) || + IsEqualGUID(iid, &IID_ISpeechContinuousRecognitionSession)) + { + IInspectable_AddRef((*out = &impl->ISpeechContinuousRecognitionSession_iface)); + return S_OK; + } + + WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI session_AddRef( ISpeechContinuousRecognitionSession *iface ) +{ + struct session *impl = impl_from_ISpeechContinuousRecognitionSession(iface); + ULONG ref = InterlockedIncrement(&impl->ref); + TRACE("iface %p, ref %lu.\n", iface, ref); + return ref; +} + +static ULONG WINAPI session_Release( ISpeechContinuousRecognitionSession *iface ) +{ + struct session *impl = impl_from_ISpeechContinuousRecognitionSession(iface); + ULONG ref = InterlockedDecrement(&impl->ref); + TRACE("iface %p, ref %lu.\n", iface, ref); + + if (!ref) + free(impl); + + return ref; +} + +static HRESULT WINAPI session_GetIids( ISpeechContinuousRecognitionSession *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 WINAPI session_GetRuntimeClassName( ISpeechContinuousRecognitionSession *iface, HSTRING *class_name ) +{ + FIXME("iface %p, class_name %p stub!\n", iface, class_name); + return E_NOTIMPL; +} + +static HRESULT WINAPI session_GetTrustLevel( ISpeechContinuousRecognitionSession *iface, TrustLevel *trust_level ) +{ + FIXME("iface %p, trust_level %p stub!\n", iface, trust_level); + return E_NOTIMPL; +} + +static HRESULT WINAPI session_get_AutoStopSilenceTimeout( ISpeechContinuousRecognitionSession *iface, TimeSpan *value ) +{ + FIXME("iface %p, value %p stub!\n", iface, value); + return E_NOTIMPL; +} + +static HRESULT WINAPI session_set_AutoStopSilenceTimeout( ISpeechContinuousRecognitionSession *iface, TimeSpan value ) +{ + FIXME("iface %p, value %#I64x stub!\n", iface, value.Duration); + return E_NOTIMPL; +} + +static HRESULT WINAPI session_StartAsync( ISpeechContinuousRecognitionSession *iface, IAsyncAction **action ) +{ + FIXME("iface %p, action %p semi stub!\n", iface, action); + return E_NOTIMPL; +} + +static HRESULT WINAPI session_StartWithModeAsync( ISpeechContinuousRecognitionSession *iface, + SpeechContinuousRecognitionMode mode, + IAsyncAction **action ) +{ + FIXME("iface %p, mode %u, action %p stub!\n", iface, mode, action); + return E_NOTIMPL; +} + +static HRESULT WINAPI session_StopAsync( ISpeechContinuousRecognitionSession *iface, IAsyncAction **action ) +{ + FIXME("iface %p, action %p stub!\n", iface, action); + return E_NOTIMPL; +} + +static HRESULT WINAPI session_CancelAsync( ISpeechContinuousRecognitionSession *iface, IAsyncAction **action ) +{ + FIXME("iface %p, action %p stub!\n", iface, action); + return E_NOTIMPL; +} + +static HRESULT WINAPI session_PauseAsync( ISpeechContinuousRecognitionSession *iface, IAsyncAction **action ) +{ + FIXME("iface %p, action %p stub!\n", iface, action); + return E_NOTIMPL; +} + +static HRESULT WINAPI session_Resume( ISpeechContinuousRecognitionSession *iface ) +{ + FIXME("iface %p stub!\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI session_add_Completed( ISpeechContinuousRecognitionSession *iface, + ITypedEventHandler_SpeechContinuousRecognitionSession_SpeechContinuousRecognitionCompletedEventArgs *handler, + EventRegistrationToken *token ) +{ + FIXME("iface %p, handler %p, token %p stub!\n", iface, handler, token); + return E_NOTIMPL; +} + +static HRESULT WINAPI session_remove_Completed( ISpeechContinuousRecognitionSession *iface, EventRegistrationToken token ) +{ + FIXME("iface %p, token.value %#I64x stub!\n", iface, token.value); + return E_NOTIMPL; +} + +static HRESULT WINAPI session_add_ResultGenerated( ISpeechContinuousRecognitionSession *iface, + ITypedEventHandler_SpeechContinuousRecognitionSession_SpeechContinuousRecognitionResultGeneratedEventArgs *handler, + EventRegistrationToken *token) +{ + FIXME("iface %p, handler %p, token %p stub!\n", iface, handler, token); + return E_NOTIMPL; +} + +static HRESULT WINAPI session_remove_ResultGenerated( ISpeechContinuousRecognitionSession *iface, EventRegistrationToken token ) +{ + FIXME("iface %p, token.value %#I64x stub!\n", iface, token.value); + return E_NOTIMPL; +} + +static const struct ISpeechContinuousRecognitionSessionVtbl session_vtbl = +{ + /* IUnknown methods */ + session_QueryInterface, + session_AddRef, + session_Release, + /* IInspectable methods */ + session_GetIids, + session_GetRuntimeClassName, + session_GetTrustLevel, + /* ISpeechContinuousRecognitionSession methods */ + session_get_AutoStopSilenceTimeout, + session_set_AutoStopSilenceTimeout, + session_StartAsync, + session_StartWithModeAsync, + session_StopAsync, + session_CancelAsync, + session_PauseAsync, + session_Resume, + session_add_Completed, + session_remove_Completed, + session_add_ResultGenerated, + session_remove_ResultGenerated +}; + /* * * SpeechRecognizer @@ -35,6 +218,8 @@ struct recognizer IClosable IClosable_iface; ISpeechRecognizer2 ISpeechRecognizer2_iface; LONG ref; + + ISpeechContinuousRecognitionSession *session; };
/* @@ -96,7 +281,10 @@ static ULONG WINAPI recognizer_Release( ISpeechRecognizer *iface ) TRACE("iface %p, ref %lu.\n", iface, ref);
if (!ref) + { + ISpeechContinuousRecognitionSession_Release(impl->session); free(impl); + }
return ref; } @@ -433,21 +621,25 @@ DEFINE_IINSPECTABLE(recognizer_factory, ISpeechRecognizerFactory, struct recogni static HRESULT WINAPI recognizer_factory_Create( ISpeechRecognizerFactory *iface, ILanguage *language, ISpeechRecognizer **speechrecognizer ) { struct recognizer *impl; + struct session *session;
TRACE("iface %p, language %p, speechrecognizer %p.\n", iface, language, speechrecognizer);
- if (!(impl = calloc(1, sizeof(*impl)))) - { - *speechrecognizer = NULL; - return E_OUTOFMEMORY; - } + *speechrecognizer = NULL; + + if (!(impl = calloc(1, sizeof(*impl)))) return E_OUTOFMEMORY; + if (!(session = calloc(1, sizeof(*session)))) return E_OUTOFMEMORY;
if (language) FIXME("language parameter unused. Stub!\n");
+ session->ISpeechContinuousRecognitionSession_iface.lpVtbl = &session_vtbl; + session->ref = 1; + impl->ISpeechRecognizer_iface.lpVtbl = &speech_recognizer_vtbl; impl->IClosable_iface.lpVtbl = &closable_vtbl; impl->ISpeechRecognizer2_iface.lpVtbl = &speech_recognizer2_vtbl; + impl->session = &session->ISpeechContinuousRecognitionSession_iface; impl->ref = 1;
TRACE("created SpeechRecognizer %p.\n", impl);
Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
Signing it off because I don't think it's ever going to happen but you're leaking impl when session fails to allocate there:
- if (!(impl = calloc(1, sizeof(*impl)))) return E_OUTOFMEMORY;
- if (!(session = calloc(1, sizeof(*session)))) return E_OUTOFMEMORY;
Signed-off-by: Bernhard Kölbl besentv@gmail.com --- dlls/windows.media.speech/recognizer.c | 6 ++++-- dlls/windows.media.speech/tests/speech.c | 9 +++++++++ 2 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/dlls/windows.media.speech/recognizer.c b/dlls/windows.media.speech/recognizer.c index 8819a46d5ba..47c6e62f417 100644 --- a/dlls/windows.media.speech/recognizer.c +++ b/dlls/windows.media.speech/recognizer.c @@ -443,8 +443,10 @@ DEFINE_IINSPECTABLE(recognizer2, ISpeechRecognizer2, struct recognizer, ISpeechR static HRESULT WINAPI recognizer2_get_ContinuousRecognitionSession( ISpeechRecognizer2 *iface, ISpeechContinuousRecognitionSession **session ) { - FIXME("iface %p, session %p stub!\n", iface, session); - return E_NOTIMPL; + struct recognizer *impl = impl_from_ISpeechRecognizer2(iface); + TRACE("iface %p, session %p.\n", iface, session); + ISpeechContinuousRecognitionSession_QueryInterface(impl->session, &IID_ISpeechContinuousRecognitionSession, (void **)session); + return S_OK; }
static HRESULT WINAPI recognizer2_get_State( ISpeechRecognizer2 *iface, SpeechRecognizerState *state ) diff --git a/dlls/windows.media.speech/tests/speech.c b/dlls/windows.media.speech/tests/speech.c index 66869a164d2..e22ab35928e 100644 --- a/dlls/windows.media.speech/tests/speech.c +++ b/dlls/windows.media.speech/tests/speech.c @@ -569,6 +569,7 @@ static void test_VoiceInformation(void) static void test_SpeechRecognizer(void) { static const WCHAR *speech_recognition_name = L"Windows.Media.SpeechRecognition.SpeechRecognizer"; + ISpeechContinuousRecognitionSession *session = NULL; ISpeechRecognizerFactory *sr_factory = NULL; ISpeechRecognizerStatics *sr_statics = NULL; ISpeechRecognizerStatics2 *sr_statics2 = NULL; @@ -648,6 +649,14 @@ static void test_SpeechRecognizer(void) hr = IInspectable_QueryInterface(inspectable, &IID_ISpeechRecognizer2, (void **)&recognizer2); ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
+ hr = ISpeechRecognizer2_get_ContinuousRecognitionSession(recognizer2, &session); + ok(hr == S_OK, "ISpeechRecognizer2_get_ContinuousRecognitionSession failed, hr %#lx.\n", hr); + check_refcount(session, 2); + check_refcount(inspectable, 3); + + ref = ISpeechContinuousRecognitionSession_Release(session); + ok(ref == 1, "Got unexpected ref %lu.\n", ref); + hr = IInspectable_QueryInterface(inspectable, &IID_IClosable, (void **)&closable); ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
Signed-off-by: Rémi Bernon rbernon@codeweavers.com
Also add helpers to manage typed event handlers.
Signed-off-by: Bernhard Kölbl besentv@gmail.com --- dlls/windows.media.speech/Makefile.in | 1 + dlls/windows.media.speech/event_handlers.c | 108 +++++++++++++++++++++ dlls/windows.media.speech/private.h | 7 ++ dlls/windows.media.speech/recognizer.c | 17 +++- dlls/windows.media.speech/tests/speech.c | 90 ++++++++++++++++- include/windows.foundation.idl | 1 + 6 files changed, 218 insertions(+), 6 deletions(-) create mode 100644 dlls/windows.media.speech/event_handlers.c
diff --git a/dlls/windows.media.speech/Makefile.in b/dlls/windows.media.speech/Makefile.in index 2f9ca159e2a..5dbdb03cf2f 100644 --- a/dlls/windows.media.speech/Makefile.in +++ b/dlls/windows.media.speech/Makefile.in @@ -2,6 +2,7 @@ MODULE = windows.media.speech.dll IMPORTS = combase uuid
C_SRCS = \ + event_handlers.c \ listconstraint.c \ main.c \ recognizer.c \ diff --git a/dlls/windows.media.speech/event_handlers.c b/dlls/windows.media.speech/event_handlers.c new file mode 100644 index 00000000000..7b5db971d1a --- /dev/null +++ b/dlls/windows.media.speech/event_handlers.c @@ -0,0 +1,108 @@ +/* WinRT Windows.Media.SpeechRecognition implementation + * + * Copyright 2022 Bernhard Kölbl + * + * 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 "private.h" + +static CRITICAL_SECTION handlers_cs; +static CRITICAL_SECTION_DEBUG handlers_cs_debug = +{ + 0, 0, &handlers_cs, + { &handlers_cs_debug.ProcessLocksList, &handlers_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": handlers_cs") } +}; +static CRITICAL_SECTION handlers_cs = { &handlers_cs_debug, -1, 0, 0, 0, 0 }; +static EventRegistrationToken next_token = {.value = 1}; + +struct typed_event_handler_entry +{ + struct list entry; + EventRegistrationToken token; + ITypedEventHandler_IInspectable_IInspectable *handler; +}; + +HRESULT typed_event_handlers_append( struct list *list, ITypedEventHandler_IInspectable_IInspectable *handler, EventRegistrationToken *token ) +{ + struct typed_event_handler_entry *entry; + + if (!(entry = calloc(1, sizeof(*entry)))) return E_OUTOFMEMORY; + ITypedEventHandler_IInspectable_IInspectable_AddRef((entry->handler = handler)); + + EnterCriticalSection(&handlers_cs); + + *token = entry->token = next_token; + next_token.value++; + list_add_tail(list, &entry->entry); + + LeaveCriticalSection(&handlers_cs); + + return S_OK; +} + +HRESULT typed_event_handlers_remove( struct list *list, EventRegistrationToken *token ) +{ + struct typed_event_handler_entry *entry; + BOOL found = FALSE; + + EnterCriticalSection(&handlers_cs); + + LIST_FOR_EACH_ENTRY(entry, list, struct typed_event_handler_entry, entry) + if ((found = !memcmp(&entry->token, token, sizeof(*token)))) break; + if (found) list_remove(&entry->entry); + + LeaveCriticalSection(&handlers_cs); + + if (found) + { + ITypedEventHandler_IInspectable_IInspectable_Release(entry->handler); + free(entry); + } + + return S_OK; +} + +HRESULT typed_event_handlers_notify( struct list *list, IInspectable *sender, IInspectable *args ) +{ + struct typed_event_handler_entry *entry; + + EnterCriticalSection(&handlers_cs); + + LIST_FOR_EACH_ENTRY(entry, list, struct typed_event_handler_entry, entry) + ITypedEventHandler_IInspectable_IInspectable_Invoke(entry->handler, sender, args); + + LeaveCriticalSection(&handlers_cs); + + return S_OK; +} + +HRESULT typed_event_handlers_clear( struct list* list ) +{ + struct typed_event_handler_entry *entry, *entry_cursor2; + + EnterCriticalSection(&handlers_cs); + + LIST_FOR_EACH_ENTRY_SAFE(entry, entry_cursor2, list, struct typed_event_handler_entry, entry) + { + list_remove(&entry->entry); + free(entry); + } + + LeaveCriticalSection(&handlers_cs); + + return S_OK; +} diff --git a/dlls/windows.media.speech/private.h b/dlls/windows.media.speech/private.h index c31b8825c74..3e2fa9aed38 100644 --- a/dlls/windows.media.speech/private.h +++ b/dlls/windows.media.speech/private.h @@ -40,6 +40,8 @@ #define WIDL_using_Windows_Media_SpeechRecognition #include "windows.media.speechrecognition.h"
+#include "wine/list.h" + /* * * Windows.Media.SpeechRecognition @@ -59,6 +61,11 @@ extern IActivationFactory *synthesizer_factory;
+HRESULT typed_event_handlers_append( struct list *list, ITypedEventHandler_IInspectable_IInspectable *handler, EventRegistrationToken *token ); +HRESULT typed_event_handlers_remove( struct list *list, EventRegistrationToken *token ); +HRESULT typed_event_handlers_notify( struct list *list, IInspectable *sender, IInspectable *args ); +HRESULT typed_event_handlers_clear( struct list* list ); + #define DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from, iface_mem, expr ) \ static inline impl_type *impl_from( iface_type *iface ) \ { \ diff --git a/dlls/windows.media.speech/recognizer.c b/dlls/windows.media.speech/recognizer.c index 47c6e62f417..7f4c7429929 100644 --- a/dlls/windows.media.speech/recognizer.c +++ b/dlls/windows.media.speech/recognizer.c @@ -33,6 +33,8 @@ struct session { ISpeechContinuousRecognitionSession ISpeechContinuousRecognitionSession_iface; LONG ref; + + struct list result_handlers; };
/* @@ -80,7 +82,10 @@ static ULONG WINAPI session_Release( ISpeechContinuousRecognitionSession *iface TRACE("iface %p, ref %lu.\n", iface, ref);
if (!ref) + { + typed_event_handlers_clear(&impl->result_handlers); free(impl); + }
return ref; } @@ -171,14 +176,17 @@ static HRESULT WINAPI session_add_ResultGenerated( ISpeechContinuousRecognitionS ITypedEventHandler_SpeechContinuousRecognitionSession_SpeechContinuousRecognitionResultGeneratedEventArgs *handler, EventRegistrationToken *token) { - FIXME("iface %p, handler %p, token %p stub!\n", iface, handler, token); - return E_NOTIMPL; + struct session *impl = impl_from_ISpeechContinuousRecognitionSession(iface); + TRACE("iface %p, handler %p, token %p.\n", iface, handler, token); + if (!handler) return E_INVALIDARG; + return typed_event_handlers_append(&impl->result_handlers, (ITypedEventHandler_IInspectable_IInspectable *)handler, token); }
static HRESULT WINAPI session_remove_ResultGenerated( ISpeechContinuousRecognitionSession *iface, EventRegistrationToken token ) { - FIXME("iface %p, token.value %#I64x stub!\n", iface, token.value); - return E_NOTIMPL; + struct session *impl = impl_from_ISpeechContinuousRecognitionSession(iface); + TRACE("iface %p, token.value %#I64x.\n", iface, token.value); + return typed_event_handlers_remove(&impl->result_handlers, &token); }
static const struct ISpeechContinuousRecognitionSessionVtbl session_vtbl = @@ -637,6 +645,7 @@ static HRESULT WINAPI recognizer_factory_Create( ISpeechRecognizerFactory *iface
session->ISpeechContinuousRecognitionSession_iface.lpVtbl = &session_vtbl; session->ref = 1; + list_init(&session->result_handlers);
impl->ISpeechRecognizer_iface.lpVtbl = &speech_recognizer_vtbl; impl->IClosable_iface.lpVtbl = &closable_vtbl; diff --git a/dlls/windows.media.speech/tests/speech.c b/dlls/windows.media.speech/tests/speech.c index e22ab35928e..80e5d9af634 100644 --- a/dlls/windows.media.speech/tests/speech.c +++ b/dlls/windows.media.speech/tests/speech.c @@ -40,6 +40,12 @@
#define SPERR_WINRT_INTERNAL_ERROR 0x800455a0
+#define IHandler_RecognitionResult ITypedEventHandler_SpeechContinuousRecognitionSession_SpeechContinuousRecognitionResultGeneratedEventArgs +#define IHandler_RecognitionResultVtbl ITypedEventHandler_SpeechContinuousRecognitionSession_SpeechContinuousRecognitionResultGeneratedEventArgsVtbl +#define IID_IHandler_RecognitionResult IID_ITypedEventHandler_SpeechContinuousRecognitionSession_SpeechContinuousRecognitionResultGeneratedEventArgs +#define impl_from_IHandler_RecognitionResult impl_from_ITypedEventHandler_SpeechContinuousRecognitionSession_SpeechContinuousRecognitionResultGeneratedEventArgs +#define IHandler_RecognitionResult_iface ITypedEventHandler_SpeechContinuousRecognitionSession_SpeechContinuousRecognitionResultGeneratedEventArgs_iface + HRESULT WINAPI (*pDllGetActivationFactory)(HSTRING, IActivationFactory **); static BOOL is_win10_1507 = FALSE;
@@ -80,6 +86,72 @@ static const char *debugstr_hstring(HSTRING hstr) return wine_dbgstr_wn(str, len); }
+struct recognition_result_handler +{ + IHandler_RecognitionResult IHandler_RecognitionResult_iface; + LONG ref; +}; + +static inline struct recognition_result_handler *impl_from_IHandler_RecognitionResult( IHandler_RecognitionResult *iface ) +{ + return CONTAINING_RECORD(iface, struct recognition_result_handler, IHandler_RecognitionResult_iface); +} + +HRESULT WINAPI recognition_result_handler_QueryInterface( IHandler_RecognitionResult *iface, REFIID iid, void **out ) +{ + if (IsEqualGUID(iid, &IID_IUnknown) || + IsEqualGUID(iid, &IID_IHandler_RecognitionResult)) + { + IUnknown_AddRef(iface); + *out = iface; + return S_OK; + } + + trace("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + *out = NULL; + return E_NOINTERFACE; +} + +ULONG WINAPI recognition_result_handler_AddRef( IHandler_RecognitionResult *iface ) +{ + struct recognition_result_handler *impl = impl_from_IHandler_RecognitionResult(iface); + ULONG ref = InterlockedIncrement(&impl->ref); + return ref; +} + +ULONG WINAPI recognition_result_handler_Release( IHandler_RecognitionResult *iface ) +{ + struct recognition_result_handler *impl = impl_from_IHandler_RecognitionResult(iface); + ULONG ref = InterlockedDecrement(&impl->ref); + return ref; +} + +HRESULT WINAPI recognition_result_handler_Invoke( IHandler_RecognitionResult *iface, + ISpeechContinuousRecognitionSession *sender, + ISpeechContinuousRecognitionResultGeneratedEventArgs *args ) +{ + trace("iface %p, sender %p, args %p.\n", iface, sender, args); + return S_OK; +} + +static const struct IHandler_RecognitionResultVtbl recognition_result_handler_vtbl = +{ + /* IUnknown methods */ + recognition_result_handler_QueryInterface, + recognition_result_handler_AddRef, + recognition_result_handler_Release, + /* ITypedEventHandler<SpeechContinuousRecognitionSession*, SpeechContinuousRecognitionResultGeneratedEventArgs* > methods */ + recognition_result_handler_Invoke +}; + +static HRESULT WINAPI recognition_result_handler_create_static( struct recognition_result_handler *impl ) +{ + impl->IHandler_RecognitionResult_iface.lpVtbl = &recognition_result_handler_vtbl; + impl->ref = 1; + + return S_OK; +} + struct iterator_hstring { IIterator_HSTRING IIterator_HSTRING_iface; @@ -192,7 +264,7 @@ static const struct IIterator_HSTRINGVtbl iterator_hstring_vtbl = iterator_hstring_GetMany };
-static HRESULT WINAPI iterator_hstring_create_static(struct iterator_hstring *impl, HSTRING *strings, UINT32 size) +static HRESULT WINAPI iterator_hstring_create_static( struct iterator_hstring *impl, HSTRING *strings, UINT32 size ) { impl->IIterator_HSTRING_iface.lpVtbl = &iterator_hstring_vtbl; impl->ref = 1; @@ -294,7 +366,7 @@ static const struct IIterable_HSTRINGVtbl iterable_hstring_vtbl = iterable_hstring_First };
-static HRESULT WINAPI iterable_hstring_create_static(struct iterable_hstring *impl, struct iterator_hstring *iterator) +static HRESULT WINAPI iterable_hstring_create_static( struct iterable_hstring *impl, struct iterator_hstring *iterator ) { impl->IIterable_HSTRING_iface.lpVtbl = &iterable_hstring_vtbl; impl->ref = 1; @@ -579,6 +651,8 @@ static void test_SpeechRecognizer(void) IInspectable *inspectable = NULL; IClosable *closable = NULL; ILanguage *language = NULL; + struct recognition_result_handler result_handler; + EventRegistrationToken token = { .value = 0 }; HSTRING hstr, hstr_lang; HRESULT hr; LONG ref; @@ -654,6 +728,18 @@ static void test_SpeechRecognizer(void) check_refcount(session, 2); check_refcount(inspectable, 3);
+ hr = ISpeechContinuousRecognitionSession_add_ResultGenerated(session, NULL, &token); + ok(hr == E_INVALIDARG, "ISpeechContinuousRecognitionSession_add_ResultGenerated failed, hr %#lx.\n", hr); + + token.value = 0xdeadbeef; + recognition_result_handler_create_static(&result_handler); + hr = ISpeechContinuousRecognitionSession_add_ResultGenerated(session, &result_handler.IHandler_RecognitionResult_iface, &token); + ok(hr == S_OK, "ISpeechContinuousRecognitionSession_add_ResultGenerated failed, hr %#lx.\n", hr); + ok(token.value != 0xdeadbeef, "Got unexpexted token: %#I64x.\n", token.value); + + hr = ISpeechContinuousRecognitionSession_remove_ResultGenerated(session, token); + ok(hr == S_OK, "ISpeechContinuousRecognitionSession_remove_ResultGenerated failed, hr %#lx.\n", hr); + ref = ISpeechContinuousRecognitionSession_Release(session); ok(ref == 1, "Got unexpected ref %lu.\n", ref);
diff --git a/include/windows.foundation.idl b/include/windows.foundation.idl index 27bec63b0ef..87aaac0f160 100644 --- a/include/windows.foundation.idl +++ b/include/windows.foundation.idl @@ -171,6 +171,7 @@ namespace Windows { interface Windows.Foundation.AsyncOperationCompletedHandler<boolean>; interface Windows.Foundation.IAsyncOperation<boolean>; interface Windows.Foundation.IReference<INT32>; + interface Windows.Foundation.TypedEventHandler<IInspectable *, IInspectable *>; } } }
Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
As you may have seen in the test runs on Windows, native likes to query a whole lot of interfaces there, I believe it's looking for a serialization marker, and adding IAgileObject seems to greatly reduce the number of queried interfaces.
+HRESULT WINAPI recognition_result_handler_QueryInterface( IHandler_RecognitionResult *iface, REFIID iid, void **out ) +{
- if (IsEqualGUID(iid, &IID_IUnknown) ||
IsEqualGUID(iid, &IID_IHandler_RecognitionResult))
- {
IUnknown_AddRef(iface);
*out = iface;
return S_OK;
- }
- trace("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
- *out = NULL;
- return E_NOINTERFACE;
+}
Signed-off-by: Bernhard Kölbl besentv@gmail.com --- dlls/windows.media.speech/recognizer.c | 14 ++-- dlls/windows.media.speech/tests/speech.c | 85 ++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 4 deletions(-)
diff --git a/dlls/windows.media.speech/recognizer.c b/dlls/windows.media.speech/recognizer.c index 7f4c7429929..da219d6bd0a 100644 --- a/dlls/windows.media.speech/recognizer.c +++ b/dlls/windows.media.speech/recognizer.c @@ -34,6 +34,7 @@ struct session ISpeechContinuousRecognitionSession ISpeechContinuousRecognitionSession_iface; LONG ref;
+ struct list completed_handlers; struct list result_handlers; };
@@ -83,6 +84,7 @@ static ULONG WINAPI session_Release( ISpeechContinuousRecognitionSession *iface
if (!ref) { + typed_event_handlers_clear(&impl->completed_handlers); typed_event_handlers_clear(&impl->result_handlers); free(impl); } @@ -162,14 +164,17 @@ static HRESULT WINAPI session_add_Completed( ISpeechContinuousRecognitionSession ITypedEventHandler_SpeechContinuousRecognitionSession_SpeechContinuousRecognitionCompletedEventArgs *handler, EventRegistrationToken *token ) { - FIXME("iface %p, handler %p, token %p stub!\n", iface, handler, token); - return E_NOTIMPL; + struct session *impl = impl_from_ISpeechContinuousRecognitionSession(iface); + TRACE("iface %p, handler %p, token %p.\n", iface, handler, token); + if (!handler) return E_INVALIDARG; + return typed_event_handlers_append(&impl->completed_handlers, (ITypedEventHandler_IInspectable_IInspectable *)handler, token); }
static HRESULT WINAPI session_remove_Completed( ISpeechContinuousRecognitionSession *iface, EventRegistrationToken token ) { - FIXME("iface %p, token.value %#I64x stub!\n", iface, token.value); - return E_NOTIMPL; + struct session *impl = impl_from_ISpeechContinuousRecognitionSession(iface); + TRACE("iface %p, token.value %#I64x.\n", iface, token.value); + return typed_event_handlers_remove(&impl->completed_handlers, &token); }
static HRESULT WINAPI session_add_ResultGenerated( ISpeechContinuousRecognitionSession *iface, @@ -645,6 +650,7 @@ static HRESULT WINAPI recognizer_factory_Create( ISpeechRecognizerFactory *iface
session->ISpeechContinuousRecognitionSession_iface.lpVtbl = &session_vtbl; session->ref = 1; + list_init(&session->completed_handlers); list_init(&session->result_handlers);
impl->ISpeechRecognizer_iface.lpVtbl = &speech_recognizer_vtbl; diff --git a/dlls/windows.media.speech/tests/speech.c b/dlls/windows.media.speech/tests/speech.c index 80e5d9af634..fc0a8d762c1 100644 --- a/dlls/windows.media.speech/tests/speech.c +++ b/dlls/windows.media.speech/tests/speech.c @@ -46,6 +46,12 @@ #define impl_from_IHandler_RecognitionResult impl_from_ITypedEventHandler_SpeechContinuousRecognitionSession_SpeechContinuousRecognitionResultGeneratedEventArgs #define IHandler_RecognitionResult_iface ITypedEventHandler_SpeechContinuousRecognitionSession_SpeechContinuousRecognitionResultGeneratedEventArgs_iface
+#define IHandler_RecognitionCompleted ITypedEventHandler_SpeechContinuousRecognitionSession_SpeechContinuousRecognitionCompletedEventArgs +#define IHandler_RecognitionCompletedVtbl ITypedEventHandler_SpeechContinuousRecognitionSession_SpeechContinuousRecognitionCompletedEventArgsVtbl +#define IID_IHandler_RecognitionCompleted IID_ITypedEventHandler_SpeechContinuousRecognitionSession_SpeechContinuousRecognitionCompletedEventArgs +#define impl_from_IHandler_RecognitionCompleted impl_from_ITypedEventHandler_SpeechContinuousRecognitionSession_SpeechContinuousRecognitionCompletedEventArgs +#define IHandler_RecognitionCompleted_iface ITypedEventHandler_SpeechContinuousRecognitionSession_SpeechContinuousRecognitionCompletedEventArgs_iface + HRESULT WINAPI (*pDllGetActivationFactory)(HSTRING, IActivationFactory **); static BOOL is_win10_1507 = FALSE;
@@ -86,6 +92,72 @@ static const char *debugstr_hstring(HSTRING hstr) return wine_dbgstr_wn(str, len); }
+struct completed_event_handler +{ + IHandler_RecognitionCompleted IHandler_RecognitionCompleted_iface; + LONG ref; +}; + +static inline struct completed_event_handler *impl_from_IHandler_RecognitionCompleted( IHandler_RecognitionCompleted *iface ) +{ + return CONTAINING_RECORD(iface, struct completed_event_handler, IHandler_RecognitionCompleted_iface); +} + +HRESULT WINAPI completed_event_handler_QueryInterface( IHandler_RecognitionCompleted *iface, REFIID iid, void **out ) +{ + if (IsEqualGUID(iid, &IID_IUnknown) || + IsEqualGUID(iid, &IID_IHandler_RecognitionCompleted)) + { + IUnknown_AddRef(iface); + *out = iface; + return S_OK; + } + + trace("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + *out = NULL; + return E_NOINTERFACE; +} + +ULONG WINAPI completed_event_handler_AddRef( IHandler_RecognitionCompleted *iface ) +{ + struct completed_event_handler *impl = impl_from_IHandler_RecognitionCompleted(iface); + ULONG ref = InterlockedIncrement(&impl->ref); + return ref; +} + +ULONG WINAPI completed_event_handler_Release( IHandler_RecognitionCompleted *iface ) +{ + struct completed_event_handler *impl = impl_from_IHandler_RecognitionCompleted(iface); + ULONG ref = InterlockedDecrement(&impl->ref); + return ref; +} + +HRESULT WINAPI completed_event_handler_Invoke( IHandler_RecognitionCompleted *iface, + ISpeechContinuousRecognitionSession *sender, + ISpeechContinuousRecognitionCompletedEventArgs *args ) +{ + trace("iface %p, sender %p, args %p.\n", iface, sender, args); + return S_OK; +} + +static const struct IHandler_RecognitionCompletedVtbl completed_event_handler_vtbl = +{ + /* IUnknown methods */ + completed_event_handler_QueryInterface, + completed_event_handler_AddRef, + completed_event_handler_Release, + /* ITypedEventHandler<SpeechContinuousRecognitionSession*, SpeechContinuousRecognitionCompletedEventArgs* > methods */ + completed_event_handler_Invoke +}; + +static HRESULT WINAPI completed_event_handler_create_static( struct completed_event_handler *impl ) +{ + impl->IHandler_RecognitionCompleted_iface.lpVtbl = &completed_event_handler_vtbl; + impl->ref = 1; + + return S_OK; +} + struct recognition_result_handler { IHandler_RecognitionResult IHandler_RecognitionResult_iface; @@ -651,6 +723,7 @@ static void test_SpeechRecognizer(void) IInspectable *inspectable = NULL; IClosable *closable = NULL; ILanguage *language = NULL; + struct completed_event_handler completed_handler; struct recognition_result_handler result_handler; EventRegistrationToken token = { .value = 0 }; HSTRING hstr, hstr_lang; @@ -728,6 +801,18 @@ static void test_SpeechRecognizer(void) check_refcount(session, 2); check_refcount(inspectable, 3);
+ hr = ISpeechContinuousRecognitionSession_add_Completed(session, NULL, &token); + ok(hr == E_INVALIDARG, "ISpeechContinuousRecognitionSession_add_ResultGenerated failed, hr %#lx.\n", hr); + + token.value = 0xdeadbeef; + completed_event_handler_create_static(&completed_handler); + hr = ISpeechContinuousRecognitionSession_add_Completed(session, &completed_handler.IHandler_RecognitionCompleted_iface, &token); + ok(hr == S_OK, "ISpeechContinuousRecognitionSession_add_ResultGenerated failed, hr %#lx.\n", hr); + ok(token.value != 0xdeadbeef, "Got unexpexted token: %#I64x.\n", token.value); + + hr = ISpeechContinuousRecognitionSession_remove_Completed(session, token); + ok(hr == S_OK, "ISpeechContinuousRecognitionSession_remove_ResultGenerated failed, hr %#lx.\n", hr); + hr = ISpeechContinuousRecognitionSession_add_ResultGenerated(session, NULL, &token); ok(hr == E_INVALIDARG, "ISpeechContinuousRecognitionSession_add_ResultGenerated failed, hr %#lx.\n", hr);
Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
Like the previous patch, I believe that adding IAgileObject to the test event handler would greatly reduce the test verbosity.