Taken from MSDN and original winerror.h.
Signed-off-by: Bernhard Kölbl besentv@gmail.com --- include/winerror.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
diff --git a/include/winerror.h b/include/winerror.h index b63b74a5b18..d51d5648cdb 100644 --- a/include/winerror.h +++ b/include/winerror.h @@ -2578,6 +2578,25 @@ static inline HRESULT HRESULT_FROM_WIN32(unsigned int x) #define E_CHANGED_STATE _HRESULT_TYPEDEF_(0x8000000C) #define E_ILLEGAL_STATE_CHANGE _HRESULT_TYPEDEF_(0x8000000D) #define E_ILLEGAL_METHOD_CALL _HRESULT_TYPEDEF_(0x8000000E) +#define RO_E_METADATA_NAME_NOT_FOUND _HRESULT_TYPEDEF_(0x8000000F) +#define RO_E_METADATA_NAME_IS_NAMESPACE _HRESULT_TYPEDEF_(0x80000010) +#define RO_E_METADATA_INVALID_TYPE_FORMAT _HRESULT_TYPEDEF_(0x80000011) +#define RO_E_INVALID_METADATA_FILE _HRESULT_TYPEDEF_(0x80000012) +#define RO_E_CLOSED _HRESULT_TYPEDEF_(0x80000013) +#define RO_E_EXCLUSIVE_WRITE _HRESULT_TYPEDEF_(0x80000014) +#define RO_E_CHANGE_NOTIFICATION_IN_PROGRESS _HRESULT_TYPEDEF_(0x80000015) +#define RO_E_ERROR_STRING_NOT_FOUND _HRESULT_TYPEDEF_(0x80000016) +#define E_STRING_NOT_NULL_TERMINATED _HRESULT_TYPEDEF_(0x80000017) +#define E_ILLEGAL_DELEGATE_ASSIGNMENT _HRESULT_TYPEDEF_(0x80000018) +#define E_ASYNC_OPERATION_NOT_STARTED _HRESULT_TYPEDEF_(0x80000019) +#define E_APPLICATION_EXITING _HRESULT_TYPEDEF_(0x8000001A) +#define E_APPLICATION_VIEW_EXITING _HRESULT_TYPEDEF_(0x8000001B) +#define RO_E_MUST_BE_AGILE _HRESULT_TYPEDEF_(0x8000001C) +#define RO_E_UNSUPPORTED_FROM_MTA _HRESULT_TYPEDEF_(0x8000001D) +#define RO_E_COMMITTED _HRESULT_TYPEDEF_(0x8000001E) +#define RO_E_BLOCKED_CROSS_ASTA_CALL _HRESULT_TYPEDEF_(0x8000001F) +#define RO_E_CANNOT_ACTIVATE_FULL_TRUST_SERVER _HRESULT_TYPEDEF_(0x80000020) +#define RO_E_CANNOT_ACTIVATE_UNIVERSAL_APPLICATION_SERVER _HRESULT_TYPEDEF_(0x80000021)
#define E_NOTIMPL _HRESULT_TYPEDEF_(0x80004001) #define E_NOINTERFACE _HRESULT_TYPEDEF_(0x80004002)
Signed-off-by: Bernhard Kölbl besentv@gmail.com --- include/windows.foundation.collections.idl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/windows.foundation.collections.idl b/include/windows.foundation.collections.idl index 5ed60ed176e..395adad27aa 100644 --- a/include/windows.foundation.collections.idl +++ b/include/windows.foundation.collections.idl @@ -64,7 +64,7 @@ cpp_quote("#endif") { [propput] HRESULT Completed([in] Windows.Foundation.AsyncOperationCompletedHandler<TResult> *handler); [propget] HRESULT Completed([out, retval] Windows.Foundation.AsyncOperationCompletedHandler<TResult> **handler); - HRESULT GetResults([out, retval] TResult **results); + HRESULT GetResults([out, retval] TResult *results); }
[
Signed-off-by: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Bernhard Kölbl besentv@gmail.com --- dlls/windows.media.speech/tests/speech.c | 241 ++++++++++++++++++++++- 1 file changed, 239 insertions(+), 2 deletions(-)
diff --git a/dlls/windows.media.speech/tests/speech.c b/dlls/windows.media.speech/tests/speech.c index 8093c4b95b8..96029a0f833 100644 --- a/dlls/windows.media.speech/tests/speech.c +++ b/dlls/windows.media.speech/tests/speech.c @@ -38,6 +38,8 @@
#include "wine/test.h"
+#define AsyncStatus_Closed 4 + #define SPERR_WINRT_INTERNAL_ERROR 0x800455a0
#define IHandler_RecognitionResult ITypedEventHandler_SpeechContinuousRecognitionSession_SpeechContinuousRecognitionResultGeneratedEventArgs @@ -52,6 +54,12 @@ #define impl_from_IHandler_RecognitionCompleted impl_from_ITypedEventHandler_SpeechContinuousRecognitionSession_SpeechContinuousRecognitionCompletedEventArgs #define IHandler_RecognitionCompleted_iface ITypedEventHandler_SpeechContinuousRecognitionSession_SpeechContinuousRecognitionCompletedEventArgs_iface
+#define IAsyncHandler_Compilation IAsyncOperationCompletedHandler_SpeechRecognitionCompilationResult +#define IAsyncHandler_CompilationVtbl IAsyncOperationCompletedHandler_SpeechRecognitionCompilationResultVtbl +#define IID_IAsyncHandler_Compilation IID_IAsyncOperationCompletedHandler_SpeechRecognitionCompilationResult +#define impl_from_IAsyncHandler_Compilation impl_from_IAsyncOperationCompletedHandler_SpeechRecognitionCompilationResult +#define IAsyncHandler_Compilation_iface IAsyncOperationCompletedHandler_SpeechRecognitionCompilationResult_iface + HRESULT WINAPI (*pDllGetActivationFactory)(HSTRING, IActivationFactory **); static BOOL is_win10_1507 = FALSE;
@@ -226,6 +234,87 @@ static HRESULT WINAPI recognition_result_handler_create_static( struct recogniti return S_OK; }
+struct compilation_handler +{ + IAsyncHandler_Compilation IAsyncHandler_Compilation_iface; + LONG ref; + + HANDLE event_finished; + BOOLEAN sleeping; + DWORD thread_id; +}; + +static inline struct compilation_handler *impl_from_IAsyncHandler_Compilation( IAsyncHandler_Compilation *iface ) +{ + return CONTAINING_RECORD(iface, struct compilation_handler, IAsyncHandler_Compilation_iface); +} + +HRESULT WINAPI compilation_handler_QueryInterface( IAsyncHandler_Compilation *iface, + REFIID iid, + void **out ) +{ + if (IsEqualGUID(iid, &IID_IUnknown) || + IsEqualGUID(iid, &IID_IAgileObject) || + IsEqualGUID(iid, &IID_IAsyncHandler_Compilation)) + { + 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 compilation_handler_AddRef( IAsyncHandler_Compilation *iface ) +{ + struct compilation_handler *impl = impl_from_IAsyncHandler_Compilation(iface); + ULONG ref = InterlockedIncrement(&impl->ref); + return ref; +} + +ULONG WINAPI compilation_handler_Release( IAsyncHandler_Compilation *iface ) +{ + struct compilation_handler *impl = impl_from_IAsyncHandler_Compilation(iface); + ULONG ref = InterlockedDecrement(&impl->ref); + return ref; +} + +HRESULT WINAPI compilation_handler_Invoke( IAsyncHandler_Compilation *iface, + IAsyncOperation_SpeechRecognitionCompilationResult *info, + AsyncStatus status ) +{ + struct compilation_handler *impl = impl_from_IAsyncHandler_Compilation(iface); + DWORD id = GetCurrentThreadId(); + trace("Iface %p, info %p, status %d.\n", iface, info, status); + trace("Caller thread id %lu callback thread id %lu.\n", impl->thread_id, id); + + ok(status != Started, "Got unexpected status %#x.\n", status); + if (impl->event_finished) SetEvent(impl->event_finished); + + return S_OK; +} + +static const struct IAsyncHandler_CompilationVtbl compilation_handler_vtbl = +{ + /* IUnknown methods */ + compilation_handler_QueryInterface, + compilation_handler_AddRef, + compilation_handler_Release, + /* IAsyncOperationCompletedHandler<SpeechRecognitionCompilationResult* > methods */ + compilation_handler_Invoke +}; + + +static HRESULT WINAPI compilation_handler_create_static( struct compilation_handler *impl ) +{ + impl->IAsyncHandler_Compilation_iface.lpVtbl = &compilation_handler_vtbl; + impl->ref = 1; + + return S_OK; +} + struct iterator_hstring { IIterator_HSTRING IIterator_HSTRING_iface; @@ -421,8 +510,6 @@ static HRESULT WINAPI iterable_hstring_First( IIterable_HSTRING *iface, IIterato struct iterable_hstring *impl = impl_from_Iterable_HSTRING(iface); struct iterator_hstring *impl_iter = impl_from_IIterator_HSTRING(impl->iterator);
- trace("iface %p, value %p.\n", iface, value); - impl_iter->index = 0; IIterator_HSTRING_AddRef((*value = impl->iterator)); return S_OK; @@ -729,6 +816,9 @@ static void test_VoiceInformation(void) static void test_SpeechRecognizer(void) { static const WCHAR *speech_recognition_name = L"Windows.Media.SpeechRecognition.SpeechRecognizer"; + IAsyncOperationCompletedHandler_SpeechRecognitionCompilationResult *handler = NULL; + IAsyncOperation_SpeechRecognitionCompilationResult *operation = NULL; + ISpeechRecognitionCompilationResult *compilation_result = NULL; IVector_ISpeechRecognitionConstraint *constraints = NULL; ISpeechContinuousRecognitionSession *session = NULL; ISpeechRecognizerFactory *sr_factory = NULL; @@ -740,11 +830,17 @@ static void test_SpeechRecognizer(void) IInspectable *inspectable = NULL; IClosable *closable = NULL; ILanguage *language = NULL; + IAsyncInfo *info = NULL; struct completed_event_handler completed_handler; struct recognition_result_handler result_handler; + struct compilation_handler compilation_handler; + struct compilation_handler compilation_handler2; + SpeechRecognitionResultStatus result_status; EventRegistrationToken token = { .value = 0 }; + AsyncStatus async_status; HSTRING hstr, hstr_lang; HRESULT hr; + UINT32 id; LONG ref;
hr = RoInitialize(RO_INIT_MULTITHREADED); @@ -848,6 +944,147 @@ static void test_SpeechRecognizer(void) ref = IVector_ISpeechRecognitionConstraint_Release(constraints); ok(ref == 1, "Got unexpected ref %lu.\n", ref);
+ compilation_handler_create_static(&compilation_handler); + compilation_handler.event_finished = CreateEventW(NULL, FALSE, FALSE, NULL); + compilation_handler.thread_id = GetCurrentThreadId(); + + hr = ISpeechRecognizer_CompileConstraintsAsync(recognizer, &operation); + todo_wine ok(hr == S_OK, "ISpeechRecognizer_CompileConstraintsAsync failed, hr %#lx.\n", hr); + + if (FAILED(hr)) goto skip_operation; + + handler = (void*)0xdeadbeef; + hr = IAsyncOperation_SpeechRecognitionCompilationResult_get_Completed(operation, &handler); + todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + todo_wine ok(handler == NULL, "Handler had value %p.\n", handler); + + compilation_result = (void*)0xdeadbeef; + hr = IAsyncOperation_SpeechRecognitionCompilationResult_GetResults(operation, &compilation_result); + todo_wine ok(hr == E_ILLEGAL_METHOD_CALL, "Got unexpected hr %#lx.\n", hr); + todo_wine ok(compilation_result == (void*)0xdeadbeef, "Compilation result had value %p.\n", compilation_result); + + hr = IAsyncOperation_SpeechRecognitionCompilationResult_put_Completed(operation, &compilation_handler.IAsyncHandler_Compilation_iface); + todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + todo_wine check_refcount(&compilation_handler.IAsyncHandler_Compilation_iface, 1); + + WaitForSingleObject(compilation_handler.event_finished, INFINITE); + CloseHandle(compilation_handler.event_finished); + + hr = IAsyncOperation_SpeechRecognitionCompilationResult_put_Completed(operation, NULL); + todo_wine ok(hr == E_ILLEGAL_DELEGATE_ASSIGNMENT, "Got unexpected hr %#lx.\n", hr); + + handler = (void*)0xdeadbeef; + hr = IAsyncOperation_SpeechRecognitionCompilationResult_get_Completed(operation, &handler); + todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + todo_wine ok(handler == NULL, "Handler had value %p.\n", handler); + + hr = IAsyncOperation_SpeechRecognitionCompilationResult_GetResults(operation, &compilation_result); + todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + todo_wine check_interface(compilation_result, &IID_IAgileObject, TRUE); + + hr = ISpeechRecognitionCompilationResult_get_Status(compilation_result, &result_status); + todo_wine ok(hr == S_OK, "ISpeechRecognitionCompilationResult_get_Status failed, hr %#lx.\n", hr); + todo_wine ok(result_status == SpeechRecognitionResultStatus_Success, "Got unexpected status %#x.\n", result_status); + + ref = ISpeechRecognitionCompilationResult_Release(compilation_result); + todo_wine ok(!ref , "Got unexpected ref %lu.\n", ref); + + hr = IAsyncOperation_SpeechRecognitionCompilationResult_GetResults(operation, &compilation_result); + todo_wine ok(hr == E_UNEXPECTED, "Got unexpected hr %#lx.\n", hr); + + hr = IAsyncOperation_SpeechRecognitionCompilationResult_QueryInterface(operation, &IID_IAsyncInfo, (void **)&info); + todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + /* Check if AsyncInfo and AsyncOperation share the same refcount. */ + IAsyncOperation_SpeechRecognitionCompilationResult_AddRef(operation); + todo_wine check_refcount(operation, 3); + todo_wine check_refcount(info, 3); + + IAsyncOperation_SpeechRecognitionCompilationResult_Release(operation); + todo_wine check_refcount(info, 2); + + id = 0xdeadbeef; + hr = IAsyncInfo_get_Id(info, &id); + todo_wine ok(hr == S_OK, "IAsyncInfo_get_Id failed, hr %#lx.\n", hr); + todo_wine ok(id != 0xdeadbeef, "Id was %#x.\n", id); + + async_status = 0xdeadbeef; + hr = IAsyncInfo_get_Status(info, &async_status); + todo_wine ok(hr == S_OK, "IAsyncInfo_get_Status failed, hr %#lx.\n", hr); + todo_wine ok(async_status == Completed, "Status was %#x.\n", async_status); + + hr = IAsyncInfo_Cancel(info); + todo_wine ok(hr == S_OK, "IAsyncInfo_Cancel failed, hr %#lx.\n", hr); + + async_status = 0xdeadbeef; + hr = IAsyncInfo_get_Status(info, &async_status); + todo_wine ok(hr == S_OK, "IAsyncInfo_get_Status failed, hr %#lx.\n", hr); + todo_wine ok(async_status == Completed, "Status was %#x.\n", async_status); + + hr = IAsyncInfo_Close(info); + todo_wine ok(hr == S_OK, "IAsyncInfo_Close failed, hr %#lx.\n", hr); + hr = IAsyncInfo_Close(info); + todo_wine ok(hr == S_OK, "IAsyncInfo_Close failed, hr %#lx.\n", hr); + + async_status = 0xdeadbeef; + hr = IAsyncInfo_get_Status(info, &async_status); + todo_wine ok(hr == E_ILLEGAL_METHOD_CALL, "IAsyncInfo_get_Status failed, hr %#lx.\n", hr); + todo_wine ok(async_status == AsyncStatus_Closed, "Status was %#x.\n", async_status); + + ref = IAsyncInfo_Release(info); + todo_wine ok(ref == 1, "Got unexpected ref %lu.\n", ref); + + hr = IAsyncOperation_SpeechRecognitionCompilationResult_put_Completed(operation, NULL); + todo_wine ok(hr == E_ILLEGAL_METHOD_CALL, "Got unexpected hr %#lx.\n", hr); + + handler = (void*)0xdeadbeef; + hr = IAsyncOperation_SpeechRecognitionCompilationResult_get_Completed(operation, &handler); + todo_wine ok(hr == E_ILLEGAL_METHOD_CALL, "Got unexpected hr %#lx.\n", hr); + + IAsyncOperation_SpeechRecognitionCompilationResult_Release(operation); + + /* Test if AsyncOperation is started immediately. */ + compilation_handler_create_static(&compilation_handler2); + compilation_handler2.event_finished = CreateEventW(NULL, FALSE, FALSE, NULL); + compilation_handler2.thread_id = GetCurrentThreadId(); + + ok(compilation_handler2.event_finished != NULL, "Finished event wasn't created.\n"); + + hr = ISpeechRecognizer_CompileConstraintsAsync(recognizer, &operation); + todo_wine ok(hr == S_OK, "ISpeechRecognizer_CompileConstraintsAsync failed, hr %#lx.\n", hr); + todo_wine check_interface(operation, &IID_IAgileObject, TRUE); + + hr = IAsyncOperation_SpeechRecognitionCompilationResult_QueryInterface(operation, &IID_IAsyncInfo, (void **)&info); + todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + /* This one can fail, if the async operation had already finished */ + compilation_result = (void*)0xdeadbeef; + hr = IAsyncOperation_SpeechRecognitionCompilationResult_GetResults(operation, &compilation_result); + todo_wine ok(hr == E_ILLEGAL_METHOD_CALL, "Got unexpected hr %#lx.\n", hr); + todo_wine ok(compilation_result == (void*)0xdeadbeef, "Compilation result had value %p.\n", compilation_result); + + async_status = 0xdeadbeef; + hr = IAsyncInfo_get_Status(info, &async_status); + todo_wine ok(hr == S_OK, "IAsyncInfo_get_Status failed, hr %#lx.\n", hr); + todo_wine ok(async_status == Started || async_status == Completed, "Status was %#x.\n", async_status); + + IAsyncInfo_Release(info); + + hr = IAsyncOperation_SpeechRecognitionCompilationResult_put_Completed(operation, &compilation_handler2.IAsyncHandler_Compilation_iface); + todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + WaitForSingleObject(compilation_handler2.event_finished, INFINITE); + CloseHandle(compilation_handler2.event_finished); + + async_status = 0xdeadbeef; + hr = IAsyncInfo_get_Status(info, &async_status); + todo_wine ok(hr == S_OK, "IAsyncInfo_get_Status failed, hr %#lx.\n", hr); + todo_wine ok(async_status == Completed, "Status was %#x.\n", async_status); + + ref = IAsyncOperation_SpeechRecognitionCompilationResult_Release(operation); + ok(!ref, "Got unexpected ref %lu.\n", ref); + +skip_operation: ref = ISpeechContinuousRecognitionSession_Release(session); ok(ref == 1, "Got unexpected ref %lu.\n", ref);
Signed-off-by: Rémi Bernon rbernon@codeweavers.com
And return an instance of it in ISpeechRecognizer_CompileConstraintsAsync.
Signed-off-by: Bernhard Kölbl besentv@gmail.com --- dlls/windows.media.speech/Makefile.in | 1 + dlls/windows.media.speech/async.c | 156 +++++++++++++++++++++++ dlls/windows.media.speech/private.h | 2 + dlls/windows.media.speech/recognizer.c | 7 +- dlls/windows.media.speech/tests/speech.c | 8 +- include/windows.foundation.idl | 2 + 6 files changed, 169 insertions(+), 7 deletions(-) create mode 100644 dlls/windows.media.speech/async.c
diff --git a/dlls/windows.media.speech/Makefile.in b/dlls/windows.media.speech/Makefile.in index 5a8291ba6f0..10903cb1d7b 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 = \ + async.c \ event_handlers.c \ listconstraint.c \ main.c \ diff --git a/dlls/windows.media.speech/async.c b/dlls/windows.media.speech/async.c new file mode 100644 index 00000000000..f701306e4f0 --- /dev/null +++ b/dlls/windows.media.speech/async.c @@ -0,0 +1,156 @@ +/* WinRT Windows.Media.Speech implementation + * + * Copyright 2022 Bernhard Kölbl 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 "private.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(speech); + +/* + * + * IAsyncOperation<IInspectable*> + * + */ + +struct async_operation +{ + IAsyncOperation_IInspectable IAsyncOperation_IInspectable_iface; + const GUID *iid; + LONG ref; +}; + +static inline struct async_operation *impl_from_IAsyncOperation_IInspectable(IAsyncOperation_IInspectable *iface) +{ + return CONTAINING_RECORD(iface, struct async_operation, IAsyncOperation_IInspectable_iface); +} + +static HRESULT WINAPI async_operation_QueryInterface( IAsyncOperation_IInspectable *iface, REFIID iid, void **out ) +{ + struct async_operation *impl = impl_from_IAsyncOperation_IInspectable(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_IAgileObject) || + IsEqualGUID(iid, impl->iid)) + { + IInspectable_AddRef((*out = &impl->IAsyncOperation_IInspectable_iface)); + return S_OK; + } + + WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI async_operation_AddRef( IAsyncOperation_IInspectable *iface ) +{ + struct async_operation *impl = impl_from_IAsyncOperation_IInspectable(iface); + ULONG ref = InterlockedIncrement(&impl->ref); + TRACE("iface %p, ref %lu.\n", iface, ref); + return ref; +} + +static ULONG WINAPI async_operation_Release( IAsyncOperation_IInspectable *iface ) +{ + struct async_operation *impl = impl_from_IAsyncOperation_IInspectable(iface); + + ULONG ref = InterlockedDecrement(&impl->ref); + TRACE("iface %p, ref %lu.\n", iface, ref); + + if (!ref) + free(impl); + + return ref; +} + +static HRESULT WINAPI async_operation_GetIids( IAsyncOperation_IInspectable *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 async_operation_GetRuntimeClassName( IAsyncOperation_IInspectable *iface, HSTRING *class_name ) +{ + FIXME("iface %p, class_name %p stub!\n", iface, class_name); + return E_NOTIMPL; +} + +static HRESULT WINAPI async_operation_GetTrustLevel( IAsyncOperation_IInspectable *iface, TrustLevel *trust_level ) +{ + FIXME("iface %p, trust_level %p stub!\n", iface, trust_level); + return E_NOTIMPL; +} + +static HRESULT WINAPI async_operation_put_Completed( IAsyncOperation_IInspectable *iface, + IAsyncOperationCompletedHandler_IInspectable *handler ) +{ + FIXME("iface %p, handler %p stub!\n", iface, handler); + return E_NOTIMPL; +} + +static HRESULT WINAPI async_operation_get_Completed( IAsyncOperation_IInspectable *iface, + IAsyncOperationCompletedHandler_IInspectable **handler ) +{ + FIXME("iface %p, handler %p stub!\n", iface, handler); + return E_NOTIMPL; +} + +static HRESULT WINAPI async_operation_GetResults( IAsyncOperation_IInspectable *iface, IInspectable **results ) +{ + FIXME("iface %p, results %p stub!\n", iface, results); + return E_NOTIMPL; +} + +static const struct IAsyncOperation_IInspectableVtbl async_operation_vtbl = +{ + /* IUnknown methods */ + async_operation_QueryInterface, + async_operation_AddRef, + async_operation_Release, + /* IInspectable methods */ + async_operation_GetIids, + async_operation_GetRuntimeClassName, + async_operation_GetTrustLevel, + /* IAsyncOperation<IInspectable*> */ + async_operation_put_Completed, + async_operation_get_Completed, + async_operation_GetResults +}; + +HRESULT async_operation_create( const GUID *iid, IAsyncOperation_IInspectable **out ) +{ + struct async_operation *impl; + + if (!(impl = calloc(1, sizeof(*impl)))) + { + *out = NULL; + return E_OUTOFMEMORY; + } + + impl->IAsyncOperation_IInspectable_iface.lpVtbl = &async_operation_vtbl; + impl->iid = iid; + impl->ref = 1; + + *out = &impl->IAsyncOperation_IInspectable_iface; + TRACE("created %p\n", *out); + return S_OK; +} diff --git a/dlls/windows.media.speech/private.h b/dlls/windows.media.speech/private.h index a5177ddd538..1cf61c51f1e 100644 --- a/dlls/windows.media.speech/private.h +++ b/dlls/windows.media.speech/private.h @@ -69,6 +69,8 @@ struct vector_iids const GUID *view; };
+HRESULT async_operation_create( const GUID *iid, IAsyncOperation_IInspectable **out ); + 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 ); diff --git a/dlls/windows.media.speech/recognizer.c b/dlls/windows.media.speech/recognizer.c index 36836f83a98..b16ecb24641 100644 --- a/dlls/windows.media.speech/recognizer.c +++ b/dlls/windows.media.speech/recognizer.c @@ -124,7 +124,7 @@ static HRESULT WINAPI session_set_AutoStopSilenceTimeout( ISpeechContinuousRecog
static HRESULT WINAPI session_StartAsync( ISpeechContinuousRecognitionSession *iface, IAsyncAction **action ) { - FIXME("iface %p, action %p semi stub!\n", iface, action); + FIXME("iface %p, action %p stub!\n", iface, action); return E_NOTIMPL; }
@@ -351,8 +351,9 @@ static HRESULT WINAPI recognizer_get_UIOptions( ISpeechRecognizer *iface, ISpeec static HRESULT WINAPI recognizer_CompileConstraintsAsync( ISpeechRecognizer *iface, IAsyncOperation_SpeechRecognitionCompilationResult **operation ) { - FIXME("iface %p, operation %p stub!\n", iface, operation); - return E_NOTIMPL; + IAsyncOperation_IInspectable **value = (IAsyncOperation_IInspectable **)operation; + FIXME("iface %p, operation %p semi-stub!\n", iface, operation); + return async_operation_create(&IID_IAsyncOperation_SpeechRecognitionCompilationResult, value); }
static HRESULT WINAPI recognizer_RecognizeAsync( ISpeechRecognizer *iface, diff --git a/dlls/windows.media.speech/tests/speech.c b/dlls/windows.media.speech/tests/speech.c index 96029a0f833..ef75178f8c1 100644 --- a/dlls/windows.media.speech/tests/speech.c +++ b/dlls/windows.media.speech/tests/speech.c @@ -949,15 +949,15 @@ static void test_SpeechRecognizer(void) compilation_handler.thread_id = GetCurrentThreadId();
hr = ISpeechRecognizer_CompileConstraintsAsync(recognizer, &operation); - todo_wine ok(hr == S_OK, "ISpeechRecognizer_CompileConstraintsAsync failed, hr %#lx.\n", hr); - - if (FAILED(hr)) goto skip_operation; + ok(hr == S_OK, "ISpeechRecognizer_CompileConstraintsAsync failed, hr %#lx.\n", hr);
handler = (void*)0xdeadbeef; hr = IAsyncOperation_SpeechRecognitionCompilationResult_get_Completed(operation, &handler); todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); todo_wine ok(handler == NULL, "Handler had value %p.\n", handler);
+ if (FAILED(hr)) goto skip_operation; + compilation_result = (void*)0xdeadbeef; hr = IAsyncOperation_SpeechRecognitionCompilationResult_GetResults(operation, &compilation_result); todo_wine ok(hr == E_ILLEGAL_METHOD_CALL, "Got unexpected hr %#lx.\n", hr); @@ -1081,10 +1081,10 @@ static void test_SpeechRecognizer(void) todo_wine ok(hr == S_OK, "IAsyncInfo_get_Status failed, hr %#lx.\n", hr); todo_wine ok(async_status == Completed, "Status was %#x.\n", async_status);
+skip_operation: ref = IAsyncOperation_SpeechRecognitionCompilationResult_Release(operation); ok(!ref, "Got unexpected ref %lu.\n", ref);
-skip_operation: 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 87aaac0f160..c5f4c04a334 100644 --- a/include/windows.foundation.idl +++ b/include/windows.foundation.idl @@ -168,7 +168,9 @@ namespace Windows { interface Windows.Foundation.Collections.IVector<IInspectable *>; interface Windows.Foundation.Collections.IMapView<HSTRING, Windows.Foundation.Collections.IVectorView<HSTRING>*>; interface Windows.Foundation.EventHandler<IInspectable *>; + interface Windows.Foundation.AsyncOperationCompletedHandler<IInspectable *>; interface Windows.Foundation.AsyncOperationCompletedHandler<boolean>; + interface Windows.Foundation.IAsyncOperation<IInspectable *>; 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
Signed-off-by: Bernhard Kölbl besentv@gmail.com --- dlls/windows.media.speech/async.c | 64 +++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+)
diff --git a/dlls/windows.media.speech/async.c b/dlls/windows.media.speech/async.c index f701306e4f0..94d0b35d9c1 100644 --- a/dlls/windows.media.speech/async.c +++ b/dlls/windows.media.speech/async.c @@ -32,6 +32,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(speech); struct async_operation { IAsyncOperation_IInspectable IAsyncOperation_IInspectable_iface; + IAsyncInfo IAsyncInfo_iface; const GUID *iid; LONG ref; }; @@ -56,6 +57,12 @@ static HRESULT WINAPI async_operation_QueryInterface( IAsyncOperation_IInspectab return S_OK; }
+ if (IsEqualGUID(iid, &IID_IAsyncInfo)) + { + IInspectable_AddRef((*out = &impl->IAsyncInfo_iface)); + return S_OK; + } + WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); *out = NULL; return E_NOINTERFACE; @@ -136,6 +143,62 @@ static const struct IAsyncOperation_IInspectableVtbl async_operation_vtbl = async_operation_GetResults };
+/* + * + * IAsyncInfo + * + */ + +DEFINE_IINSPECTABLE(async_operation_info, IAsyncInfo, struct async_operation, IAsyncOperation_IInspectable_iface) + +static HRESULT WINAPI async_operation_info_get_Id( IAsyncInfo *iface, UINT32 *id ) +{ + FIXME("iface %p, id %p stub!\n", iface, id); + return E_NOTIMPL; +} + +static HRESULT WINAPI async_operation_info_get_Status( IAsyncInfo *iface, AsyncStatus *status ) +{ + FIXME("iface %p, status %p stub!\n", iface, status); + return E_NOTIMPL; +} + +static HRESULT WINAPI async_operation_info_get_ErrorCode( IAsyncInfo *iface, HRESULT *error_code ) +{ + FIXME("iface %p, error_code %p stub!\n", iface, error_code); + return E_NOTIMPL; +} + +static HRESULT WINAPI async_operation_info_Cancel( IAsyncInfo *iface ) +{ + FIXME("iface %p stub!\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI async_operation_info_Close( IAsyncInfo *iface ) +{ + FIXME("iface %p stub!\n", iface); + return E_NOTIMPL; +} + +static const struct IAsyncInfoVtbl async_operation_info_vtbl = +{ + /* IUnknown methods */ + async_operation_info_QueryInterface, + async_operation_info_AddRef, + async_operation_info_Release, + /* IInspectable methods */ + async_operation_info_GetIids, + async_operation_info_GetRuntimeClassName, + async_operation_info_GetTrustLevel, + /* IAsyncInfo */ + async_operation_info_get_Id, + async_operation_info_get_Status, + async_operation_info_get_ErrorCode, + async_operation_info_Cancel, + async_operation_info_Close +}; + HRESULT async_operation_create( const GUID *iid, IAsyncOperation_IInspectable **out ) { struct async_operation *impl; @@ -147,6 +210,7 @@ HRESULT async_operation_create( const GUID *iid, IAsyncOperation_IInspectable ** }
impl->IAsyncOperation_IInspectable_iface.lpVtbl = &async_operation_vtbl; + impl->IAsyncInfo_iface.lpVtbl = &async_operation_info_vtbl; impl->iid = iid; impl->ref = 1;
Signed-off-by: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Bernhard Kölbl besentv@gmail.com --- v2: Make IAsyncOperation truely asynchronous using a threadpool worker. v3: Fix test failures. --- dlls/windows.media.speech/async.c | 120 ++++++++++++++++++++--- dlls/windows.media.speech/private.h | 4 +- dlls/windows.media.speech/recognizer.c | 10 +- dlls/windows.media.speech/tests/speech.c | 70 ++++++------- 4 files changed, 158 insertions(+), 46 deletions(-)
diff --git a/dlls/windows.media.speech/async.c b/dlls/windows.media.speech/async.c index 94d0b35d9c1..5042a31b503 100644 --- a/dlls/windows.media.speech/async.c +++ b/dlls/windows.media.speech/async.c @@ -35,6 +35,18 @@ struct async_operation IAsyncInfo IAsyncInfo_iface; const GUID *iid; LONG ref; + + IAsyncOperationCompletedHandler_IInspectable *handler; + IInspectable *result; + + async_operation_worker worker; + TP_WORK *async_run_work; + void *data; + + CRITICAL_SECTION cs; + + AsyncStatus status; + HRESULT hr; };
static inline struct async_operation *impl_from_IAsyncOperation_IInspectable(IAsyncOperation_IInspectable *iface) @@ -84,7 +96,11 @@ static ULONG WINAPI async_operation_Release( IAsyncOperation_IInspectable *iface TRACE("iface %p, ref %lu.\n", iface, ref);
if (!ref) + { + if (impl->result) IInspectable_Release(impl->result); + DeleteCriticalSection(&impl->cs); free(impl); + }
return ref; } @@ -110,21 +126,60 @@ static HRESULT WINAPI async_operation_GetTrustLevel( IAsyncOperation_IInspectabl static HRESULT WINAPI async_operation_put_Completed( IAsyncOperation_IInspectable *iface, IAsyncOperationCompletedHandler_IInspectable *handler ) { - FIXME("iface %p, handler %p stub!\n", iface, handler); - return E_NOTIMPL; + struct async_operation *impl = impl_from_IAsyncOperation_IInspectable(iface); + HRESULT hr; + + TRACE("iface %p, handler %p.\n", iface, handler); + + EnterCriticalSection(&impl->cs); + + if (impl->handler) + hr = E_ILLEGAL_DELEGATE_ASSIGNMENT; + else + { + impl->handler = handler; + if (impl->status != Started && impl->handler) + IAsyncOperationCompletedHandler_IInspectable_Invoke(impl->handler, &impl->IAsyncOperation_IInspectable_iface, impl->status); + hr = S_OK; + } + + LeaveCriticalSection(&impl->cs); + + return hr; }
static HRESULT WINAPI async_operation_get_Completed( IAsyncOperation_IInspectable *iface, IAsyncOperationCompletedHandler_IInspectable **handler ) { - FIXME("iface %p, handler %p stub!\n", iface, handler); - return E_NOTIMPL; + FIXME("iface %p, handler %p semi stub!\n", iface, handler); + *handler = NULL; + return S_OK; }
static HRESULT WINAPI async_operation_GetResults( IAsyncOperation_IInspectable *iface, IInspectable **results ) { - FIXME("iface %p, results %p stub!\n", iface, results); - return E_NOTIMPL; + /* NOTE: Despite the name, this function only returns one result! */ + struct async_operation *impl = impl_from_IAsyncOperation_IInspectable(iface); + HRESULT hr; + + TRACE("iface %p, results %p.\n", iface, results); + + EnterCriticalSection(&impl->cs); + + if (!impl->result) + hr = E_UNEXPECTED; + else if (impl->status != Completed) + hr = E_ILLEGAL_METHOD_CALL; + else + { + *results = impl->result; + impl->result = NULL; /* NOTE: AsyncOperation gives up it's reference to result here! */ + hr = S_OK; + } + + LeaveCriticalSection(&impl->cs); + + return hr; }
static const struct IAsyncOperation_IInspectableVtbl async_operation_vtbl = @@ -159,14 +214,26 @@ static HRESULT WINAPI async_operation_info_get_Id( IAsyncInfo *iface, UINT32 *id
static HRESULT WINAPI async_operation_info_get_Status( IAsyncInfo *iface, AsyncStatus *status ) { - FIXME("iface %p, status %p stub!\n", iface, status); - return E_NOTIMPL; + struct async_operation *impl = impl_from_IAsyncInfo(iface); + TRACE("iface %p, status %p.\n", iface, status); + + EnterCriticalSection(&impl->cs); + *status = impl->status; + LeaveCriticalSection(&impl->cs); + + return S_OK; }
static HRESULT WINAPI async_operation_info_get_ErrorCode( IAsyncInfo *iface, HRESULT *error_code ) { - FIXME("iface %p, error_code %p stub!\n", iface, error_code); - return E_NOTIMPL; + struct async_operation *impl = impl_from_IAsyncInfo(iface); + TRACE("iface %p, error_code %p.\n", iface, error_code); + + EnterCriticalSection(&impl->cs); + *error_code = impl->hr; + LeaveCriticalSection(&impl->cs); + + return S_OK; }
static HRESULT WINAPI async_operation_info_Cancel( IAsyncInfo *iface ) @@ -199,7 +266,28 @@ static const struct IAsyncInfoVtbl async_operation_info_vtbl = async_operation_info_Close };
-HRESULT async_operation_create( const GUID *iid, IAsyncOperation_IInspectable **out ) +static void CALLBACK async_run_cb(TP_CALLBACK_INSTANCE *instance, void *context, TP_WORK *work) +{ + struct async_operation *impl = context; + IInspectable *result = NULL; + HRESULT hr; + + hr = impl->worker(impl->data, &result); + impl->result = result; + + EnterCriticalSection(&impl->cs); + if (FAILED(hr)) impl->status = Error; + else impl->status = Completed; + + if (impl->handler) IAsyncOperationCompletedHandler_IInspectable_Invoke( impl->handler, + &impl->IAsyncOperation_IInspectable_iface, + impl->status ); + + impl->hr = hr; + LeaveCriticalSection(&impl->cs); +} + +HRESULT async_operation_create( const GUID *iid, void *data, async_operation_worker worker, IAsyncOperation_IInspectable **out ) { struct async_operation *impl;
@@ -214,6 +302,16 @@ HRESULT async_operation_create( const GUID *iid, IAsyncOperation_IInspectable ** impl->iid = iid; impl->ref = 1;
+ impl->worker = worker; + impl->data = data; + impl->async_run_work = CreateThreadpoolWork(async_run_cb, impl, NULL); + impl->status = Started; + + InitializeCriticalSection(&impl->cs); + impl->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": async_operation.cs"); + + SubmitThreadpoolWork(impl->async_run_work); + *out = &impl->IAsyncOperation_IInspectable_iface; TRACE("created %p\n", *out); return S_OK; diff --git a/dlls/windows.media.speech/private.h b/dlls/windows.media.speech/private.h index 1cf61c51f1e..ed11cad7966 100644 --- a/dlls/windows.media.speech/private.h +++ b/dlls/windows.media.speech/private.h @@ -69,7 +69,9 @@ struct vector_iids const GUID *view; };
-HRESULT async_operation_create( const GUID *iid, IAsyncOperation_IInspectable **out ); +typedef HRESULT (WINAPI *async_operation_worker)( void *data, IInspectable **result ); + +HRESULT async_operation_create( const GUID *iid, void *data, async_operation_worker worker, IAsyncOperation_IInspectable **out );
HRESULT typed_event_handlers_append( struct list *list, ITypedEventHandler_IInspectable_IInspectable *handler, EventRegistrationToken *token ); HRESULT typed_event_handlers_remove( struct list *list, EventRegistrationToken *token ); diff --git a/dlls/windows.media.speech/recognizer.c b/dlls/windows.media.speech/recognizer.c index b16ecb24641..fa36b7937b0 100644 --- a/dlls/windows.media.speech/recognizer.c +++ b/dlls/windows.media.speech/recognizer.c @@ -348,12 +348,20 @@ static HRESULT WINAPI recognizer_get_UIOptions( ISpeechRecognizer *iface, ISpeec return E_NOTIMPL; }
+static HRESULT WINAPI compile_worker( void *data, IInspectable **result ) +{ + return S_OK; +} + static HRESULT WINAPI recognizer_CompileConstraintsAsync( ISpeechRecognizer *iface, IAsyncOperation_SpeechRecognitionCompilationResult **operation ) { IAsyncOperation_IInspectable **value = (IAsyncOperation_IInspectable **)operation; + struct recognizer *impl = impl_from_ISpeechRecognizer(iface); + FIXME("iface %p, operation %p semi-stub!\n", iface, operation); - return async_operation_create(&IID_IAsyncOperation_SpeechRecognitionCompilationResult, value); + + return async_operation_create(&IID_IAsyncOperation_SpeechRecognitionCompilationResult, impl, compile_worker, value); }
static HRESULT WINAPI recognizer_RecognizeAsync( ISpeechRecognizer *iface, diff --git a/dlls/windows.media.speech/tests/speech.c b/dlls/windows.media.speech/tests/speech.c index ef75178f8c1..9dbd7b9ee52 100644 --- a/dlls/windows.media.speech/tests/speech.c +++ b/dlls/windows.media.speech/tests/speech.c @@ -953,55 +953,59 @@ static void test_SpeechRecognizer(void)
handler = (void*)0xdeadbeef; hr = IAsyncOperation_SpeechRecognitionCompilationResult_get_Completed(operation, &handler); - todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - todo_wine ok(handler == NULL, "Handler had value %p.\n", handler); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(handler == NULL, "Handler had value %p.\n", handler);
if (FAILED(hr)) goto skip_operation;
compilation_result = (void*)0xdeadbeef; hr = IAsyncOperation_SpeechRecognitionCompilationResult_GetResults(operation, &compilation_result); todo_wine ok(hr == E_ILLEGAL_METHOD_CALL, "Got unexpected hr %#lx.\n", hr); - todo_wine ok(compilation_result == (void*)0xdeadbeef, "Compilation result had value %p.\n", compilation_result); + ok(compilation_result == (void*)0xdeadbeef, "Compilation result had value %p.\n", compilation_result);
hr = IAsyncOperation_SpeechRecognitionCompilationResult_put_Completed(operation, &compilation_handler.IAsyncHandler_Compilation_iface); - todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - todo_wine check_refcount(&compilation_handler.IAsyncHandler_Compilation_iface, 1); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + check_refcount(&compilation_handler.IAsyncHandler_Compilation_iface, 1);
WaitForSingleObject(compilation_handler.event_finished, INFINITE); CloseHandle(compilation_handler.event_finished);
hr = IAsyncOperation_SpeechRecognitionCompilationResult_put_Completed(operation, NULL); - todo_wine ok(hr == E_ILLEGAL_DELEGATE_ASSIGNMENT, "Got unexpected hr %#lx.\n", hr); + ok(hr == E_ILLEGAL_DELEGATE_ASSIGNMENT, "Got unexpected hr %#lx.\n", hr);
handler = (void*)0xdeadbeef; hr = IAsyncOperation_SpeechRecognitionCompilationResult_get_Completed(operation, &handler); - todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - todo_wine ok(handler == NULL, "Handler had value %p.\n", handler); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(handler == NULL, "Handler had value %p.\n", handler);
hr = IAsyncOperation_SpeechRecognitionCompilationResult_GetResults(operation, &compilation_result); todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - todo_wine check_interface(compilation_result, &IID_IAgileObject, TRUE);
- hr = ISpeechRecognitionCompilationResult_get_Status(compilation_result, &result_status); - todo_wine ok(hr == S_OK, "ISpeechRecognitionCompilationResult_get_Status failed, hr %#lx.\n", hr); - todo_wine ok(result_status == SpeechRecognitionResultStatus_Success, "Got unexpected status %#x.\n", result_status); + if (SUCCEEDED(hr)) + { + todo_wine check_interface(compilation_result, &IID_IAgileObject, TRUE); + + hr = ISpeechRecognitionCompilationResult_get_Status(compilation_result, &result_status); + todo_wine ok(hr == S_OK, "ISpeechRecognitionCompilationResult_get_Status failed, hr %#lx.\n", hr); + todo_wine ok(result_status == SpeechRecognitionResultStatus_Success, "Got unexpected status %#x.\n", result_status);
- ref = ISpeechRecognitionCompilationResult_Release(compilation_result); - todo_wine ok(!ref , "Got unexpected ref %lu.\n", ref); + ref = ISpeechRecognitionCompilationResult_Release(compilation_result); + todo_wine ok(!ref , "Got unexpected ref %lu.\n", ref); + }
hr = IAsyncOperation_SpeechRecognitionCompilationResult_GetResults(operation, &compilation_result); - todo_wine ok(hr == E_UNEXPECTED, "Got unexpected hr %#lx.\n", hr); + ok(hr == E_UNEXPECTED, "Got unexpected hr %#lx.\n", hr);
hr = IAsyncOperation_SpeechRecognitionCompilationResult_QueryInterface(operation, &IID_IAsyncInfo, (void **)&info); - todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
/* Check if AsyncInfo and AsyncOperation share the same refcount. */ IAsyncOperation_SpeechRecognitionCompilationResult_AddRef(operation); - todo_wine check_refcount(operation, 3); - todo_wine check_refcount(info, 3); + check_refcount(operation, 3); + check_refcount(info, 3);
IAsyncOperation_SpeechRecognitionCompilationResult_Release(operation); - todo_wine check_refcount(info, 2); + check_refcount(info, 2);
id = 0xdeadbeef; hr = IAsyncInfo_get_Id(info, &id); @@ -1010,16 +1014,16 @@ static void test_SpeechRecognizer(void)
async_status = 0xdeadbeef; hr = IAsyncInfo_get_Status(info, &async_status); - todo_wine ok(hr == S_OK, "IAsyncInfo_get_Status failed, hr %#lx.\n", hr); - todo_wine ok(async_status == Completed, "Status was %#x.\n", async_status); + ok(hr == S_OK, "IAsyncInfo_get_Status failed, hr %#lx.\n", hr); + ok(async_status == Completed, "Status was %#x.\n", async_status);
hr = IAsyncInfo_Cancel(info); todo_wine ok(hr == S_OK, "IAsyncInfo_Cancel failed, hr %#lx.\n", hr);
async_status = 0xdeadbeef; hr = IAsyncInfo_get_Status(info, &async_status); - todo_wine ok(hr == S_OK, "IAsyncInfo_get_Status failed, hr %#lx.\n", hr); - todo_wine ok(async_status == Completed, "Status was %#x.\n", async_status); + ok(hr == S_OK, "IAsyncInfo_get_Status failed, hr %#lx.\n", hr); + ok(async_status == Completed, "Status was %#x.\n", async_status);
hr = IAsyncInfo_Close(info); todo_wine ok(hr == S_OK, "IAsyncInfo_Close failed, hr %#lx.\n", hr); @@ -1032,7 +1036,7 @@ static void test_SpeechRecognizer(void) todo_wine ok(async_status == AsyncStatus_Closed, "Status was %#x.\n", async_status);
ref = IAsyncInfo_Release(info); - todo_wine ok(ref == 1, "Got unexpected ref %lu.\n", ref); + ok(ref == 1, "Got unexpected ref %lu.\n", ref);
hr = IAsyncOperation_SpeechRecognitionCompilationResult_put_Completed(operation, NULL); todo_wine ok(hr == E_ILLEGAL_METHOD_CALL, "Got unexpected hr %#lx.\n", hr); @@ -1051,35 +1055,35 @@ static void test_SpeechRecognizer(void) ok(compilation_handler2.event_finished != NULL, "Finished event wasn't created.\n");
hr = ISpeechRecognizer_CompileConstraintsAsync(recognizer, &operation); - todo_wine ok(hr == S_OK, "ISpeechRecognizer_CompileConstraintsAsync failed, hr %#lx.\n", hr); - todo_wine check_interface(operation, &IID_IAgileObject, TRUE); + ok(hr == S_OK, "ISpeechRecognizer_CompileConstraintsAsync failed, hr %#lx.\n", hr); + check_interface(operation, &IID_IAgileObject, TRUE);
hr = IAsyncOperation_SpeechRecognitionCompilationResult_QueryInterface(operation, &IID_IAsyncInfo, (void **)&info); - todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
/* This one can fail, if the async operation had already finished */ compilation_result = (void*)0xdeadbeef; hr = IAsyncOperation_SpeechRecognitionCompilationResult_GetResults(operation, &compilation_result); todo_wine ok(hr == E_ILLEGAL_METHOD_CALL, "Got unexpected hr %#lx.\n", hr); - todo_wine ok(compilation_result == (void*)0xdeadbeef, "Compilation result had value %p.\n", compilation_result); + ok(compilation_result == (void*)0xdeadbeef, "Compilation result had value %p.\n", compilation_result);
async_status = 0xdeadbeef; hr = IAsyncInfo_get_Status(info, &async_status); - todo_wine ok(hr == S_OK, "IAsyncInfo_get_Status failed, hr %#lx.\n", hr); - todo_wine ok(async_status == Started || async_status == Completed, "Status was %#x.\n", async_status); + ok(hr == S_OK, "IAsyncInfo_get_Status failed, hr %#lx.\n", hr); + ok(async_status == Started || async_status == Completed, "Status was %#x.\n", async_status);
IAsyncInfo_Release(info);
hr = IAsyncOperation_SpeechRecognitionCompilationResult_put_Completed(operation, &compilation_handler2.IAsyncHandler_Compilation_iface); - todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
WaitForSingleObject(compilation_handler2.event_finished, INFINITE); CloseHandle(compilation_handler2.event_finished);
async_status = 0xdeadbeef; hr = IAsyncInfo_get_Status(info, &async_status); - todo_wine ok(hr == S_OK, "IAsyncInfo_get_Status failed, hr %#lx.\n", hr); - todo_wine ok(async_status == Completed, "Status was %#x.\n", async_status); + ok(hr == S_OK, "IAsyncInfo_get_Status failed, hr %#lx.\n", hr); + ok(async_status == Completed, "Status was %#x.\n", async_status);
skip_operation: ref = IAsyncOperation_SpeechRecognitionCompilationResult_Release(operation);
Hi Bernhard,
On 4/6/22 18:28, Bernhard Kölbl wrote:
Signed-off-by: Bernhard Kölbl besentv@gmail.com
v2: Make IAsyncOperation truely asynchronous using a threadpool worker. v3: Fix test failures.
dlls/windows.media.speech/async.c | 120 ++++++++++++++++++++--- dlls/windows.media.speech/private.h | 4 +- dlls/windows.media.speech/recognizer.c | 10 +- dlls/windows.media.speech/tests/speech.c | 70 ++++++------- 4 files changed, 158 insertions(+), 46 deletions(-)
diff --git a/dlls/windows.media.speech/async.c b/dlls/windows.media.speech/async.c index 94d0b35d9c1..5042a31b503 100644 --- a/dlls/windows.media.speech/async.c +++ b/dlls/windows.media.speech/async.c @@ -35,6 +35,18 @@ struct async_operation IAsyncInfo IAsyncInfo_iface; const GUID *iid; LONG ref;
IAsyncOperationCompletedHandler_IInspectable *handler;
IInspectable *result;
async_operation_worker worker;
TP_WORK *async_run_work;
void *data;
CRITICAL_SECTION cs;
AsyncStatus status;
HRESULT hr; };
static inline struct async_operation *impl_from_IAsyncOperation_IInspectable(IAsyncOperation_IInspectable *iface)
@@ -84,7 +96,11 @@ static ULONG WINAPI async_operation_Release( IAsyncOperation_IInspectable *iface TRACE("iface %p, ref %lu.\n", iface, ref);
if (!ref)
{
if (impl->result) IInspectable_Release(impl->result);
DeleteCriticalSection(&impl->cs); free(impl);
}
return ref; }
As described more in detail below, I think you will need to cleanup the thread pool work item there, calling Cancel and Close, and waiting for it to complete probably. Or making sure it always completes before the final async operation Release.
You'll still need to call CloseThreadpoolWork in any case.
@@ -110,21 +126,60 @@ static HRESULT WINAPI async_operation_GetTrustLevel( IAsyncOperation_IInspectabl static HRESULT WINAPI async_operation_put_Completed( IAsyncOperation_IInspectable *iface, IAsyncOperationCompletedHandler_IInspectable *handler ) {
- FIXME("iface %p, handler %p stub!\n", iface, handler);
- return E_NOTIMPL;
- struct async_operation *impl = impl_from_IAsyncOperation_IInspectable(iface);
- HRESULT hr;
- TRACE("iface %p, handler %p.\n", iface, handler);
- EnterCriticalSection(&impl->cs);
- if (impl->handler)
hr = E_ILLEGAL_DELEGATE_ASSIGNMENT;
- else
- {
impl->handler = handler;
if (impl->status != Started && impl->handler)
IAsyncOperationCompletedHandler_IInspectable_Invoke(impl->handler, &impl->IAsyncOperation_IInspectable_iface, impl->status);
hr = S_OK;
- }
- LeaveCriticalSection(&impl->cs);
- return hr; }
I find it surprising, but as far as I can test, a NULL handler is perfectly valid, but additionally, you can indeed only set the handler once, even if you've set NULL the first time.
IMHO you don't need to implement that behavior, and instead I think it'd be better to check that handler parameter is not NULL and return an error if it is (eventually with a FIXME as it would differ from what native does).
This would save you the impl->handler check.
static HRESULT WINAPI async_operation_info_Cancel( IAsyncInfo *iface ) @@ -199,7 +266,28 @@ static const struct IAsyncInfoVtbl async_operation_info_vtbl = async_operation_info_Close };
I think it could be good to implement Cancel and Close too, though as far as I can see it also means you need to setup a thread pool cleanup group to able to cancel, close and wait for the work item.
I never used it but there's a sample there:
https://docs.microsoft.com/en-us/windows/win32/procthread/using-the-thread-p...
The idea is that when the async operation is released, you will also either want it to cancel and wait for the work to complete, so that it doesn't outlive the async operation and later tries accessing it.
Or, alternatively, you need an additional reference on the async operation itself while the work is not completed.
As there's a Cancel and Close method I think you'll need the thread pool cleanup group anyway. Whether native keeps a ref on the async operation while the work is not complete, or whether it waits for its completion on async operation final release is a matter of testing but it may be a bit tricky.
-HRESULT async_operation_create( const GUID *iid, IAsyncOperation_IInspectable **out ) +static void CALLBACK async_run_cb(TP_CALLBACK_INSTANCE *instance, void *context, TP_WORK *work) +{
- struct async_operation *impl = context;
- IInspectable *result = NULL;
- HRESULT hr;
- hr = impl->worker(impl->data, &result);
- impl->result = result;
- EnterCriticalSection(&impl->cs);
- if (FAILED(hr)) impl->status = Error;
- else impl->status = Completed;
- if (impl->handler) IAsyncOperationCompletedHandler_IInspectable_Invoke( impl->handler,
&impl->IAsyncOperation_IInspectable_iface,
impl->status );
- impl->hr = hr;
- LeaveCriticalSection(&impl->cs);
+}
I find it a bit weird that impl->hr is assigned after the handler has been invoked. What if the handler calls get_ErrorCode, does it always get 0 here?
I suspect hr should be set first, so that in the error case the handler is Invoked with Error status, and can retrieve hr through get_ErrorCode.
+HRESULT async_operation_create( const GUID *iid, void *data, async_operation_worker worker, IAsyncOperation_IInspectable **out ) { struct async_operation *impl;
@@ -214,6 +302,16 @@ HRESULT async_operation_create( const GUID *iid, IAsyncOperation_IInspectable ** impl->iid = iid; impl->ref = 1;
- impl->worker = worker;
- impl->data = data;
- impl->async_run_work = CreateThreadpoolWork(async_run_cb, impl, NULL);
- impl->status = Started;
- InitializeCriticalSection(&impl->cs);
- impl->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": async_operation.cs");
- SubmitThreadpoolWork(impl->async_run_work);
*out = &impl->IAsyncOperation_IInspectable_iface; TRACE("created %p\n", *out); return S_OK;
You probably need to handle the potential CreateThreadpoolWork failure.
diff --git a/dlls/windows.media.speech/recognizer.c b/dlls/windows.media.speech/recognizer.c index b16ecb24641..fa36b7937b0 100644 --- a/dlls/windows.media.speech/recognizer.c +++ b/dlls/windows.media.speech/recognizer.c @@ -348,12 +348,20 @@ static HRESULT WINAPI recognizer_get_UIOptions( ISpeechRecognizer *iface, ISpeec return E_NOTIMPL; }
+static HRESULT WINAPI compile_worker( void *data, IInspectable **result ) +{
- return S_OK;
+}
- static HRESULT WINAPI recognizer_CompileConstraintsAsync( ISpeechRecognizer *iface, IAsyncOperation_SpeechRecognitionCompilationResult **operation ) { IAsyncOperation_IInspectable **value = (IAsyncOperation_IInspectable **)operation;
- struct recognizer *impl = impl_from_ISpeechRecognizer(iface);
FIXME("iface %p, operation %p semi-stub!\n", iface, operation);
- return async_operation_create(&IID_IAsyncOperation_SpeechRecognitionCompilationResult, value);
- return async_operation_create(&IID_IAsyncOperation_SpeechRecognitionCompilationResult, impl, compile_worker, value); }
Although you may want to pass impl there later, as you'll probably need access to the recognizer in compiler_worker i think you should not pass it yet, and for instance, pass NULL data, or even better, remove the data parameter for now.
Later, when you'll need it, you will probably have to increase its reference count before passing it to async operation, so that the async operation doesn't outlive it.
Maybe for clarity purposes it'd be even better if data was a reference counted interface, like an IInspectable, which the async operation can keep a ref on, itself, in the async_operation_create, and release it on its destruction.
Cheers,
And use it for ISpeechRecognizer_CompileConstraintsAsync.
Signed-off-by: Bernhard Kölbl besentv@gmail.com --- dlls/windows.media.speech/recognizer.c | 124 ++++++++++++++++++++++- dlls/windows.media.speech/tests/speech.c | 17 ++-- 2 files changed, 130 insertions(+), 11 deletions(-)
diff --git a/dlls/windows.media.speech/recognizer.c b/dlls/windows.media.speech/recognizer.c index fa36b7937b0..309ec291273 100644 --- a/dlls/windows.media.speech/recognizer.c +++ b/dlls/windows.media.speech/recognizer.c @@ -23,6 +23,128 @@
WINE_DEFAULT_DEBUG_CHANNEL(speech);
+/* + * + * ISpeechRecognitionCompilationResult + * + */ + +struct compilation_result +{ + ISpeechRecognitionCompilationResult ISpeechRecognitionCompilationResult_iface; + LONG ref; + + SpeechRecognitionResultStatus status; +}; + +static inline struct compilation_result *impl_from_ISpeechRecognitionCompilationResult( ISpeechRecognitionCompilationResult *iface ) +{ + return CONTAINING_RECORD(iface, struct compilation_result, ISpeechRecognitionCompilationResult_iface); +} + +static HRESULT WINAPI compilation_result_QueryInterface( ISpeechRecognitionCompilationResult *iface, REFIID iid, void **out ) +{ + struct compilation_result *impl = impl_from_ISpeechRecognitionCompilationResult(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_IAgileObject) || + IsEqualGUID(iid, &IID_ISpeechRecognitionCompilationResult)) + { + IInspectable_AddRef((*out = &impl->ISpeechRecognitionCompilationResult_iface)); + return S_OK; + } + + WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI compilation_result_AddRef( ISpeechRecognitionCompilationResult *iface ) +{ + struct compilation_result *impl = impl_from_ISpeechRecognitionCompilationResult(iface); + ULONG ref = InterlockedIncrement(&impl->ref); + TRACE("iface %p, ref %lu.\n", iface, ref); + return ref; +} + +static ULONG WINAPI compilation_result_Release( ISpeechRecognitionCompilationResult *iface ) +{ + struct compilation_result *impl = impl_from_ISpeechRecognitionCompilationResult(iface); + + ULONG ref = InterlockedDecrement(&impl->ref); + TRACE("iface %p, ref %lu.\n", iface, ref); + + if (!ref) + free(impl); + + return ref; +} + +static HRESULT WINAPI compilation_result_GetIids( ISpeechRecognitionCompilationResult *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 compilation_result_GetRuntimeClassName( ISpeechRecognitionCompilationResult *iface, HSTRING *class_name ) +{ + FIXME("iface %p, class_name %p stub!\n", iface, class_name); + return E_NOTIMPL; +} + +static HRESULT WINAPI compilation_result_GetTrustLevel( ISpeechRecognitionCompilationResult *iface, TrustLevel *trust_level ) +{ + FIXME("iface %p, trust_level %p stub!\n", iface, trust_level); + return E_NOTIMPL; +} + +static HRESULT WINAPI compilation_result_get_Status( ISpeechRecognitionCompilationResult *iface, SpeechRecognitionResultStatus *value ) +{ + struct compilation_result *impl = impl_from_ISpeechRecognitionCompilationResult(iface); + TRACE("iface %p, value %p.\n", iface, value); + *value = impl->status; + return S_OK; +} + +static const struct ISpeechRecognitionCompilationResultVtbl compilation_result_vtbl = +{ + /* IUnknown methods */ + compilation_result_QueryInterface, + compilation_result_AddRef, + compilation_result_Release, + /* IInspectable methods */ + compilation_result_GetIids, + compilation_result_GetRuntimeClassName, + compilation_result_GetTrustLevel, + /* ISpeechRecognitionCompilationResult methods */ + compilation_result_get_Status +}; + + +static HRESULT WINAPI compilation_result_create( SpeechRecognitionResultStatus status, ISpeechRecognitionCompilationResult **out ) +{ + struct compilation_result *impl; + + TRACE("out %p.\n", out); + + if (!(impl = calloc(1, sizeof(*impl)))) + { + *out = NULL; + return E_OUTOFMEMORY; + } + + impl->ISpeechRecognitionCompilationResult_iface.lpVtbl = &compilation_result_vtbl; + impl->ref = 1; + impl->status = status; + + *out = &impl->ISpeechRecognitionCompilationResult_iface; + TRACE("created %p\n", *out); + return S_OK; +} + /* * * SpeechContinuousRecognitionSession @@ -350,7 +472,7 @@ static HRESULT WINAPI recognizer_get_UIOptions( ISpeechRecognizer *iface, ISpeec
static HRESULT WINAPI compile_worker( void *data, IInspectable **result ) { - return S_OK; + return compilation_result_create(SpeechRecognitionResultStatus_Success, (ISpeechRecognitionCompilationResult **) result); }
static HRESULT WINAPI recognizer_CompileConstraintsAsync( ISpeechRecognizer *iface, diff --git a/dlls/windows.media.speech/tests/speech.c b/dlls/windows.media.speech/tests/speech.c index 9dbd7b9ee52..655e9b01e14 100644 --- a/dlls/windows.media.speech/tests/speech.c +++ b/dlls/windows.media.speech/tests/speech.c @@ -979,19 +979,16 @@ static void test_SpeechRecognizer(void) ok(handler == NULL, "Handler had value %p.\n", handler);
hr = IAsyncOperation_SpeechRecognitionCompilationResult_GetResults(operation, &compilation_result); - todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
- if (SUCCEEDED(hr)) - { - todo_wine check_interface(compilation_result, &IID_IAgileObject, TRUE); + check_interface(compilation_result, &IID_IAgileObject, TRUE);
- hr = ISpeechRecognitionCompilationResult_get_Status(compilation_result, &result_status); - todo_wine ok(hr == S_OK, "ISpeechRecognitionCompilationResult_get_Status failed, hr %#lx.\n", hr); - todo_wine ok(result_status == SpeechRecognitionResultStatus_Success, "Got unexpected status %#x.\n", result_status); + hr = ISpeechRecognitionCompilationResult_get_Status(compilation_result, &result_status); + ok(hr == S_OK, "ISpeechRecognitionCompilationResult_get_Status failed, hr %#lx.\n", hr); + ok(result_status == SpeechRecognitionResultStatus_Success, "Got unexpected status %#x.\n", result_status);
- ref = ISpeechRecognitionCompilationResult_Release(compilation_result); - todo_wine ok(!ref , "Got unexpected ref %lu.\n", ref); - } + ref = ISpeechRecognitionCompilationResult_Release(compilation_result); + ok(!ref , "Got unexpected ref %lu.\n", ref);
hr = IAsyncOperation_SpeechRecognitionCompilationResult_GetResults(operation, &compilation_result); ok(hr == E_UNEXPECTED, "Got unexpected hr %#lx.\n", hr);