[PATCH v4 0/5] MR6889: threadpoolwinrt: Implement IAsyncAction and IAsyncInfo.
This MR adds an implementation for the `IAsyncAction` and `IAsyncInfo` interfaces exported by `Windows.System.Threading`, including support for setting `IAsyncActionCompletedHandler` values for an `IAsyncAction`. It also re-writes (or factors?) the `IAsyncOperation<boolean>` implementation in dlls/cryptowinrt to use `ThreadPoolStatics::RunAsync`, by introducing a type-punning variant of `AsyncOperationCompletedHandler<T>` (similar to `WineAsyncOperationCompletedHandler`), which is a wrapper around the `IAsyncAction` returned by `RunAsync`. The new `IAsyncOperation<T>` implementation is simpler, and if merged, can be exported to other dlls (windows.gaming.input and windows.security.credentials.ui.userconsentverifier for now). -- v4: cryptowinrt: Rewrite IAsyncOperation using RunAsync from Windows.System.Threading. https://gitlab.winehq.org/wine/wine/-/merge_requests/6889
From: Vibhav Pant <vibhavp(a)gmail.com> --- dlls/threadpoolwinrt/tests/threadpool.c | 138 ++++++++++++++++++++++-- 1 file changed, 130 insertions(+), 8 deletions(-) diff --git a/dlls/threadpoolwinrt/tests/threadpool.c b/dlls/threadpoolwinrt/tests/threadpool.c index 715180818e1..c86e6af8483 100644 --- a/dlls/threadpoolwinrt/tests/threadpool.c +++ b/dlls/threadpoolwinrt/tests/threadpool.c @@ -138,7 +138,6 @@ static ULONG STDMETHODCALLTYPE work_item_Release(IWorkItemHandler *iface) static HRESULT STDMETHODCALLTYPE work_item_Invoke(IWorkItemHandler *iface, IAsyncAction *action) { struct work_item *item = impl_from_IWorkItemHandler(iface); - IAsyncActionCompletedHandler *handler; IAsyncInfo *async_info; AsyncStatus status; HRESULT hr; @@ -160,13 +159,6 @@ static HRESULT STDMETHODCALLTYPE work_item_Invoke(IWorkItemHandler *iface, IAsyn todo_wine ok(hr == E_ILLEGAL_METHOD_CALL, "Unexpected hr %#lx.\n", hr); - handler = (void *)0xdeadbeef; - hr = IAsyncAction_get_Completed(action, &handler); - todo_wine - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine - ok(!handler, "Unexpected pointer %p.\n", handler); - hr = IAsyncAction_put_Completed(action, NULL); todo_wine ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); @@ -202,10 +194,107 @@ static HRESULT create_work_item(IWorkItemHandler **item) return S_OK; } +struct completed_handler +{ + IAsyncActionCompletedHandler IAsyncActionCompletedHandler_iface; + HANDLE invoked_event; + BOOL invoked; + LONG refcount; +}; + +static inline struct completed_handler * +impl_from_IAsyncActionCompletedHandler(IAsyncActionCompletedHandler *iface) +{ + return CONTAINING_RECORD(iface, struct completed_handler, IAsyncActionCompletedHandler_iface); +} + +static HRESULT STDMETHODCALLTYPE handler_QueryInterface(IAsyncActionCompletedHandler *iface, REFIID riid, void **out) +{ + if (IsEqualGUID(&IID_IUnknown, riid) || + IsEqualGUID(&IID_IAsyncActionCompletedHandler, riid)) + { + *out = iface; + IUnknown_AddRef((IUnknown *)*out); + return S_OK; + } + + return E_NOINTERFACE; +} + +static ULONG STDMETHODCALLTYPE handler_AddRef(IAsyncActionCompletedHandler *iface) +{ + struct completed_handler *handler = impl_from_IAsyncActionCompletedHandler(iface); + return InterlockedIncrement(&handler->refcount); +} + +static ULONG STDMETHODCALLTYPE handler_Release(IAsyncActionCompletedHandler *iface) +{ + struct completed_handler *handler = impl_from_IAsyncActionCompletedHandler(iface); + ULONG ref = InterlockedDecrement(&handler->refcount); + if (!ref) + { + CloseHandle(handler->invoked_event); + free(handler); + } + + return ref; +} + +static HRESULT STDMETHODCALLTYPE handler_Invoke(IAsyncActionCompletedHandler *iface, IAsyncAction *action, + AsyncStatus status) +{ + struct completed_handler *handler = impl_from_IAsyncActionCompletedHandler(iface); + + ok(!handler->invoked, "Handler should only be invoked once.\n"); + ok(!!action, "Execpted non-null IAsyncAction value.\n"); + handler->invoked = TRUE; + SetEvent(handler->invoked_event); + return S_OK; +} + +static const IAsyncActionCompletedHandlerVtbl completed_handler_vtbl = { + handler_QueryInterface, + handler_AddRef, + handler_Release, + handler_Invoke, +}; + +static HRESULT create_completed_handler(IAsyncActionCompletedHandler **handler) +{ + struct completed_handler *object; + + *handler = NULL; + + object = calloc(1, sizeof(*object)); + if (!object) + return E_OUTOFMEMORY; + + object->IAsyncActionCompletedHandler_iface.lpVtbl = &completed_handler_vtbl; + object->refcount = 1; + object->invoked_event = CreateEventW(NULL, FALSE, FALSE, NULL); + + *handler = &object->IAsyncActionCompletedHandler_iface; + + return S_OK; +} + +#define test_IAsyncActionCompletedHandler(h) test_IAsyncActionCompletedHandler_(__LINE__, (h)) +static void test_IAsyncActionCompletedHandler_(int line, IAsyncActionCompletedHandler *handler) +{ + struct completed_handler *impl = impl_from_IAsyncActionCompletedHandler(handler); + DWORD ret; + + ret = WaitForSingleObject(impl->invoked_event, 1000); + ok(!ret, "Unexpected wait result %lu.\n", ret); + + ok_(__FILE__, line)(impl->invoked, "Expected invoked to be non-zero.\n"); +} + static void test_RunAsync(void) { IActivationFactory *factory = NULL; IThreadPoolStatics *threadpool_statics; + IAsyncActionCompletedHandler *handler = NULL; IWorkItemHandler *item_iface; struct work_item *item; IAsyncAction *action; @@ -250,15 +339,48 @@ static void test_RunAsync(void) hr = IThreadPoolStatics_RunWithPriorityAsync(threadpool_statics, item_iface, WorkItemPriority_Normal, &action); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + hr = create_completed_handler(&handler); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + if (hr == S_OK) + { + hr = IAsyncAction_put_Completed(action, handler); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + } + } ret = WaitForSingleObject(item->event, 1000); ok(!ret, "Unexpected wait result %lu.\n", ret); + if (handler) + { + todo_wine test_IAsyncActionCompletedHandler(handler); + IAsyncActionCompletedHandler_Release(handler); + } IAsyncAction_Release(action); + handler = NULL; hr = IThreadPoolStatics_RunWithPriorityAndOptionsAsync(threadpool_statics, item_iface, WorkItemPriority_Normal, WorkItemOptions_TimeSliced, &action); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ret = WaitForSingleObject(item->event, 1000); ok(!ret, "Unexpected wait result %lu.\n", ret); + /* Try setting a Completed handler after the work item has likely run. */ + if (hr == S_OK) + { + hr = create_completed_handler(&handler); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + if (hr == S_OK) + { + hr = IAsyncAction_put_Completed(action, handler); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IAsyncAction_put_Completed(action, handler); + todo_wine ok(hr == E_ILLEGAL_DELEGATE_ASSIGNMENT, "%#lx != %#lx\n", hr, E_ILLEGAL_DELEGATE_ASSIGNMENT); + todo_wine test_IAsyncActionCompletedHandler(handler); + IAsyncActionCompletedHandler_Release(handler); + } + } IAsyncAction_Release(action); hr = IThreadPoolStatics_RunWithPriorityAndOptionsAsync(threadpool_statics, item_iface, WorkItemPriority_Low, -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/6889
From: Vibhav Pant <vibhavp(a)gmail.com> --- dlls/threadpoolwinrt/main.c | 199 +++++++++++------------- dlls/threadpoolwinrt/tests/threadpool.c | 1 - 2 files changed, 89 insertions(+), 111 deletions(-) diff --git a/dlls/threadpoolwinrt/main.c b/dlls/threadpoolwinrt/main.c index d047d3ce9fb..66910c5e01a 100644 --- a/dlls/threadpoolwinrt/main.c +++ b/dlls/threadpoolwinrt/main.c @@ -48,6 +48,12 @@ struct async_action { IAsyncAction IAsyncAction_iface; IAsyncInfo IAsyncInfo_iface; + + TP_WORK *work; + IWorkItemHandler *work_item_handler; + + CRITICAL_SECTION cs; + AsyncStatus status; LONG refcount; }; @@ -116,7 +122,12 @@ static ULONG STDMETHODCALLTYPE async_action_Release(IAsyncAction *iface) TRACE("iface %p, refcount %lu.\n", iface, refcount); if (!refcount) + { + IWorkItemHandler_Release(action->work_item_handler); + action->cs.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&action->cs); free(action); + } return refcount; } @@ -161,9 +172,18 @@ static HRESULT STDMETHODCALLTYPE async_action_get_Completed(IAsyncAction *iface, static HRESULT STDMETHODCALLTYPE async_action_GetResults(IAsyncAction *iface) { - FIXME("iface %p stub!\n", iface); + struct async_action *action; + HRESULT hr = E_ILLEGAL_METHOD_CALL; - return E_NOTIMPL; + TRACE("iface %p\n", iface); + + action = impl_from_IAsyncAction(iface); + EnterCriticalSection(&action->cs); + if (action->status == Completed || action->status == Error) + hr = S_OK; + LeaveCriticalSection(&action->cs); + + return hr; } static const IAsyncActionVtbl async_action_vtbl = @@ -265,73 +285,87 @@ static const IAsyncInfoVtbl async_info_vtbl = async_info_Close, }; -static HRESULT async_action_create(IAsyncAction **ret) -{ - struct async_action *object; - - *ret = NULL; - - if (!(object = calloc(1, sizeof(*object)))) - return E_OUTOFMEMORY; - object->IAsyncAction_iface.lpVtbl = &async_action_vtbl; - object->IAsyncInfo_iface.lpVtbl = &async_info_vtbl; - object->refcount = 1; +static void async_action_invoke_and_release(IAsyncAction *action_iface) +{ + struct async_action *action = impl_from_IAsyncAction(action_iface); + HRESULT hr; - *ret = &object->IAsyncAction_iface; + hr = IWorkItemHandler_Invoke(action->work_item_handler, action_iface); - return S_OK; + EnterCriticalSection(&action->cs); + action->status = FAILED(hr) ? Error : Completed; + LeaveCriticalSection(&action->cs); + IAsyncAction_Release(action_iface); } -struct work_item +static void CALLBACK async_action_tp_callback(TP_CALLBACK_INSTANCE *inst, void *action_iface, TP_WORK *work) { - IWorkItemHandler *handler; - IAsyncAction *action; -}; + async_action_invoke_and_release(action_iface); +} -static void release_work_item(struct work_item *item) +static DWORD CALLBACK async_action_sliced_proc(void *action_iface) { - IWorkItemHandler_Release(item->handler); - IAsyncAction_Release(item->action); - free(item); + async_action_invoke_and_release(action_iface); + return 0; } -static HRESULT alloc_work_item(IWorkItemHandler *handler, struct work_item **ret) +static HRESULT async_action_create_and_start(TP_CALLBACK_ENVIRON *environment, WorkItemPriority priority, + IWorkItemHandler *work_item, IAsyncAction **ret) { - struct work_item *object; - HRESULT hr; + struct async_action *object; + HANDLE thread = NULL; *ret = NULL; if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY; - if (FAILED(hr = async_action_create(&object->action))) + object->IAsyncAction_iface.lpVtbl = &async_action_vtbl; + object->IAsyncInfo_iface.lpVtbl = &async_info_vtbl; + if (environment) { - free(object); - return hr; + object->work = CreateThreadpoolWork(async_action_tp_callback, &object->IAsyncAction_iface, environment); + if (!object->work) + { + ERR("Failed to create a thread pool work item: %lu.\n", GetLastError()); + free(object); + return HRESULT_FROM_WIN32(GetLastError()); + } } - - IWorkItemHandler_AddRef((object->handler = handler)); - - *ret = object; + else + { + thread = CreateThread(NULL, 0, async_action_sliced_proc, &object->IAsyncAction_iface, CREATE_SUSPENDED, + NULL); + if (!thread) + { + ERR("Failed to create a thread: %lu\n", GetLastError()); + free(object); + return HRESULT_FROM_WIN32(GetLastError()); + } + if (priority != WorkItemPriority_Normal) + SetThreadPriority(thread, priority == WorkItemPriority_High ? THREAD_PRIORITY_HIGHEST + : THREAD_PRIORITY_LOWEST); + } + object->work_item_handler = work_item; + IWorkItemHandler_AddRef(work_item); + object->status = Started; + InitializeCriticalSectionEx(&object->cs, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO); + object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__": async_action.cs"); + object->refcount = 2; + + if (object->work) + SubmitThreadpoolWork(object->work); + else + { + ResumeThread(thread); + CloseHandle(thread); + } + *ret = &object->IAsyncAction_iface; return S_OK; } -static void work_item_invoke_release(struct work_item *item) -{ - IWorkItemHandler_Invoke(item->handler, item->action); - release_work_item(item); -} - -static DWORD WINAPI sliced_thread_proc(void *arg) -{ - struct work_item *item = arg; - work_item_invoke_release(item); - return 0; -} - struct thread_pool { INIT_ONCE init_once; @@ -354,62 +388,10 @@ static BOOL CALLBACK pool_init_once(INIT_ONCE *init_once, void *param, void **co return TRUE; } -static void CALLBACK pool_work_callback(TP_CALLBACK_INSTANCE *instance, void *context, TP_WORK *work) -{ - struct work_item *item = context; - work_item_invoke_release(item); -} - -static HRESULT submit_threadpool_work(struct work_item *item, WorkItemPriority priority, IAsyncAction **action) -{ - struct thread_pool *pool; - TP_WORK *work; - - assert(priority == WorkItemPriority_Low - || priority == WorkItemPriority_Normal - || priority == WorkItemPriority_High); - - pool = &pools[priority + 1]; - - if (!InitOnceExecuteOnce(&pool->init_once, pool_init_once, pool, NULL)) - return E_FAIL; - - if (!(work = CreateThreadpoolWork(pool_work_callback, item, &pool->environment))) - return E_FAIL; - - IAsyncAction_AddRef((*action = item->action)); - SubmitThreadpoolWork(work); - - return S_OK; -} - -static HRESULT submit_standalone_thread_work(struct work_item *item, WorkItemPriority priority, IAsyncAction **action) -{ - HANDLE thread; - - if (!(thread = CreateThread(NULL, 0, sliced_thread_proc, item, priority == WorkItemPriority_Normal ? - 0 : CREATE_SUSPENDED, NULL))) - { - WARN("Failed to create a thread, error %ld.\n", GetLastError()); - return HRESULT_FROM_WIN32(GetLastError()); - } - - IAsyncAction_AddRef((*action = item->action)); - if (priority != WorkItemPriority_Normal) - { - SetThreadPriority(thread, priority == WorkItemPriority_High ? THREAD_PRIORITY_HIGHEST : THREAD_PRIORITY_LOWEST); - ResumeThread(thread); - } - CloseHandle(thread); - - return S_OK; -} - static HRESULT run_async(IWorkItemHandler *handler, WorkItemPriority priority, WorkItemOptions options, IAsyncAction **action) { - struct work_item *item; - HRESULT hr; + TP_CALLBACK_ENVIRON *environment = NULL; *action = NULL; @@ -419,18 +401,15 @@ static HRESULT run_async(IWorkItemHandler *handler, WorkItemPriority priority, W if (priority < WorkItemPriority_Low || priority > WorkItemPriority_High) return E_INVALIDARG; - if (FAILED(hr = alloc_work_item(handler, &item))) - return hr; - - if (options == WorkItemOptions_TimeSliced) - hr = submit_standalone_thread_work(item, priority, action); - else - hr = submit_threadpool_work(item, priority, action); - - if (FAILED(hr)) - release_work_item(item); + if (options != WorkItemOptions_TimeSliced) + { + struct thread_pool *pool = &pools[priority + 1]; + if (!InitOnceExecuteOnce(&pool->init_once, pool_init_once, pool, NULL)) + return E_FAIL; + environment = &pools[priority + 1].environment; + } - return hr; + return async_action_create_and_start(environment, priority, handler, action); } static HRESULT STDMETHODCALLTYPE threadpool_factory_QueryInterface( diff --git a/dlls/threadpoolwinrt/tests/threadpool.c b/dlls/threadpoolwinrt/tests/threadpool.c index c86e6af8483..73a91358c64 100644 --- a/dlls/threadpoolwinrt/tests/threadpool.c +++ b/dlls/threadpoolwinrt/tests/threadpool.c @@ -156,7 +156,6 @@ static HRESULT STDMETHODCALLTYPE work_item_Invoke(IWorkItemHandler *iface, IAsyn IAsyncInfo_Release(async_info); hr = IAsyncAction_GetResults(action); - todo_wine ok(hr == E_ILLEGAL_METHOD_CALL, "Unexpected hr %#lx.\n", hr); hr = IAsyncAction_put_Completed(action, NULL); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/6889
From: Vibhav Pant <vibhavp(a)gmail.com> --- dlls/threadpoolwinrt/main.c | 85 +++++++++++++++++++++---- dlls/threadpoolwinrt/tests/threadpool.c | 2 - 2 files changed, 74 insertions(+), 13 deletions(-) diff --git a/dlls/threadpoolwinrt/main.c b/dlls/threadpoolwinrt/main.c index 66910c5e01a..8a85cdb1612 100644 --- a/dlls/threadpoolwinrt/main.c +++ b/dlls/threadpoolwinrt/main.c @@ -37,6 +37,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(threadpool); +#define Closed 4 + struct threadpool_factory { IActivationFactory IActivationFactory_iface; @@ -49,6 +51,8 @@ struct async_action IAsyncAction IAsyncAction_iface; IAsyncInfo IAsyncInfo_iface; + UINT32 id; + HRESULT hr; TP_WORK *work; IWorkItemHandler *work_item_handler; @@ -123,6 +127,7 @@ static ULONG STDMETHODCALLTYPE async_action_Release(IAsyncAction *iface) if (!refcount) { + IAsyncInfo_Close(&action->IAsyncInfo_iface); IWorkItemHandler_Release(action->work_item_handler); action->cs.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&action->cs); @@ -237,37 +242,91 @@ static HRESULT STDMETHODCALLTYPE async_info_GetTrustLevel(IAsyncInfo *iface, Tru static HRESULT STDMETHODCALLTYPE async_info_get_Id(IAsyncInfo *iface, UINT32 *id) { - FIXME("iface %p, id %p stub!\n", iface, id); + struct async_action *action = impl_from_IAsyncInfo(iface); + HRESULT hr = S_OK; - return E_NOTIMPL; + TRACE("iface %p, id %p\n", iface, id); + + EnterCriticalSection(&action->cs); + if (action->status == Closed) + hr = E_ILLEGAL_METHOD_CALL; + else + *id = action->id; + LeaveCriticalSection(&action->cs); + + return hr; } static HRESULT STDMETHODCALLTYPE async_info_get_Status(IAsyncInfo *iface, AsyncStatus *status) { - FIXME("iface %p, status %p stub!\n", iface, status); + struct async_action *action = impl_from_IAsyncInfo(iface); + HRESULT hr = S_OK; - return E_NOTIMPL; + TRACE("iface %p, status %p\n", iface, status); + + EnterCriticalSection(&action->cs); + if (action->status == Closed) + hr = E_ILLEGAL_METHOD_CALL; + *status = action->status; + LeaveCriticalSection(&action->cs); + + return hr; } static HRESULT STDMETHODCALLTYPE async_info_get_ErrorCode(IAsyncInfo *iface, HRESULT *error_code) { - FIXME("iface %p, error_code %p stub!\n", iface, error_code); + struct async_action *action = impl_from_IAsyncInfo(iface); + HRESULT hr = S_OK; - return E_NOTIMPL; + TRACE("iface %p, error_code %p\n", iface, error_code); + + EnterCriticalSection(&action->cs); + if (action->status == Closed) + *error_code = hr = E_ILLEGAL_METHOD_CALL; + else + *error_code = action->hr; + LeaveCriticalSection(&action->cs); + + return hr; } static HRESULT STDMETHODCALLTYPE async_info_Cancel(IAsyncInfo *iface) { - FIXME("iface %p stub!\n", iface); + struct async_action *action = impl_from_IAsyncInfo(iface); + HRESULT hr = S_OK; - return E_NOTIMPL; + TRACE("iface %p\n", iface); + + EnterCriticalSection(&action->cs); + if (action->status == Closed) + hr = E_ILLEGAL_METHOD_CALL; + else if (action->status == Started) + action->status = Canceled; + LeaveCriticalSection(&action->cs); + + return hr; } static HRESULT STDMETHODCALLTYPE async_info_Close(IAsyncInfo *iface) { - FIXME("iface %p stub!\n", iface); + struct async_action *action = impl_from_IAsyncInfo( iface ); + HRESULT hr = S_OK; - return E_NOTIMPL; + TRACE("iface %p\n", iface); + + EnterCriticalSection(&action->cs); + if (action->status == Started) + hr = E_ILLEGAL_STATE_CHANGE; + else if (action->status != Closed) + { + if (action->work) + CloseThreadpoolWork( action->work ); + action->work = NULL; + action->status = Closed; + } + LeaveCriticalSection(&action->cs); + + return hr; } static const IAsyncInfoVtbl async_info_vtbl = @@ -294,7 +353,9 @@ static void async_action_invoke_and_release(IAsyncAction *action_iface) hr = IWorkItemHandler_Invoke(action->work_item_handler, action_iface); EnterCriticalSection(&action->cs); - action->status = FAILED(hr) ? Error : Completed; + action->hr = hr; + if (action->status != Closed) + action->status = FAILED(hr) ? Error : Completed; LeaveCriticalSection(&action->cs); IAsyncAction_Release(action_iface); } @@ -314,6 +375,7 @@ static HRESULT async_action_create_and_start(TP_CALLBACK_ENVIRON *environment, W IWorkItemHandler *work_item, IAsyncAction **ret) { struct async_action *object; + static LONG async_action_id = 0; HANDLE thread = NULL; *ret = NULL; @@ -347,6 +409,7 @@ static HRESULT async_action_create_and_start(TP_CALLBACK_ENVIRON *environment, W SetThreadPriority(thread, priority == WorkItemPriority_High ? THREAD_PRIORITY_HIGHEST : THREAD_PRIORITY_LOWEST); } + object->id = InterlockedIncrement(&async_action_id); object->work_item_handler = work_item; IWorkItemHandler_AddRef(work_item); object->status = Started; diff --git a/dlls/threadpoolwinrt/tests/threadpool.c b/dlls/threadpoolwinrt/tests/threadpool.c index 73a91358c64..6048a868234 100644 --- a/dlls/threadpoolwinrt/tests/threadpool.c +++ b/dlls/threadpoolwinrt/tests/threadpool.c @@ -145,12 +145,10 @@ static HRESULT STDMETHODCALLTYPE work_item_Invoke(IWorkItemHandler *iface, IAsyn hr = IAsyncAction_QueryInterface(action, &IID_IAsyncInfo, (void **)&async_info); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IAsyncInfo_get_Status(async_info, &status); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); if (SUCCEEDED(hr)) ok(status == Started, "Unexpected status %d.\n", status); hr = IAsyncInfo_Cancel(async_info); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); IAsyncInfo_Release(async_info); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/6889
From: Vibhav Pant <vibhavp(a)gmail.com> --- dlls/threadpoolwinrt/main.c | 72 +++++++++++++++++++++++-- dlls/threadpoolwinrt/tests/threadpool.c | 11 ++-- 2 files changed, 72 insertions(+), 11 deletions(-) diff --git a/dlls/threadpoolwinrt/main.c b/dlls/threadpoolwinrt/main.c index 8a85cdb1612..87643836513 100644 --- a/dlls/threadpoolwinrt/main.c +++ b/dlls/threadpoolwinrt/main.c @@ -37,6 +37,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(threadpool); +#define HANDLER_NOT_SET ((void *)~(ULONG_PTR)0) #define Closed 4 struct threadpool_factory @@ -57,6 +58,7 @@ struct async_action IWorkItemHandler *work_item_handler; CRITICAL_SECTION cs; + IAsyncActionCompletedHandler *completed_handler; AsyncStatus status; LONG refcount; }; @@ -127,6 +129,8 @@ static ULONG STDMETHODCALLTYPE async_action_Release(IAsyncAction *iface) if (!refcount) { + if (action->completed_handler && action->completed_handler != HANDLER_NOT_SET) + IAsyncActionCompletedHandler_Release( action->completed_handler ); IAsyncInfo_Close(&action->IAsyncInfo_iface); IWorkItemHandler_Release(action->work_item_handler); action->cs.DebugInfo->Spare[0] = 0; @@ -163,16 +167,61 @@ static HRESULT STDMETHODCALLTYPE async_action_GetTrustLevel( static HRESULT STDMETHODCALLTYPE async_action_put_Completed(IAsyncAction *iface, IAsyncActionCompletedHandler *handler) { - FIXME("iface %p, handler %p stub!\n", iface, handler); + struct async_action *action; + HRESULT hr = S_OK; - return E_NOTIMPL; + TRACE("iface %p, handler %p\n", iface, handler); + + if (!handler) + return E_POINTER; + + action = impl_from_IAsyncAction(iface); + EnterCriticalSection(&action->cs); + if (action->status == Closed) + hr = E_ILLEGAL_METHOD_CALL; + else if (action->completed_handler != HANDLER_NOT_SET) + hr = E_ILLEGAL_DELEGATE_ASSIGNMENT; + else if (handler) + { + action->completed_handler = handler; + IAsyncActionCompletedHandler_AddRef(action->completed_handler); + if (action->status > Started) + { + AsyncStatus status = action->status; + action->completed_handler = NULL; + LeaveCriticalSection(&action->cs); + + IAsyncActionCompletedHandler_Invoke(handler, iface, status); + IAsyncActionCompletedHandler_Release(handler); + return S_OK; + } + } + LeaveCriticalSection(&action->cs); + + return hr; } static HRESULT STDMETHODCALLTYPE async_action_get_Completed(IAsyncAction *iface, IAsyncActionCompletedHandler **handler) { - FIXME("iface %p, handler %p stub!\n", iface, handler); + struct async_action *action; + HRESULT hr = S_OK; - return E_NOTIMPL; + TRACE("iface %p, handler %p\n", iface, handler); + + action = impl_from_IAsyncAction(iface); + EnterCriticalSection(&action->cs); + if (action->status == Closed) + hr = E_ILLEGAL_METHOD_CALL; + if (!action->completed_handler || action->completed_handler == HANDLER_NOT_SET) + *handler = NULL; + else + { + *handler = action->completed_handler; + IAsyncActionCompletedHandler_AddRef(*handler); + } + LeaveCriticalSection(&action->cs); + + return hr; } static HRESULT STDMETHODCALLTYPE async_action_GetResults(IAsyncAction *iface) @@ -354,9 +403,21 @@ static void async_action_invoke_and_release(IAsyncAction *action_iface) EnterCriticalSection(&action->cs); action->hr = hr; + if (action->status != Closed) action->status = FAILED(hr) ? Error : Completed; - LeaveCriticalSection(&action->cs); + if (action->completed_handler && action->completed_handler != HANDLER_NOT_SET) + { + AsyncStatus status = action->status; + IAsyncActionCompletedHandler *handler = action->completed_handler; + action->completed_handler = NULL; + LeaveCriticalSection(&action->cs); + + IAsyncActionCompletedHandler_Invoke(handler, &action->IAsyncAction_iface, status); + IAsyncActionCompletedHandler_Release(handler); + } + else + LeaveCriticalSection(&action->cs); IAsyncAction_Release(action_iface); } @@ -412,6 +473,7 @@ static HRESULT async_action_create_and_start(TP_CALLBACK_ENVIRON *environment, W object->id = InterlockedIncrement(&async_action_id); object->work_item_handler = work_item; IWorkItemHandler_AddRef(work_item); + object->completed_handler = HANDLER_NOT_SET; object->status = Started; InitializeCriticalSectionEx(&object->cs, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO); object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__": async_action.cs"); diff --git a/dlls/threadpoolwinrt/tests/threadpool.c b/dlls/threadpoolwinrt/tests/threadpool.c index 6048a868234..94e7cf48bf5 100644 --- a/dlls/threadpoolwinrt/tests/threadpool.c +++ b/dlls/threadpoolwinrt/tests/threadpool.c @@ -157,7 +157,6 @@ static HRESULT STDMETHODCALLTYPE work_item_Invoke(IWorkItemHandler *iface, IAsyn ok(hr == E_ILLEGAL_METHOD_CALL, "Unexpected hr %#lx.\n", hr); hr = IAsyncAction_put_Completed(action, NULL); - todo_wine ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); SetEvent(item->event); @@ -344,14 +343,14 @@ static void test_RunAsync(void) if (hr == S_OK) { hr = IAsyncAction_put_Completed(action, handler); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); } } ret = WaitForSingleObject(item->event, 1000); ok(!ret, "Unexpected wait result %lu.\n", ret); if (handler) { - todo_wine test_IAsyncActionCompletedHandler(handler); + test_IAsyncActionCompletedHandler(handler); IAsyncActionCompletedHandler_Release(handler); } IAsyncAction_Release(action); @@ -371,10 +370,10 @@ static void test_RunAsync(void) if (hr == S_OK) { hr = IAsyncAction_put_Completed(action, handler); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IAsyncAction_put_Completed(action, handler); - todo_wine ok(hr == E_ILLEGAL_DELEGATE_ASSIGNMENT, "%#lx != %#lx\n", hr, E_ILLEGAL_DELEGATE_ASSIGNMENT); - todo_wine test_IAsyncActionCompletedHandler(handler); + ok(hr == E_ILLEGAL_DELEGATE_ASSIGNMENT, "%#lx != %#lx\n", hr, E_ILLEGAL_DELEGATE_ASSIGNMENT); + test_IAsyncActionCompletedHandler(handler); IAsyncActionCompletedHandler_Release(handler); } } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/6889
From: Vibhav Pant <vibhavp(a)gmail.com> --- dlls/cryptowinrt/Makefile.in | 1 - dlls/cryptowinrt/async.c | 460 +++++++++++++++------------------- dlls/cryptowinrt/private.h | 3 +- dlls/cryptowinrt/provider.idl | 47 ---- 4 files changed, 200 insertions(+), 311 deletions(-) delete mode 100644 dlls/cryptowinrt/provider.idl diff --git a/dlls/cryptowinrt/Makefile.in b/dlls/cryptowinrt/Makefile.in index 8d9d23a6cc2..9517170b1d3 100644 --- a/dlls/cryptowinrt/Makefile.in +++ b/dlls/cryptowinrt/Makefile.in @@ -6,4 +6,3 @@ SOURCES = \ classes.idl \ credentials.c \ main.c \ - provider.idl diff --git a/dlls/cryptowinrt/async.c b/dlls/cryptowinrt/async.c index 5c3d718ae2d..5d6addfa6af 100644 --- a/dlls/cryptowinrt/async.c +++ b/dlls/cryptowinrt/async.c @@ -2,6 +2,7 @@ * * Copyright 2022 Bernhard Kölbl for CodeWeavers * Copyright 2022 Rémi Bernon for CodeWeavers + * Copyright 2024 Vibhav Pant * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,353 +21,257 @@ #include "private.h" +#include "roapi.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(crypto); -#define Closed 4 -#define HANDLER_NOT_SET ((void *)~(ULONG_PTR)0) - -struct async_info +/* A type-pruning variant of IAsyncOperationCompletedHandler<T> */ +struct async_completed { - IWineAsyncInfoImpl IWineAsyncInfoImpl_iface; - IAsyncInfo IAsyncInfo_iface; - IInspectable *IInspectable_outer; + IAsyncActionCompletedHandler IAsyncActionCompletedHandler_iface; + IInspectable *inner_handler; + IInspectable *inner_action; LONG ref; - - async_operation_callback callback; - TP_WORK *async_run_work; - IUnknown *invoker; - IUnknown *param; - - CRITICAL_SECTION cs; - IWineAsyncOperationCompletedHandler *handler; - PROPVARIANT result; - AsyncStatus status; - HRESULT hr; }; -static inline struct async_info *impl_from_IWineAsyncInfoImpl( IWineAsyncInfoImpl *iface ) +static inline struct async_completed *impl_from_IAsyncActionCompletedHandler( IAsyncActionCompletedHandler *iface ) { - return CONTAINING_RECORD( iface, struct async_info, IWineAsyncInfoImpl_iface ); + return CONTAINING_RECORD( iface, struct async_completed, IAsyncActionCompletedHandler_iface ); } -static HRESULT WINAPI async_impl_QueryInterface( IWineAsyncInfoImpl *iface, REFIID iid, void **out ) +static HRESULT WINAPI async_completed_QueryInterface( IAsyncActionCompletedHandler *iface, REFIID iid, void **out ) { - struct async_info *impl = impl_from_IWineAsyncInfoImpl( iface ); + struct async_completed *impl = impl_from_IAsyncActionCompletedHandler( 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_IWineAsyncInfoImpl )) - { - IInspectable_AddRef( (*out = &impl->IWineAsyncInfoImpl_iface) ); - return S_OK; - } - - if (IsEqualGUID( iid, &IID_IAsyncInfo )) + IsEqualGUID( iid, &IID_IAsyncActionCompletedHandler )) { - IInspectable_AddRef( (*out = &impl->IAsyncInfo_iface) ); + *out = iface; + IUnknown_AddRef((IUnknown *)*out); return S_OK; } - FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); - *out = NULL; - return E_NOINTERFACE; + return IInspectable_QueryInterface( impl->inner_handler, iid, out ); } -static ULONG WINAPI async_impl_AddRef( IWineAsyncInfoImpl *iface ) +static ULONG WINAPI async_completed_AddRef( IAsyncActionCompletedHandler *iface ) { - struct async_info *impl = impl_from_IWineAsyncInfoImpl( iface ); + struct async_completed *impl = impl_from_IAsyncActionCompletedHandler( iface ); ULONG ref = InterlockedIncrement( &impl->ref ); TRACE( "iface %p, ref %lu.\n", iface, ref ); return ref; } -static ULONG WINAPI async_impl_Release( IWineAsyncInfoImpl *iface ) +static ULONG WINAPI async_completed_Release( IAsyncActionCompletedHandler *iface ) { - struct async_info *impl = impl_from_IWineAsyncInfoImpl( iface ); + struct async_completed *impl = impl_from_IAsyncActionCompletedHandler( iface ); ULONG ref = InterlockedDecrement( &impl->ref ); TRACE( "iface %p, ref %lu.\n", iface, ref ); if (!ref) { - if (impl->handler && impl->handler != HANDLER_NOT_SET) IWineAsyncOperationCompletedHandler_Release( impl->handler ); - IAsyncInfo_Close( &impl->IAsyncInfo_iface ); - if (impl->param) IUnknown_Release( impl->param ); - if (impl->invoker) IUnknown_Release( impl->invoker ); - impl->cs.DebugInfo->Spare[0] = 0; - DeleteCriticalSection( &impl->cs ); + IInspectable_Release( impl->inner_handler ); + IInspectable_Release( impl->inner_action ); free( impl ); } return ref; } -static HRESULT WINAPI async_impl_put_Completed( IWineAsyncInfoImpl *iface, IWineAsyncOperationCompletedHandler *handler ) +static HRESULT WINAPI async_completed_Invoke( IAsyncActionCompletedHandler *iface, IAsyncAction *info, + AsyncStatus status ) { - struct async_info *impl = impl_from_IWineAsyncInfoImpl( iface ); - HRESULT hr = S_OK; + struct async_completed *impl = impl_from_IAsyncActionCompletedHandler( iface ); + IAsyncActionCompletedHandler *handler = (IAsyncActionCompletedHandler *)impl->inner_handler; + IAsyncAction *action = (IAsyncAction *)impl->inner_action; - TRACE( "iface %p, handler %p.\n", iface, handler ); - - EnterCriticalSection( &impl->cs ); - if (impl->status == Closed) hr = E_ILLEGAL_METHOD_CALL; - else if (impl->handler != HANDLER_NOT_SET) hr = E_ILLEGAL_DELEGATE_ASSIGNMENT; - else if ((impl->handler = handler)) - { - IWineAsyncOperationCompletedHandler_AddRef( impl->handler ); - - if (impl->status > Started) - { - IInspectable *operation = impl->IInspectable_outer; - AsyncStatus status = impl->status; - impl->handler = NULL; /* Prevent concurrent invoke. */ - LeaveCriticalSection( &impl->cs ); - - IWineAsyncOperationCompletedHandler_Invoke( handler, operation, status ); - IWineAsyncOperationCompletedHandler_Release( handler ); - - return S_OK; - } - } - LeaveCriticalSection( &impl->cs ); - - return hr; + return IAsyncActionCompletedHandler_Invoke( handler, action, status ); } -static HRESULT WINAPI async_impl_get_Completed( IWineAsyncInfoImpl *iface, IWineAsyncOperationCompletedHandler **handler ) +static const IAsyncActionCompletedHandlerVtbl async_completed_vtbl = { - struct async_info *impl = impl_from_IWineAsyncInfoImpl( iface ); - HRESULT hr = S_OK; - - TRACE( "iface %p, handler %p.\n", iface, handler ); - - EnterCriticalSection( &impl->cs ); - if (impl->status == Closed) hr = E_ILLEGAL_METHOD_CALL; - if (impl->handler == NULL || impl->handler == HANDLER_NOT_SET) *handler = NULL; - else IWineAsyncOperationCompletedHandler_AddRef( (*handler = impl->handler) ); - LeaveCriticalSection( &impl->cs ); - - return hr; -} - -static HRESULT WINAPI async_impl_get_Result( IWineAsyncInfoImpl *iface, PROPVARIANT *result ) -{ - struct async_info *impl = impl_from_IWineAsyncInfoImpl( iface ); - HRESULT hr = E_ILLEGAL_METHOD_CALL; - - TRACE( "iface %p, result %p.\n", iface, result ); - - EnterCriticalSection( &impl->cs ); - if (impl->status == Completed || impl->status == Error) - { - PropVariantCopy( result, &impl->result ); - hr = impl->hr; - } - LeaveCriticalSection( &impl->cs ); - - return hr; -} + async_completed_QueryInterface, + async_completed_AddRef, + async_completed_Release, + async_completed_Invoke, +}; -static HRESULT WINAPI async_impl_Start( IWineAsyncInfoImpl *iface ) +static HRESULT async_completed_create( IInspectable *inner_action, IInspectable *inner_handler, IAsyncActionCompletedHandler **handler ) { - struct async_info *impl = impl_from_IWineAsyncInfoImpl( iface ); + struct async_completed *impl; - TRACE( "iface %p.\n", iface ); + impl = calloc( 1, sizeof( *impl ) ); + if (!impl) + return E_NOINTERFACE; - /* keep the async alive in the callback */ - IInspectable_AddRef( impl->IInspectable_outer ); - SubmitThreadpoolWork( impl->async_run_work ); + impl->IAsyncActionCompletedHandler_iface.lpVtbl = &async_completed_vtbl; + impl->inner_action = inner_action; + impl->inner_handler = inner_handler; + IInspectable_AddRef( impl->inner_action ); + IInspectable_AddRef( impl->inner_handler ); + impl->ref = 1; + *handler = &impl->IAsyncActionCompletedHandler_iface; return S_OK; } -static const struct IWineAsyncInfoImplVtbl async_impl_vtbl = +struct async_operation_base { - /* IUnknown methods */ - async_impl_QueryInterface, - async_impl_AddRef, - async_impl_Release, - /* IWineAsyncInfoImpl */ - async_impl_put_Completed, - async_impl_get_Completed, - async_impl_get_Result, - async_impl_Start, + IWorkItemHandler *work_item; + IAsyncAction *inner_action; + PROPVARIANT result; + LONG ref; }; -DEFINE_IINSPECTABLE_OUTER( async_info, IAsyncInfo, struct async_info, IInspectable_outer ) - -static HRESULT WINAPI async_info_get_Id( IAsyncInfo *iface, UINT32 *id ) +static HRESULT async_operation_put_Completed( struct async_operation_base *base, IInspectable *action, void *handler ) { - struct async_info *impl = impl_from_IAsyncInfo( iface ); - HRESULT hr = S_OK; - - TRACE( "iface %p, id %p.\n", iface, id ); - - EnterCriticalSection( &impl->cs ); - if (impl->status == Closed) hr = E_ILLEGAL_METHOD_CALL; - *id = 1; - LeaveCriticalSection( &impl->cs ); + IAsyncActionCompletedHandler *wrapper; + HRESULT hr; + hr = async_completed_create( (IInspectable *)action, (IInspectable *)handler, &wrapper ); + if (FAILED( hr )) + return hr; + hr = IAsyncAction_put_Completed( base->inner_action, wrapper ); + IAsyncActionCompletedHandler_Release( wrapper ); return hr; } -static HRESULT WINAPI async_info_get_Status( IAsyncInfo *iface, AsyncStatus *status ) +static HRESULT async_operation_get_Completed( struct async_operation_base *base, REFIID iid, void **handler ) { - struct async_info *impl = impl_from_IAsyncInfo( iface ); - HRESULT hr = S_OK; - - TRACE( "iface %p, status %p.\n", iface, status ); + IAsyncActionCompletedHandler *wrapper; + HRESULT hr; - EnterCriticalSection( &impl->cs ); - if (impl->status == Closed) hr = E_ILLEGAL_METHOD_CALL; - *status = impl->status; - LeaveCriticalSection( &impl->cs ); + *handler = NULL; + hr = IAsyncAction_get_Completed( base->inner_action, &wrapper ); + TRACE("hr = %#lx, inner: %p, wrapper: %p\n", hr, base->inner_action, wrapper); + if (FAILED( hr ) || !wrapper) + return hr; + hr = IAsyncActionCompletedHandler_QueryInterface( wrapper, iid, (void **)handler ); + IAsyncActionCompletedHandler_Release( wrapper ); return hr; } -static HRESULT WINAPI async_info_get_ErrorCode( IAsyncInfo *iface, HRESULT *error_code ) +struct work_item { - struct async_info *impl = impl_from_IAsyncInfo( iface ); - HRESULT hr = S_OK; - - TRACE( "iface %p, error_code %p.\n", iface, error_code ); + IWorkItemHandler IWorkItemHandler_iface; + async_operation_callback callback; + PROPVARIANT *result; - EnterCriticalSection( &impl->cs ); - if (impl->status == Closed) *error_code = hr = E_ILLEGAL_METHOD_CALL; - else *error_code = impl->hr; - LeaveCriticalSection( &impl->cs ); + IUnknown *invoker; + IUnknown *param; + LONG ref; +}; - return hr; +static inline struct work_item *impl_from_IWorkItemHandler( IWorkItemHandler *iface ) +{ + return CONTAINING_RECORD( iface, struct work_item, IWorkItemHandler_iface ); } -static HRESULT WINAPI async_info_Cancel( IAsyncInfo *iface ) +static HRESULT WINAPI work_item_QueryInterface( IWorkItemHandler *iface, REFIID iid, void **out ) { - struct async_info *impl = impl_from_IAsyncInfo( iface ); - HRESULT hr = S_OK; - - TRACE( "iface %p.\n", iface ); + TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out ); - EnterCriticalSection( &impl->cs ); - if (impl->status == Closed) hr = E_ILLEGAL_METHOD_CALL; - else if (impl->status == Started) impl->status = Canceled; - LeaveCriticalSection( &impl->cs ); + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IInspectable ) || + IsEqualGUID( iid, &IID_IWorkItemHandler )) + { + *out = iface; + IUnknown_AddRef( (IUnknown *)*out ); + return S_OK; + } - return hr; + *out = NULL; + FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + return E_NOINTERFACE; } -static HRESULT WINAPI async_info_Close( IAsyncInfo *iface ) +static ULONG WINAPI work_item_AddRef( IWorkItemHandler *iface ) { - struct async_info *impl = impl_from_IAsyncInfo( iface ); - HRESULT hr = S_OK; + struct work_item *impl = impl_from_IWorkItemHandler( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + TRACE( "iface %p, ref %lu.\n", iface, ref ); + return ref; +} - TRACE( "iface %p.\n", iface ); +static ULONG WINAPI work_item_Release( IWorkItemHandler *iface ) +{ + struct work_item *impl = impl_from_IWorkItemHandler( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + TRACE( "iface %p, ref %lu.\n", iface, ref ); - EnterCriticalSection( &impl->cs ); - if (impl->status == Started) - hr = E_ILLEGAL_STATE_CHANGE; - else if (impl->status != Closed) + if (!ref) { - CloseThreadpoolWork( impl->async_run_work ); - impl->async_run_work = NULL; - impl->status = Closed; + if (impl->invoker) + IUnknown_Release( impl->invoker ); + if (impl->param) + IUnknown_Release( impl->param ); + free( impl ); } - LeaveCriticalSection( &impl->cs ); - - return hr; + return ref; } -static const struct IAsyncInfoVtbl async_info_vtbl = -{ - /* IUnknown methods */ - async_info_QueryInterface, - async_info_AddRef, - async_info_Release, - /* IInspectable methods */ - async_info_GetIids, - async_info_GetRuntimeClassName, - async_info_GetTrustLevel, - /* IAsyncInfo */ - async_info_get_Id, - async_info_get_Status, - async_info_get_ErrorCode, - async_info_Cancel, - async_info_Close, -}; - -static void CALLBACK async_info_callback( TP_CALLBACK_INSTANCE *instance, void *iface, TP_WORK *work ) +static HRESULT WINAPI work_item_Invoke( IWorkItemHandler *iface, IAsyncAction *action ) { - struct async_info *impl = impl_from_IWineAsyncInfoImpl( iface ); - IInspectable *operation = impl->IInspectable_outer; - PROPVARIANT result; + struct work_item *impl = impl_from_IWorkItemHandler( iface ); + IAsyncInfo *info; + AsyncStatus status; HRESULT hr; - hr = impl->callback( impl->invoker, impl->param, &result ); + TRACE( "iface %p, action %p.\n", iface, action ); - EnterCriticalSection( &impl->cs ); - if (impl->status != Closed) impl->status = FAILED(hr) ? Error : Completed; - PropVariantCopy( &impl->result, &result ); - impl->hr = hr; - - if (impl->handler != NULL && impl->handler != HANDLER_NOT_SET) - { - IWineAsyncOperationCompletedHandler *handler = impl->handler; - AsyncStatus status = impl->status; - impl->handler = NULL; /* Prevent concurrent invoke. */ - LeaveCriticalSection( &impl->cs ); - - IWineAsyncOperationCompletedHandler_Invoke( handler, operation, status ); - IWineAsyncOperationCompletedHandler_Release( handler ); - } - else LeaveCriticalSection( &impl->cs ); + hr = IAsyncAction_QueryInterface( action, &IID_IAsyncInfo, (void **)&info ); + if (FAILED( hr )) + return hr; - /* release refcount acquired in Start */ - IInspectable_Release( operation ); + hr = IAsyncInfo_get_Status( info, &status ); + IAsyncInfo_Release( info ); + if (FAILED( hr )) + return hr; - PropVariantClear( &result ); + return status != Canceled ? impl->callback( impl->invoker, impl->param, impl->result ) : S_OK; } -static HRESULT async_info_create( IUnknown *invoker, IUnknown *param, async_operation_callback callback, - IInspectable *outer, IWineAsyncInfoImpl **out ) +static const IWorkItemHandlerVtbl work_item_vtbl = { - struct async_info *impl; - HRESULT hr; - - if (!(impl = calloc( 1, sizeof(struct async_info) ))) return E_OUTOFMEMORY; - impl->IWineAsyncInfoImpl_iface.lpVtbl = &async_impl_vtbl; - impl->IAsyncInfo_iface.lpVtbl = &async_info_vtbl; - impl->IInspectable_outer = outer; - impl->ref = 1; + work_item_QueryInterface, + work_item_AddRef, + work_item_Release, + work_item_Invoke, +}; - impl->callback = callback; - impl->handler = HANDLER_NOT_SET; - impl->status = Started; - if (!(impl->async_run_work = CreateThreadpoolWork( async_info_callback, &impl->IWineAsyncInfoImpl_iface, NULL ))) - { - hr = HRESULT_FROM_WIN32( GetLastError() ); - free( impl ); - return hr; - } +static HRESULT work_item_create( IUnknown *invoker, IUnknown *param, async_operation_callback callback, + PROPVARIANT *result, IWorkItemHandler **handler ) +{ + struct work_item *impl; - if ((impl->invoker = invoker)) IUnknown_AddRef( impl->invoker ); - if ((impl->param = param)) IUnknown_AddRef( impl->param ); + impl = calloc( 1, sizeof( *impl ) ); + if (!impl) + return E_OUTOFMEMORY; - InitializeCriticalSectionEx( &impl->cs, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO ); - impl->cs.DebugInfo->Spare[0] = (DWORD_PTR)( __FILE__ ": async_info.cs" ); + impl->IWorkItemHandler_iface.lpVtbl = &work_item_vtbl; + impl->callback = callback; + impl->result = result; + impl->invoker = invoker; + impl->param = param; + if (invoker) + IUnknown_AddRef(invoker); + if (param) + IUnknown_AddRef(param); + impl->ref = 1; - *out = &impl->IWineAsyncInfoImpl_iface; + *handler = &impl->IWorkItemHandler_iface; return S_OK; } struct async_bool { IAsyncOperation_boolean IAsyncOperation_boolean_iface; - IWineAsyncInfoImpl *IWineAsyncInfoImpl_inner; - LONG ref; + struct async_operation_base base; }; static inline struct async_bool *impl_from_IAsyncOperation_boolean( IAsyncOperation_boolean *iface ) @@ -389,13 +294,13 @@ static HRESULT WINAPI async_bool_QueryInterface( IAsyncOperation_boolean *iface, return S_OK; } - return IWineAsyncInfoImpl_QueryInterface( impl->IWineAsyncInfoImpl_inner, iid, out ); + return IAsyncAction_QueryInterface( impl->base.inner_action, iid, out ); } static ULONG WINAPI async_bool_AddRef( IAsyncOperation_boolean *iface ) { struct async_bool *impl = impl_from_IAsyncOperation_boolean( iface ); - ULONG ref = InterlockedIncrement( &impl->ref ); + ULONG ref = InterlockedIncrement( &impl->base.ref ); TRACE( "iface %p, ref %lu.\n", iface, ref ); return ref; } @@ -403,14 +308,13 @@ static ULONG WINAPI async_bool_AddRef( IAsyncOperation_boolean *iface ) static ULONG WINAPI async_bool_Release( IAsyncOperation_boolean *iface ) { struct async_bool *impl = impl_from_IAsyncOperation_boolean( iface ); - ULONG ref = InterlockedDecrement( &impl->ref ); + ULONG ref = InterlockedDecrement( &impl->base.ref ); TRACE( "iface %p, ref %lu.\n", iface, ref ); if (!ref) { - /* guard against re-entry if inner releases an outer iface */ - InterlockedIncrement( &impl->ref ); - IWineAsyncInfoImpl_Release( impl->IWineAsyncInfoImpl_inner ); + IWorkItemHandler_Release(impl->base.work_item); + IAsyncAction_Release( impl->base.inner_action ); free( impl ); } @@ -438,18 +342,20 @@ static HRESULT WINAPI async_bool_GetTrustLevel( IAsyncOperation_boolean *iface, static HRESULT WINAPI async_bool_put_Completed( IAsyncOperation_boolean *iface, IAsyncOperationCompletedHandler_boolean *bool_handler ) { - IWineAsyncOperationCompletedHandler *handler = (IWineAsyncOperationCompletedHandler *)bool_handler; struct async_bool *impl = impl_from_IAsyncOperation_boolean( iface ); - TRACE( "iface %p, handler %p.\n", iface, handler ); - return IWineAsyncInfoImpl_put_Completed( impl->IWineAsyncInfoImpl_inner, (IWineAsyncOperationCompletedHandler *)handler ); + + TRACE( "iface %p, handler %p.\n", iface, bool_handler ); + + return async_operation_put_Completed( &impl->base, (IInspectable *)iface, bool_handler ); } static HRESULT WINAPI async_bool_get_Completed( IAsyncOperation_boolean *iface, IAsyncOperationCompletedHandler_boolean **bool_handler ) { - IWineAsyncOperationCompletedHandler **handler = (IWineAsyncOperationCompletedHandler **)bool_handler; struct async_bool *impl = impl_from_IAsyncOperation_boolean( iface ); - TRACE( "iface %p, handler %p.\n", iface, handler ); - return IWineAsyncInfoImpl_get_Completed( impl->IWineAsyncInfoImpl_inner, (IWineAsyncOperationCompletedHandler **)handler ); + + TRACE( "iface %p, handler %p.\n", iface, bool_handler ); + + return async_operation_get_Completed( &impl->base, &IID_IAsyncOperationCompletedHandler_boolean, (void **)bool_handler ); } static HRESULT WINAPI async_bool_GetResults( IAsyncOperation_boolean *iface, BOOLEAN *results ) @@ -460,10 +366,13 @@ static HRESULT WINAPI async_bool_GetResults( IAsyncOperation_boolean *iface, BOO TRACE( "iface %p, results %p.\n", iface, results ); - hr = IWineAsyncInfoImpl_get_Result( impl->IWineAsyncInfoImpl_inner, &result ); + hr = IAsyncAction_GetResults( impl->base.inner_action ); + if (hr == S_OK) + { + *results = impl->base.result.boolVal; + PropVariantClear( &result ); + } - *results = result.boolVal; - PropVariantClear( &result ); return hr; } @@ -483,6 +392,24 @@ static const struct IAsyncOperation_booleanVtbl async_bool_vtbl = async_bool_GetResults, }; +static IThreadPoolStatics *threadpool_statics; +static INIT_ONCE threadpool_statics_init = INIT_ONCE_STATIC_INIT; + +static BOOL CALLBACK init_threadpool_statics( INIT_ONCE *once, void *param, void **ctx ) +{ + HSTRING str; + HRESULT hr; + + hr = WindowsCreateString( RuntimeClass_Windows_System_Threading_ThreadPool, + wcslen( RuntimeClass_Windows_System_Threading_ThreadPool ), &str ); + if (FAILED( hr )) + return FALSE; + + hr = RoGetActivationFactory( str, &IID_IThreadPoolStatics, (void **)&threadpool_statics ); + WindowsDeleteString( str ); + return SUCCEEDED( hr ); +} + HRESULT async_operation_boolean_create( IUnknown *invoker, IUnknown *param, async_operation_callback callback, IAsyncOperation_boolean **out ) { @@ -490,18 +417,27 @@ HRESULT async_operation_boolean_create( IUnknown *invoker, IUnknown *param, asyn HRESULT hr; *out = NULL; + if (!InitOnceExecuteOnce( &threadpool_statics_init, init_threadpool_statics, NULL, NULL )) + return E_FAIL; + if (!(impl = calloc( 1, sizeof(*impl) ))) return E_OUTOFMEMORY; impl->IAsyncOperation_boolean_iface.lpVtbl = &async_bool_vtbl; - impl->ref = 1; - if (FAILED(hr = async_info_create( invoker, param, callback, (IInspectable *)&impl->IAsyncOperation_boolean_iface, &impl->IWineAsyncInfoImpl_inner )) || - FAILED(hr = IWineAsyncInfoImpl_Start( impl->IWineAsyncInfoImpl_inner ))) + hr = work_item_create( invoker, param, callback, &impl->base.result, &impl->base.work_item ); + if (FAILED( hr )) { - if (impl->IWineAsyncInfoImpl_inner) IWineAsyncInfoImpl_Release( impl->IWineAsyncInfoImpl_inner ); free( impl ); return hr; } + impl->base.ref = 1; + hr = IThreadPoolStatics_RunAsync( threadpool_statics, impl->base.work_item, &impl->base.inner_action ); + if (FAILED( hr )) + { + IWorkItemHandler_Release( impl->base.work_item ); + free( impl ); + return hr; + } *out = &impl->IAsyncOperation_boolean_iface; TRACE( "created IAsyncOperation_boolean %p\n", *out ); return S_OK; diff --git a/dlls/cryptowinrt/private.h b/dlls/cryptowinrt/private.h index 3ce3620118c..8a4595eb9ae 100644 --- a/dlls/cryptowinrt/private.h +++ b/dlls/cryptowinrt/private.h @@ -37,7 +37,8 @@ #define WIDL_using_Windows_Security_Credentials #include "windows.security.credentials.h" -#include "provider.h" +#define WIDL_using_Windows_System_Threading +#include "windows.system.threading.h" extern IActivationFactory *credentials_activation_factory; diff --git a/dlls/cryptowinrt/provider.idl b/dlls/cryptowinrt/provider.idl deleted file mode 100644 index 7196119dba0..00000000000 --- a/dlls/cryptowinrt/provider.idl +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2022 Mohamad Al-Jaf - * Copyright 2022 Rémi Bernon 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 - */ - -#pragma makedep header - -#ifdef __WIDL__ -#pragma winrt ns_prefix -#endif - -import "propidl.idl"; -import "inspectable.idl"; -import "asyncinfo.idl"; -import "eventtoken.idl"; -import "windowscontracts.idl"; -import "windows.foundation.idl"; - -namespace Windows.Security.Credentials { - /* type-pruning version of AsyncOperationCompletedHandler<T> */ - delegate HRESULT WineAsyncOperationCompletedHandler([in] IInspectable *async, [in] AsyncStatus status); - - [ - uuid(83f377ee-c799-11ec-9d64-0242ac120002) - ] - interface IWineAsyncInfoImpl : IUnknown - { - [propput] HRESULT Completed([in] WineAsyncOperationCompletedHandler *handler); - [propget] HRESULT Completed([out, retval] WineAsyncOperationCompletedHandler **handler); - [propget] HRESULT Result([out, retval] PROPVARIANT *result); - HRESULT Start(); - } -} -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/6889
Hi, It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated. The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=149894 Your paranoid android. === build (build log) === error: patch failed: dlls/cryptowinrt/Makefile.in:6 error: patch failed: dlls/cryptowinrt/async.c:2 error: patch failed: dlls/cryptowinrt/private.h:37 error: patch failed: dlls/cryptowinrt/provider.idl:1 Task: Patch failed to apply === debian11 (build log) === error: patch failed: dlls/cryptowinrt/Makefile.in:6 error: patch failed: dlls/cryptowinrt/async.c:2 error: patch failed: dlls/cryptowinrt/private.h:37 error: patch failed: dlls/cryptowinrt/provider.idl:1 Task: Patch failed to apply === debian11b (build log) === error: patch failed: dlls/cryptowinrt/Makefile.in:6 error: patch failed: dlls/cryptowinrt/async.c:2 error: patch failed: dlls/cryptowinrt/private.h:37 error: patch failed: dlls/cryptowinrt/provider.idl:1 Task: Patch failed to apply
participants (3)
-
Marvin -
Vibhav Pant -
Vibhav Pant (@vibhavp)