[PATCH 1/6] include/winerror.h: Add missing WinRT HRESULT codes.
Taken from MSDN and original winerror.h. Signed-off-by: Bernhard Kölbl <besentv(a)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) -- 2.35.1
Together with some tests and return an instance of it in ISpeechRecognizer_CompileConstraintsAsync. Signed-off-by: Bernhard Kölbl <besentv(a)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 *>; -- 2.35.1
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. -- Rémi Bernon <rbernon(a)codeweavers.com>
Signed-off-by: Bernhard Kölbl <besentv(a)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; -- 2.35.1
Signed-off-by: Bernhard Kölbl <besentv(a)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); -- 2.35.1
On 3/31/22 18:17, Bernhard Kölbl wrote:
Signed-off-by: Bernhard Kölbl <besentv(a)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. -- Rémi Bernon <rbernon(a)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(a)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(a)codeweavers.com>
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(a)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(a)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(a)codeweavers.com>
And fix a mistake in include/windows.foundation.collections.idl. Signed-off-by: Bernhard Kölbl <besentv(a)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); } [ -- 2.35.1
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. -- Rémi Bernon <rbernon(a)codeweavers.com>
And use it for ISpeechRecognizer_CompileConstraintsAsync. Signed-off-by: Bernhard Kölbl <besentv(a)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); -- 2.35.1
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(a)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(a)codeweavers.com>
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(a)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(a)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(a)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! -- Rémi Bernon <rbernon(a)codeweavers.com>
participants (3)
-
Bernhard Kölbl -
Jacek Caban -
Rémi Bernon