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).
-- v6: cryptowinrt: Rewrite IAsyncOperation using Windows.System.Threading.
From: Vibhav Pant vibhavp@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,
From: Vibhav Pant vibhavp@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);
From: Vibhav Pant vibhavp@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);
From: Vibhav Pant vibhavp@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); } }
From: Vibhav Pant vibhavp@gmail.com
--- dlls/cryptowinrt/Makefile.in | 1 - dlls/cryptowinrt/async.c | 479 +++++++++++++++------------------- dlls/cryptowinrt/private.h | 3 +- dlls/cryptowinrt/provider.idl | 47 ---- 4 files changed, 216 insertions(+), 314 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..bb6c76fec5e 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,268 @@
#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) +typedef HRESULT (WINAPI *async_completed_invoke_callback)(IInspectable *handler, IInspectable *info, AsyncStatus status);
-struct async_info +struct async_completed { - IWineAsyncInfoImpl IWineAsyncInfoImpl_iface; - IAsyncInfo IAsyncInfo_iface; - IInspectable *IInspectable_outer; + IAsyncActionCompletedHandler IAsyncActionCompletedHandler_iface; + IInspectable *outer_handler; + IInspectable *outer_operation; + async_completed_invoke_callback cb; 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 ) +#define DEFINE_ASYNC_COMPLETED_HANDLER_CALLBACK( type ) \ + static HRESULT WINAPI async_completed_handler_cb_##type( IInspectable *handler, IInspectable *operation, \ + AsyncStatus status ) \ + { \ + return IAsyncOperationCompletedHandler_##type##_Invoke( \ + (IAsyncOperationCompletedHandler_##type *)handler, (IAsyncOperation_##type *)operation, status ); \ + } + +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->outer_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->outer_handler ); + IInspectable_Release( impl->outer_operation ); 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; - - 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; -} - -static HRESULT WINAPI async_impl_get_Completed( IWineAsyncInfoImpl *iface, IWineAsyncOperationCompletedHandler **handler ) -{ - 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; + struct async_completed *impl = impl_from_IAsyncActionCompletedHandler( iface ); + return impl->cb( (IInspectable *)impl->outer_handler, (IInspectable *)impl->outer_operation, status); }
-static HRESULT WINAPI async_impl_get_Result( IWineAsyncInfoImpl *iface, PROPVARIANT *result ) +static const IAsyncActionCompletedHandlerVtbl async_completed_vtbl = { - 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 *outer_operation, IInspectable *outer_handler, + async_completed_invoke_callback cb, IAsyncActionCompletedHandler **handler ) { - struct async_info *impl = impl_from_IWineAsyncInfoImpl( iface ); - - TRACE( "iface %p.\n", iface ); - - /* keep the async alive in the callback */ - IInspectable_AddRef( impl->IInspectable_outer ); - SubmitThreadpoolWork( impl->async_run_work ); + struct async_completed *impl; + + impl = calloc( 1, sizeof( *impl ) ); + if (!impl) + return E_NOINTERFACE; + + impl->IAsyncActionCompletedHandler_iface.lpVtbl = &async_completed_vtbl; + impl->outer_operation = outer_operation; + impl->outer_handler = outer_handler; + IInspectable_AddRef( impl->outer_operation ); + IInspectable_AddRef( impl->outer_handler ); + impl->cb = cb; + 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 ) +/* operation should be an IAsyncOperation<T>, while handler should be an IAsyncOperationCompletedHandler<T>. */ +static HRESULT async_operation_put_Completed( struct async_operation_base *base, IInspectable *operation, + IInspectable *handler, async_completed_invoke_callback cb ) { - 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 *)operation, (IInspectable *)handler, cb, &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 ); + 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 = +static HRESULT WINAPI work_item_Invoke( IWorkItemHandler *iface, IAsyncAction *action ) { - /* 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 ) -{ - 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->invoker = invoker; + impl->param = param; + if (invoker) + IUnknown_AddRef(invoker); + if (param) + IUnknown_AddRef(param); + impl->ref = 1;
- *out = &impl->IWineAsyncInfoImpl_iface; + *result = &impl->result; + *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 +305,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 +319,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 ); }
@@ -436,34 +351,41 @@ static HRESULT WINAPI async_bool_GetTrustLevel( IAsyncOperation_boolean *iface, return E_NOTIMPL; }
+DEFINE_ASYNC_COMPLETED_HANDLER_CALLBACK( boolean ); + 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, (IInspectable *)bool_handler, + async_completed_handler_cb_boolean ); }
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 ) { struct async_bool *impl = impl_from_IAsyncOperation_boolean( iface ); - PROPVARIANT result = {.vt = VT_BOOL}; HRESULT hr;
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( impl->base.result ); + }
- *results = result.boolVal; - PropVariantClear( &result ); return hr; }
@@ -483,6 +405,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 +430,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(); - } -}
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=149909
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
On Sat Nov 23 08:16:05 2024 +0000, Vibhav Pant wrote:
changed this line in [version 6 of the diff](/wine/wine/-/merge_requests/6889/diffs?diff_id=145058&start_sha=d17b08e6b50ed502e62b756e9882bfcaa79a044f#532bd115d24f86d19dc230b4dae5dbba4ebea792_92_99)
Fair. I have replaced this with a wrapper callback that uses the actual interface vtables for `IAsyncOperationCompletedHandler<T>` and `IAsyncOperation<T>`.
I think sharing code through a static library of WinRT building blocks would be more flexible.
Oh definitely, I don't intend for this to be a replacement for !2298.. My motivation here is just for this to be a way to implement `IAsyncOperation<T>` by dogfooding the `Windows.System.Threading` module and reducing usage of Win32 primitives as much as possible (assuming that's a desirable goal for WinRT components :-)), and can possibly be the code for the static lib too (unless using COM modules from `dlls/` is frowned upon in static libraries).
Just had a quick look but it only seem to save ~50 LoC in cryptowinrt compared to the previous implementation, so I'm not sure it's worth the extra indirections and extra code?
Ideally, the `IAsyncOperation<T>` implementation code is generic enough, and can be boiled down to a macro implementation if needed. I think the LoC reductions are mostly cumulative as a result.
It's also not clear to me how `IAsyncOperationWithProgress` would be implemented with this
Yeah, I was thinking of keeping track of the progress handler from the outer `IAsyncOperationWithProgress` implementation with an additional wrapper like `struct async_operation`, but that would require guarding it with additional synchronization, which is suboptimal and defeats the purpose of not using on Win32 primitives in the first place.
This merge request was closed by Vibhav Pant.