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)
Together with some tests 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 | 161 +++++++++++++++++++++++ include/windows.foundation.idl | 2 + 6 files changed, 326 insertions(+), 3 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..9905a6d75ab --- /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 8093c4b95b8..542d6fcf8d0 100644 --- a/dlls/windows.media.speech/tests/speech.c +++ b/dlls/windows.media.speech/tests/speech.c @@ -52,6 +52,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 +232,83 @@ 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; + 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); + ok(impl->thread_id == id, "thread id %lu not matching %lu.\n", impl->thread_id, id); + 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; @@ -729,6 +812,8 @@ 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; IVector_ISpeechRecognitionConstraint *constraints = NULL; ISpeechContinuousRecognitionSession *session = NULL; ISpeechRecognizerFactory *sr_factory = NULL; @@ -740,11 +825,15 @@ 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; EventRegistrationToken token = { .value = 0 }; + AsyncStatus async_status; HSTRING hstr, hstr_lang; HRESULT hr; + UINT32 id; LONG ref;
hr = RoInitialize(RO_INIT_MULTITHREADED); @@ -848,6 +937,78 @@ 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(); + + if (!compilation_handler.event_finished) goto skip_compile; + + hr = ISpeechRecognizer_CompileConstraintsAsync(recognizer, &operation); + ok(hr == S_OK, "ISpeechRecognizer_CompileConstraintsAsync failed, hr %#lx.\n", hr); + check_interface(operation, &IID_IAgileObject, TRUE); + + 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; + + hr = IAsyncOperation_SpeechRecognitionCompilationResult_put_Completed(operation, &compilation_handler.IAsyncHandler_Compilation_iface); + todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + check_refcount(&compilation_handler.IAsyncHandler_Compilation_iface, 1); + + WaitForSingleObject(compilation_handler.event_finished, INFINITE); + + 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_QueryInterface(operation, &IID_IAsyncInfo, (void **)&info); + todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + IAsyncInfo_AddRef(info); + check_refcount(operation, 3); + check_refcount(info, 3); + + IAsyncOperation_SpeechRecognitionCompilationResult_AddRef(operation); + check_refcount(operation, 4); + check_refcount(info, 4); + IAsyncOperation_SpeechRecognitionCompilationResult_Release(operation); + + ref = IAsyncInfo_Release(info); + todo_wine ok(ref == 2, "Got unexpected ref %lu.\n", ref); + + 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 = IAsyncOperation_SpeechRecognitionCompilationResult_put_Completed(operation, NULL); + todo_wine ok(hr == E_ILLEGAL_DELEGATE_ASSIGNMENT, "Got unexpected hr %#lx.\n", hr); + + hr = IAsyncInfo_Close(info); + todo_wine ok(hr == S_OK, "IAsyncInfo_Close failed, hr %#lx.\n", hr); + + 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); + +skip_operation: + ref = IAsyncOperation_SpeechRecognitionCompilationResult_Release(operation); + ok(!ref, "Got unexpected ref %lu.\n", ref); + + CloseHandle(compilation_handler.event_finished); + +skip_compile: 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 *>;
On 3/31/22 18:17, Bernhard Kölbl wrote:
hr = RoInitialize(RO_INIT_MULTITHREADED);
@@ -848,6 +937,78 @@ 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();
if (!compilation_handler.event_finished) goto skip_compile;
I don't think this will ever fail. You can probably instead add an ok to check the event, and ignore failures. If it fails and times-out the test message will be enough to tell.
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 9905a6d75ab..5b74ec60be1 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: Bernhard Kölbl besentv@gmail.com --- dlls/windows.media.speech/async.c | 40 ++++++++++++++++++++---- dlls/windows.media.speech/private.h | 1 + dlls/windows.media.speech/recognizer.c | 10 +++++- dlls/windows.media.speech/tests/speech.c | 25 +++++++-------- 4 files changed, 55 insertions(+), 21 deletions(-)
diff --git a/dlls/windows.media.speech/async.c b/dlls/windows.media.speech/async.c index 5b74ec60be1..767b4a3a4e4 100644 --- a/dlls/windows.media.speech/async.c +++ b/dlls/windows.media.speech/async.c @@ -35,6 +35,10 @@ struct async_operation IAsyncInfo IAsyncInfo_iface; const GUID *iid; LONG ref; + + IAsyncOperationCompletedHandler_IInspectable *handler; + BOOLEAN handler_set; + AsyncStatus status; };
static inline struct async_operation *impl_from_IAsyncOperation_IInspectable(IAsyncOperation_IInspectable *iface) @@ -110,15 +114,26 @@ 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); + + TRACE("iface %p, handler %p.\n", iface, handler); + + if (impl->handler_set) return E_ILLEGAL_DELEGATE_ASSIGNMENT; + impl->handler = handler; + impl->handler_set = TRUE; + + if (impl->status == Completed) + return async_operation_notify(iface); + + return S_OK; }
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 ) @@ -159,8 +174,10 @@ 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); + *status = impl->status; + return S_OK; }
static HRESULT WINAPI async_operation_info_get_ErrorCode( IAsyncInfo *iface, HRESULT *error_code ) @@ -218,3 +235,14 @@ HRESULT async_operation_create( const GUID *iid, IAsyncOperation_IInspectable ** TRACE("created %p\n", *out); return S_OK; } + +HRESULT async_operation_notify( IAsyncOperation_IInspectable *operation ) +{ + struct async_operation *impl = impl_from_IAsyncOperation_IInspectable(operation); + + impl->status = Completed; + if (impl->handler) + IAsyncOperationCompletedHandler_IInspectable_Invoke(impl->handler, operation, impl->status); + + return S_OK; +} \ No newline at end of file diff --git a/dlls/windows.media.speech/private.h b/dlls/windows.media.speech/private.h index 1cf61c51f1e..aefadaf21c7 100644 --- a/dlls/windows.media.speech/private.h +++ b/dlls/windows.media.speech/private.h @@ -70,6 +70,7 @@ struct vector_iids };
HRESULT async_operation_create( const GUID *iid, IAsyncOperation_IInspectable **out ); +HRESULT async_operation_notify( IAsyncOperation_IInspectable *operation );
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..793be7d1749 100644 --- a/dlls/windows.media.speech/recognizer.c +++ b/dlls/windows.media.speech/recognizer.c @@ -352,8 +352,16 @@ static HRESULT WINAPI recognizer_CompileConstraintsAsync( ISpeechRecognizer *ifa IAsyncOperation_SpeechRecognitionCompilationResult **operation ) { IAsyncOperation_IInspectable **value = (IAsyncOperation_IInspectable **)operation; + HRESULT hr; + FIXME("iface %p, operation %p semi-stub!\n", iface, operation); - return async_operation_create(&IID_IAsyncOperation_SpeechRecognitionCompilationResult, value); + + *operation = NULL; + + if (FAILED(hr = async_operation_create(&IID_IAsyncOperation_SpeechRecognitionCompilationResult, value))) return hr; + async_operation_notify(*value); + + return S_OK; }
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 542d6fcf8d0..9c9ebf2c80c 100644 --- a/dlls/windows.media.speech/tests/speech.c +++ b/dlls/windows.media.speech/tests/speech.c @@ -949,24 +949,22 @@ 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); - - if (FAILED(hr)) goto skip_operation; + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(handler == NULL, "Handler had value %p.\n", handler);
hr = IAsyncOperation_SpeechRecognitionCompilationResult_put_Completed(operation, &compilation_handler.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); check_refcount(&compilation_handler.IAsyncHandler_Compilation_iface, 1);
WaitForSingleObject(compilation_handler.event_finished, INFINITE);
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_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);
IAsyncInfo_AddRef(info); check_refcount(operation, 3); @@ -978,7 +976,7 @@ static void test_SpeechRecognizer(void) IAsyncOperation_SpeechRecognitionCompilationResult_Release(operation);
ref = IAsyncInfo_Release(info); - todo_wine ok(ref == 2, "Got unexpected ref %lu.\n", ref); + ok(ref == 2, "Got unexpected ref %lu.\n", ref);
id = 0xdeadbeef; hr = IAsyncInfo_get_Id(info, &id); @@ -987,22 +985,21 @@ 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 = 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);
hr = IAsyncInfo_Close(info); todo_wine ok(hr == S_OK, "IAsyncInfo_Close failed, hr %#lx.\n", hr);
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);
-skip_operation: ref = IAsyncOperation_SpeechRecognitionCompilationResult_Release(operation); ok(!ref, "Got unexpected ref %lu.\n", ref);
On 3/31/22 18:17, Bernhard Kölbl wrote:
Signed-off-by: Bernhard Kölbl besentv@gmail.com
dlls/windows.media.speech/async.c | 40 ++++++++++++++++++++---- dlls/windows.media.speech/private.h | 1 + dlls/windows.media.speech/recognizer.c | 10 +++++- dlls/windows.media.speech/tests/speech.c | 25 +++++++-------- 4 files changed, 55 insertions(+), 21 deletions(-)
diff --git a/dlls/windows.media.speech/async.c b/dlls/windows.media.speech/async.c index 5b74ec60be1..767b4a3a4e4 100644 --- a/dlls/windows.media.speech/async.c +++ b/dlls/windows.media.speech/async.c @@ -35,6 +35,10 @@ struct async_operation IAsyncInfo IAsyncInfo_iface; const GUID *iid; LONG ref;
IAsyncOperationCompletedHandler_IInspectable *handler;
BOOLEAN handler_set;
AsyncStatus status; };
static inline struct async_operation *impl_from_IAsyncOperation_IInspectable(IAsyncOperation_IInspectable *iface)
@@ -110,15 +114,26 @@ 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);
TRACE("iface %p, handler %p.\n", iface, handler);
if (impl->handler_set) return E_ILLEGAL_DELEGATE_ASSIGNMENT;
impl->handler = handler;
impl->handler_set = TRUE;
if (impl->status == Completed)
return async_operation_notify(iface);
return S_OK; }
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 )
@@ -159,8 +174,10 @@ 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);
*status = impl->status;
return S_OK; }
static HRESULT WINAPI async_operation_info_get_ErrorCode( IAsyncInfo *iface, HRESULT *error_code )
@@ -218,3 +235,14 @@ HRESULT async_operation_create( const GUID *iid, IAsyncOperation_IInspectable ** TRACE("created %p\n", *out); return S_OK; }
+HRESULT async_operation_notify( IAsyncOperation_IInspectable *operation ) +{
- struct async_operation *impl = impl_from_IAsyncOperation_IInspectable(operation);
- impl->status = Completed;
- if (impl->handler)
IAsyncOperationCompletedHandler_IInspectable_Invoke(impl->handler, operation, impl->status);
- return S_OK;
+} \ No newline at end of file
It might require a bit of reorganization of the patches, to introduce the result first, but I think you only need one private helper overall, which would be something like "async_operation_complete". I don't think it makes much sense to have two separate "set_result" + "notify" operations.
It would also be interesting to add tests for the IAsyncInfo and results before setting a completion handler. As far as I can tell, the async is actually completed by the put_Completed call, not right when it is created. This would make the "already completed" case in put_Completed go away.
Imho adding the tests first, in a separate patch, including with the results tests also would make things a bit more clear in term of to which direction the implementation should go.
On 4/1/22 11:15, Rémi Bernon wrote:
On 3/31/22 18:17, Bernhard Kölbl wrote:
Signed-off-by: Bernhard Kölbl besentv@gmail.com
dlls/windows.media.speech/async.c | 40 ++++++++++++++++++++---- dlls/windows.media.speech/private.h | 1 + dlls/windows.media.speech/recognizer.c | 10 +++++- dlls/windows.media.speech/tests/speech.c | 25 +++++++-------- 4 files changed, 55 insertions(+), 21 deletions(-)
diff --git a/dlls/windows.media.speech/async.c b/dlls/windows.media.speech/async.c index 5b74ec60be1..767b4a3a4e4 100644 --- a/dlls/windows.media.speech/async.c +++ b/dlls/windows.media.speech/async.c @@ -35,6 +35,10 @@ struct async_operation IAsyncInfo IAsyncInfo_iface; const GUID *iid; LONG ref;
+ IAsyncOperationCompletedHandler_IInspectable *handler; + BOOLEAN handler_set; + AsyncStatus status; }; static inline struct async_operation *impl_from_IAsyncOperation_IInspectable(IAsyncOperation_IInspectable *iface) @@ -110,15 +114,26 @@ 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);
+ TRACE("iface %p, handler %p.\n", iface, handler);
+ if (impl->handler_set) return E_ILLEGAL_DELEGATE_ASSIGNMENT; + impl->handler = handler; + impl->handler_set = TRUE;
+ if (impl->status == Completed) + return async_operation_notify(iface);
+ return S_OK; } 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 ) @@ -159,8 +174,10 @@ 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); + *status = impl->status; + return S_OK; } static HRESULT WINAPI async_operation_info_get_ErrorCode( IAsyncInfo *iface, HRESULT *error_code ) @@ -218,3 +235,14 @@ HRESULT async_operation_create( const GUID *iid, IAsyncOperation_IInspectable ** TRACE("created %p\n", *out); return S_OK; }
+HRESULT async_operation_notify( IAsyncOperation_IInspectable *operation ) +{ + struct async_operation *impl = impl_from_IAsyncOperation_IInspectable(operation);
+ impl->status = Completed; + if (impl->handler)
IAsyncOperationCompletedHandler_IInspectable_Invoke(impl->handler, operation, impl->status);
+ return S_OK; +} \ No newline at end of file
It might require a bit of reorganization of the patches, to introduce the result first, but I think you only need one private helper overall, which would be something like "async_operation_complete". I don't think it makes much sense to have two separate "set_result" + "notify" operations.
It would also be interesting to add tests for the IAsyncInfo and results before setting a completion handler. As far as I can tell, the async is actually completed by the put_Completed call, not right when it is created. This would make the "already completed" case in put_Completed go away.
Imho adding the tests first, in a separate patch, including with the results tests also would make things a bit more clear in term of to which direction the implementation should go.
And I'm guessing here, but I think that truly async operations could work with a "async_operation_start", also called from put_Completed, starting a task on a worker thread at that point to also avoid the situation where the task completes before the handler has been provided.
FWIW instead (or in addition to an async_operation_complete) you could already introduce a "async_operation_start" helper, which would later be able to either queue long tasks to worker thread, or simply execute and complete short async tasks synchronously.
Yeah the many helpers aren't ideal. I'll rework the patches.
Thanks, Bernhard
Am Fr., 1. Apr. 2022 um 11:24 Uhr schrieb Rémi Bernon rbernon@codeweavers.com:
On 4/1/22 11:15, Rémi Bernon wrote:
On 3/31/22 18:17, Bernhard Kölbl wrote:
Signed-off-by: Bernhard Kölbl besentv@gmail.com
dlls/windows.media.speech/async.c | 40 ++++++++++++++++++++---- dlls/windows.media.speech/private.h | 1 + dlls/windows.media.speech/recognizer.c | 10 +++++- dlls/windows.media.speech/tests/speech.c | 25 +++++++-------- 4 files changed, 55 insertions(+), 21 deletions(-)
diff --git a/dlls/windows.media.speech/async.c b/dlls/windows.media.speech/async.c index 5b74ec60be1..767b4a3a4e4 100644 --- a/dlls/windows.media.speech/async.c +++ b/dlls/windows.media.speech/async.c @@ -35,6 +35,10 @@ struct async_operation IAsyncInfo IAsyncInfo_iface; const GUID *iid; LONG ref;
- IAsyncOperationCompletedHandler_IInspectable *handler;
- BOOLEAN handler_set;
- AsyncStatus status; }; static inline struct async_operation
*impl_from_IAsyncOperation_IInspectable(IAsyncOperation_IInspectable *iface) @@ -110,15 +114,26 @@ 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);
- TRACE("iface %p, handler %p.\n", iface, handler);
- if (impl->handler_set) return E_ILLEGAL_DELEGATE_ASSIGNMENT;
- impl->handler = handler;
- impl->handler_set = TRUE;
- if (impl->status == Completed)
return async_operation_notify(iface);
- return S_OK; } 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 ) @@ -159,8 +174,10 @@ 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);
- *status = impl->status;
- return S_OK; } static HRESULT WINAPI async_operation_info_get_ErrorCode( IAsyncInfo
*iface, HRESULT *error_code ) @@ -218,3 +235,14 @@ HRESULT async_operation_create( const GUID *iid, IAsyncOperation_IInspectable ** TRACE("created %p\n", *out); return S_OK; }
+HRESULT async_operation_notify( IAsyncOperation_IInspectable *operation ) +{
- struct async_operation *impl =
impl_from_IAsyncOperation_IInspectable(operation);
- impl->status = Completed;
- if (impl->handler)
IAsyncOperationCompletedHandler_IInspectable_Invoke(impl->handler, operation, impl->status);
- return S_OK;
+} \ No newline at end of file
It might require a bit of reorganization of the patches, to introduce the result first, but I think you only need one private helper overall, which would be something like "async_operation_complete". I don't think it makes much sense to have two separate "set_result" + "notify" operations.
It would also be interesting to add tests for the IAsyncInfo and results before setting a completion handler. As far as I can tell, the async is actually completed by the put_Completed call, not right when it is created. This would make the "already completed" case in put_Completed go away.
Imho adding the tests first, in a separate patch, including with the results tests also would make things a bit more clear in term of to which direction the implementation should go.
And I'm guessing here, but I think that truly async operations could work with a "async_operation_start", also called from put_Completed, starting a task on a worker thread at that point to also avoid the situation where the task completes before the handler has been provided.
FWIW instead (or in addition to an async_operation_complete) you could already introduce a "async_operation_start" helper, which would later be able to either queue long tasks to worker thread, or simply execute and complete short async tasks synchronously.
-- Rémi Bernon rbernon@codeweavers.com
And fix a mistake in include/windows.foundation.collections.idl.
Signed-off-by: Bernhard Kölbl besentv@gmail.com --- dlls/windows.media.speech/async.c | 32 +++++++++++++++++++--- dlls/windows.media.speech/tests/speech.c | 15 ++++++++++ include/windows.foundation.collections.idl | 2 +- 3 files changed, 44 insertions(+), 5 deletions(-)
diff --git a/dlls/windows.media.speech/async.c b/dlls/windows.media.speech/async.c index 767b4a3a4e4..88377311ba1 100644 --- a/dlls/windows.media.speech/async.c +++ b/dlls/windows.media.speech/async.c @@ -37,6 +37,7 @@ struct async_operation LONG ref;
IAsyncOperationCompletedHandler_IInspectable *handler; + IInspectable *result; BOOLEAN handler_set; AsyncStatus status; }; @@ -88,7 +89,10 @@ 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); free(impl); + }
return ref; } @@ -131,15 +135,23 @@ static HRESULT WINAPI async_operation_put_Completed( IAsyncOperation_IInspectabl static HRESULT WINAPI async_operation_get_Completed( IAsyncOperation_IInspectable *iface, IAsyncOperationCompletedHandler_IInspectable **handler ) { - FIXME("iface %p, handler %p semi stub!\n", iface, handler); + 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 ) +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); + + TRACE("iface %p, results %p.\n", iface, results); + + if (!impl->result) return E_UNEXPECTED; + + *results = impl->result; + impl->result = NULL; /* NOTE: AsyncOperation gives up it's reference to result here! */ + return S_OK; }
static const struct IAsyncOperation_IInspectableVtbl async_operation_vtbl = @@ -244,5 +256,17 @@ HRESULT async_operation_notify( IAsyncOperation_IInspectable *operation ) if (impl->handler) IAsyncOperationCompletedHandler_IInspectable_Invoke(impl->handler, operation, impl->status);
+ return S_OK; +} + +HRESULT async_operation_set_result( IAsyncOperation_IInspectable *operation, IInspectable *result ) +{ + struct async_operation *impl = impl_from_IAsyncOperation_IInspectable(operation); + + if(!result) return E_POINTER; + + if (!impl->result) IInspectable_AddRef((impl->result = result)); + else return E_FAIL; + return S_OK; } \ No newline at end of file diff --git a/dlls/windows.media.speech/tests/speech.c b/dlls/windows.media.speech/tests/speech.c index 9c9ebf2c80c..c0e990c575a 100644 --- a/dlls/windows.media.speech/tests/speech.c +++ b/dlls/windows.media.speech/tests/speech.c @@ -814,6 +814,7 @@ 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; @@ -963,6 +964,20 @@ static void test_SpeechRecognizer(void) 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); + + if(SUCCEEDED(hr)) + { + check_interface(compilation_result, &IID_IAgileObject, TRUE); + + 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); + hr = IAsyncOperation_SpeechRecognitionCompilationResult_QueryInterface(operation, &IID_IAsyncInfo, (void **)&info); ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
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); }
[
On 3/31/22 18:18, Bernhard Kölbl wrote:
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); } [
Although small and straightforward, I think this would deserve a separate patch, so that it can be picked up independently.
And use it for ISpeechRecognizer_CompileConstraintsAsync.
Signed-off-by: Bernhard Kölbl besentv@gmail.com --- dlls/windows.media.speech/private.h | 1 + dlls/windows.media.speech/recognizer.c | 134 ++++++++++++++++++++++- dlls/windows.media.speech/tests/speech.c | 16 +-- 3 files changed, 143 insertions(+), 8 deletions(-)
diff --git a/dlls/windows.media.speech/private.h b/dlls/windows.media.speech/private.h index aefadaf21c7..066fa8bd6f9 100644 --- a/dlls/windows.media.speech/private.h +++ b/dlls/windows.media.speech/private.h @@ -71,6 +71,7 @@ struct vector_iids
HRESULT async_operation_create( const GUID *iid, IAsyncOperation_IInspectable **out ); HRESULT async_operation_notify( IAsyncOperation_IInspectable *operation ); +HRESULT async_operation_set_result( IAsyncOperation_IInspectable *operation, IInspectable *result );
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 793be7d1749..f7aeafb5ad2 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 @@ -352,6 +474,7 @@ static HRESULT WINAPI recognizer_CompileConstraintsAsync( ISpeechRecognizer *ifa IAsyncOperation_SpeechRecognitionCompilationResult **operation ) { IAsyncOperation_IInspectable **value = (IAsyncOperation_IInspectable **)operation; + ISpeechRecognitionCompilationResult *result; HRESULT hr;
FIXME("iface %p, operation %p semi-stub!\n", iface, operation); @@ -359,9 +482,18 @@ static HRESULT WINAPI recognizer_CompileConstraintsAsync( ISpeechRecognizer *ifa *operation = NULL;
if (FAILED(hr = async_operation_create(&IID_IAsyncOperation_SpeechRecognitionCompilationResult, value))) return hr; - async_operation_notify(*value); + if (FAILED(hr = compilation_result_create(SpeechRecognitionResultStatus_Success, &result))) goto error;
+ hr = async_operation_set_result(*value, (IInspectable *)result); + ISpeechRecognitionCompilationResult_Release(result); + if (FAILED(hr)) goto error; + + async_operation_notify(*value); return S_OK; + +error: + if (*value) IAsyncOperation_IInspectable_Release(*value); + return hr; }
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 c0e990c575a..359aafe95f0 100644 --- a/dlls/windows.media.speech/tests/speech.c +++ b/dlls/windows.media.speech/tests/speech.c @@ -831,6 +831,7 @@ static void test_SpeechRecognizer(void) struct recognition_result_handler result_handler; struct compilation_handler compilation_handler; EventRegistrationToken token = { .value = 0 }; + SpeechRecognitionResultStatus result_status; AsyncStatus async_status; HSTRING hstr, hstr_lang; HRESULT hr; @@ -965,15 +966,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)) - { - check_interface(compilation_result, &IID_IAgileObject, TRUE); + check_interface(compilation_result, &IID_IAgileObject, TRUE);
- ref = ISpeechRecognitionCompilationResult_Release(compilation_result); - ok(!ref , "Got unexpected ref %lu.\n", ref); - } + 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); + 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);
Hi Bernhard,
On 3/31/22 18:17, Bernhard Kölbl wrote:
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)
I'm not completely sure what's the policy about this but it looks like you only need E_ILLEGAL_DELEGATE_ASSIGNMENT after all.
Most of these error seem very specific to MS implementation, I don't know if they will be very useful to add?
Hi,
I thought it's a bit odd to create an "island" with missing values in between. I think some of these might in fact become useful in the future like RO_E_CLOSED (likely IClosable) or the async operation not started value.
Bernhard
Rémi Bernon rbernon@codeweavers.com schrieb am Fr., 1. Apr. 2022, 10:47:
Hi Bernhard,
On 3/31/22 18:17, Bernhard Kölbl wrote:
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)
I'm not completely sure what's the policy about this but it looks like you only need E_ILLEGAL_DELEGATE_ASSIGNMENT after all.
Most of these error seem very specific to MS implementation, I don't know if they will be very useful to add? -- Rémi Bernon rbernon@codeweavers.com
Hi Rémi,
On 4/1/22 10:47, Rémi Bernon wrote:
I'm not completely sure what's the policy about this but it looks like you only need E_ILLEGAL_DELEGATE_ASSIGNMENT after all.
It's a public header, it's fine to add public declarations even if we don't need them (yet?) for Wine itself.
Jacek
On 4/1/22 11:36, Jacek Caban wrote:
Hi Rémi,
On 4/1/22 10:47, Rémi Bernon wrote:
I'm not completely sure what's the policy about this but it looks like you only need E_ILLEGAL_DELEGATE_ASSIGNMENT after all.
It's a public header, it's fine to add public declarations even if we don't need them (yet?) for Wine itself.
Jacek
Alright, looks good then!