Signed-off-by: Nikolay Sivov nsivov@codeweavers.com
-- v2: threadpoolwinrt: Add initial implementation of RunAsync. threadpoolwinrt: Add a stub module. include: Add windows.system.threading.idl.
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- include/Makefile.in | 1 + include/windows.system.threading.idl | 96 ++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 include/windows.system.threading.idl
diff --git a/include/Makefile.in b/include/Makefile.in index 0598a3ce3de..14fe8e24863 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -809,6 +809,7 @@ SOURCES = \ windows.storage.streams.idl \ windows.system.idl \ windows.system.power.idl \ + windows.system.threading.idl \ windows.system.userprofile.idl \ windows.ui.idl \ windowscontracts.idl \ diff --git a/include/windows.system.threading.idl b/include/windows.system.threading.idl new file mode 100644 index 00000000000..f1c3ade1033 --- /dev/null +++ b/include/windows.system.threading.idl @@ -0,0 +1,96 @@ +/* + * Copyright 2022 Nikolay Sivov 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 + */ + +#ifdef __WIDL__ +#pragma winrt ns_prefix +#endif + +import "inspectable.idl"; +import "asyncinfo.idl"; +import "windowscontracts.idl"; +import "windows.foundation.idl"; + +namespace Windows.System.Threading +{ + typedef enum WorkItemPriority WorkItemPriority; + typedef enum WorkItemOptions WorkItemOptions; + + runtimeclass ThreadPool; + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0) + ] + enum WorkItemPriority + { + Low = -1, + Normal = 0, + High = 1 + }; + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + flags + ] + enum WorkItemOptions + { + None = 0x0, + TimeSliced = 0x1 + }; + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + uuid(1d1a8b8b-fa66-414f-9cbd-b65fc99d17fa) + ] + delegate HRESULT WorkItemHandler([in] Windows.Foundation.IAsyncAction *operation); + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + exclusiveto(Windows.System.Threading.ThreadPool), + uuid(b6bf67dd-84bd-44f8-ac1c-93ebcb9dba91) + ] + interface IThreadPoolStatics : IInspectable + { + [overload("RunAsync")] HRESULT RunAsync( + [in] Windows.System.Threading.WorkItemHandler *handler, + [out, retval] Windows.Foundation.IAsyncAction **operation + ); + + [overload("RunAsync")] HRESULT RunWithPriorityAsync( + [in] Windows.System.Threading.WorkItemHandler *handler, + [in] Windows.System.Threading.WorkItemPriority priority, + [out, retval] Windows.Foundation.IAsyncAction **operation + ); + + [overload("RunAsync")] HRESULT RunWithPriorityAndOptionsAsync( + [in] Windows.System.Threading.WorkItemHandler *handler, + [in] Windows.System.Threading.WorkItemPriority priority, + [in] Windows.System.Threading.WorkItemOptions options, + [out, retval] Windows.Foundation.IAsyncAction **operation + ); + } + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + marshaling_behavior(agile), + static(Windows.System.Threading.IThreadPoolStatics, Windows.Foundation.UniversalApiContract, 1.0), + threading(both) + ] + runtimeclass ThreadPool + { + } +}
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- configure | 2 + configure.ac | 1 + dlls/threadpoolwinrt/Makefile.in | 7 + dlls/threadpoolwinrt/classes.idl | 21 ++ dlls/threadpoolwinrt/main.c | 260 ++++++++++++++++++++++ dlls/threadpoolwinrt/threadpoolwinrt.spec | 3 + 6 files changed, 294 insertions(+) create mode 100644 dlls/threadpoolwinrt/Makefile.in create mode 100644 dlls/threadpoolwinrt/classes.idl create mode 100644 dlls/threadpoolwinrt/main.c create mode 100644 dlls/threadpoolwinrt/threadpoolwinrt.spec
diff --git a/configure b/configure index c79b3a373cd..19c9e1726ee 100755 --- a/configure +++ b/configure @@ -1372,6 +1372,7 @@ enable_taskschd enable_tbs enable_tdh enable_tdi_sys +enable_threadpoolwinrt enable_traffic enable_twain_32 enable_tzres @@ -21956,6 +21957,7 @@ wine_fn_config_makefile dlls/taskschd/tests enable_tests wine_fn_config_makefile dlls/tbs enable_tbs wine_fn_config_makefile dlls/tdh enable_tdh wine_fn_config_makefile dlls/tdi.sys enable_tdi_sys +wine_fn_config_makefile dlls/threadpoolwinrt enable_threadpoolwinrt wine_fn_config_makefile dlls/toolhelp.dll16 enable_win16 wine_fn_config_makefile dlls/traffic enable_traffic wine_fn_config_makefile dlls/twain.dll16 enable_win16 diff --git a/configure.ac b/configure.ac index d67b97d3ec9..2d94a28a7e3 100644 --- a/configure.ac +++ b/configure.ac @@ -3062,6 +3062,7 @@ WINE_CONFIG_MAKEFILE(dlls/taskschd/tests) WINE_CONFIG_MAKEFILE(dlls/tbs) WINE_CONFIG_MAKEFILE(dlls/tdh) WINE_CONFIG_MAKEFILE(dlls/tdi.sys) +WINE_CONFIG_MAKEFILE(dlls/threadpoolwinrt) WINE_CONFIG_MAKEFILE(dlls/toolhelp.dll16,enable_win16) WINE_CONFIG_MAKEFILE(dlls/traffic) WINE_CONFIG_MAKEFILE(dlls/twain.dll16,enable_win16) diff --git a/dlls/threadpoolwinrt/Makefile.in b/dlls/threadpoolwinrt/Makefile.in new file mode 100644 index 00000000000..1058cac55a8 --- /dev/null +++ b/dlls/threadpoolwinrt/Makefile.in @@ -0,0 +1,7 @@ +MODULE = threadpoolwinrt.dll +IMPORTS = combase uuid + +C_SRCS = \ + main.c + +IDL_SRCS = classes.idl diff --git a/dlls/threadpoolwinrt/classes.idl b/dlls/threadpoolwinrt/classes.idl new file mode 100644 index 00000000000..1b4a653a106 --- /dev/null +++ b/dlls/threadpoolwinrt/classes.idl @@ -0,0 +1,21 @@ +/* + * Copyright 2022 Nikolay Sivov 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 register + +#include "windows.system.threading.idl" diff --git a/dlls/threadpoolwinrt/main.c b/dlls/threadpoolwinrt/main.c new file mode 100644 index 00000000000..9795abb38d8 --- /dev/null +++ b/dlls/threadpoolwinrt/main.c @@ -0,0 +1,260 @@ +/* + * Copyright 2022 Nikolay Sivov for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdarg.h> + +#define COBJMACROS +#include "windef.h" +#include "winbase.h" +#include "winstring.h" +#include "wine/debug.h" +#include "objbase.h" + +#include "initguid.h" +#include "activation.h" + +#define WIDL_using_Windows_Foundation +#define WIDL_using_Windows_Foundation_Collections +#include "windows.foundation.h" +#define WIDL_using_Windows_System_Threading +#include "windows.system.threading.h" + +WINE_DEFAULT_DEBUG_CHANNEL(threadpool); + +static const char *debugstr_hstring(HSTRING hstr) +{ + const WCHAR *str; + UINT32 len; + if (hstr && !((ULONG_PTR)hstr >> 16)) return "(invalid)"; + str = WindowsGetStringRawBuffer(hstr, &len); + return wine_dbgstr_wn(str, len); +} + +struct threadpool_factory +{ + IActivationFactory IActivationFactory_iface; + IThreadPoolStatics IThreadPoolStatics_iface; + LONG refcount; +}; + +static inline struct threadpool_factory *impl_from_IActivationFactory(IActivationFactory *iface) +{ + return CONTAINING_RECORD(iface, struct threadpool_factory, IActivationFactory_iface); +} + +static inline struct threadpool_factory *impl_from_IThreadPoolStatics(IThreadPoolStatics *iface) +{ + return CONTAINING_RECORD(iface, struct threadpool_factory, IThreadPoolStatics_iface); +} + +static HRESULT STDMETHODCALLTYPE threadpool_factory_QueryInterface( + IActivationFactory *iface, REFIID iid, void **out) +{ + struct threadpool_factory *factory = impl_from_IActivationFactory(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_IActivationFactory)) + { + IUnknown_AddRef(iface); + *out = &factory->IActivationFactory_iface; + return S_OK; + } + + if (IsEqualGUID(iid, &IID_IThreadPoolStatics)) + { + IUnknown_AddRef(iface); + *out = &factory->IThreadPoolStatics_iface; + return S_OK; + } + + FIXME("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG STDMETHODCALLTYPE threadpool_factory_AddRef(IActivationFactory *iface) +{ + struct threadpool_factory *factory = impl_from_IActivationFactory(iface); + ULONG refcount = InterlockedIncrement(&factory->refcount); + + TRACE("iface %p, refcount %lu.\n", iface, refcount); + + return refcount; +} + +static ULONG STDMETHODCALLTYPE threadpool_factory_Release(IActivationFactory *iface) +{ + struct threadpool_factory *factory = impl_from_IActivationFactory(iface); + ULONG refcount = InterlockedDecrement(&factory->refcount); + + TRACE("iface %p, refcount %lu.\n", iface, refcount); + + return refcount; +} + +static HRESULT STDMETHODCALLTYPE threadpool_factory_GetIids( + IActivationFactory *iface, ULONG *iid_count, IID **iids) +{ + FIXME("iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE threadpool_factory_GetRuntimeClassName( + IActivationFactory *iface, HSTRING *class_name) +{ + FIXME("iface %p, class_name %p stub!\n", iface, class_name); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE threadpool_factory_GetTrustLevel( + IActivationFactory *iface, TrustLevel *trust_level) +{ + FIXME("iface %p, trust_level %p stub!\n", iface, trust_level); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE threadpool_factory_ActivateInstance( + IActivationFactory *iface, IInspectable **instance) +{ + FIXME("iface %p, instance %p stub!\n", iface, instance); + return E_NOTIMPL; +} + +static const struct IActivationFactoryVtbl threadpool_factory_vtbl = +{ + threadpool_factory_QueryInterface, + threadpool_factory_AddRef, + threadpool_factory_Release, + /* IInspectable methods */ + threadpool_factory_GetIids, + threadpool_factory_GetRuntimeClassName, + threadpool_factory_GetTrustLevel, + /* IActivationFactory methods */ + threadpool_factory_ActivateInstance, +}; + +static HRESULT STDMETHODCALLTYPE threadpool_statics_QueryInterface( + IThreadPoolStatics *iface, REFIID iid, void **object) +{ + struct threadpool_factory *factory = impl_from_IThreadPoolStatics(iface); + return IActivationFactory_QueryInterface(&factory->IActivationFactory_iface, iid, object); +} + +static ULONG STDMETHODCALLTYPE threadpool_statics_AddRef(IThreadPoolStatics *iface) +{ + struct threadpool_factory *factory = impl_from_IThreadPoolStatics(iface); + return IActivationFactory_AddRef(&factory->IActivationFactory_iface); +} + +static ULONG STDMETHODCALLTYPE threadpool_statics_Release(IThreadPoolStatics *iface) +{ + struct threadpool_factory *factory = impl_from_IThreadPoolStatics(iface); + return IActivationFactory_Release(&factory->IActivationFactory_iface); +} + +static HRESULT STDMETHODCALLTYPE threadpool_statics_GetIids( + IThreadPoolStatics *iface, ULONG *iid_count, IID **iids) +{ + FIXME("iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE threadpool_statics_GetRuntimeClassName( + IThreadPoolStatics *iface, HSTRING *class_name) +{ + FIXME("iface %p, class_name %p stub!\n", iface, class_name); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE threadpool_statics_GetTrustLevel( + IThreadPoolStatics *iface, TrustLevel *trust_level) +{ + FIXME("iface %p, trust_level %p stub!\n", iface, trust_level); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE threadpool_statics_RunAsync( + IThreadPoolStatics *iface, IWorkItemHandler *handler, IAsyncAction **operation) +{ + FIXME("iface %p, handler %p, operation %p stub!\n", iface, handler, operation); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE threadpool_statics_RunWithPriorityAsync( + IThreadPoolStatics *iface, IWorkItemHandler *handler, WorkItemPriority priority, IAsyncAction **operation) +{ + FIXME("iface %p, handler %p, priority %d, operation %p stub!\n", iface, handler, priority, operation); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE threadpool_statics_RunWithPriorityAndOptionsAsync( + IThreadPoolStatics *iface, IWorkItemHandler *handler, WorkItemPriority priority, + WorkItemOptions options, IAsyncAction **operation) +{ + FIXME("iface %p, handler %p, priority %d, options %d, operation %p stub!\n", iface, handler, priority, options, operation); + return E_NOTIMPL; +} + +static const struct IThreadPoolStaticsVtbl threadpool_statics_vtbl = +{ + threadpool_statics_QueryInterface, + threadpool_statics_AddRef, + threadpool_statics_Release, + /* IInspectable methods */ + threadpool_statics_GetIids, + threadpool_statics_GetRuntimeClassName, + threadpool_statics_GetTrustLevel, + /* IThreadPoolStatics methods */ + threadpool_statics_RunAsync, + threadpool_statics_RunWithPriorityAsync, + threadpool_statics_RunWithPriorityAndOptionsAsync, +}; + +static struct threadpool_factory threadpool_factory = +{ + .IActivationFactory_iface.lpVtbl = &threadpool_factory_vtbl, + .IThreadPoolStatics_iface.lpVtbl = &threadpool_statics_vtbl, +}; + +HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **out) +{ + FIXME("clsid %s, riid %s, out %p stub!\n", debugstr_guid(clsid), debugstr_guid(riid), out); + return CLASS_E_CLASSNOTAVAILABLE; +} + +HRESULT WINAPI DllGetActivationFactory(HSTRING classid, IActivationFactory **factory) +{ + const WCHAR *name = WindowsGetStringRawBuffer(classid, NULL); + + TRACE("classid %s, factory %p.\n", debugstr_hstring(classid), factory); + + *factory = NULL; + + if (!wcscmp(name, RuntimeClass_Windows_System_Threading_ThreadPool)) + { + *factory = &threadpool_factory.IActivationFactory_iface; + IUnknown_AddRef(*factory); + } + + if (*factory) return S_OK; + return CLASS_E_CLASSNOTAVAILABLE; +} diff --git a/dlls/threadpoolwinrt/threadpoolwinrt.spec b/dlls/threadpoolwinrt/threadpoolwinrt.spec new file mode 100644 index 00000000000..20a8bfa98ea --- /dev/null +++ b/dlls/threadpoolwinrt/threadpoolwinrt.spec @@ -0,0 +1,3 @@ +@ stdcall -private DllCanUnloadNow() +@ stdcall -private DllGetActivationFactory(ptr ptr) +@ stdcall -private DllGetClassObject(ptr ptr ptr)
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- configure | 1 + configure.ac | 1 + dlls/threadpoolwinrt/main.c | 390 +++++++++++++++++++++++- dlls/threadpoolwinrt/tests/Makefile.in | 5 + dlls/threadpoolwinrt/tests/threadpool.c | 292 ++++++++++++++++++ 5 files changed, 683 insertions(+), 6 deletions(-) create mode 100644 dlls/threadpoolwinrt/tests/Makefile.in create mode 100644 dlls/threadpoolwinrt/tests/threadpool.c
diff --git a/configure b/configure index 19c9e1726ee..3898637ccc7 100755 --- a/configure +++ b/configure @@ -21958,6 +21958,7 @@ wine_fn_config_makefile dlls/tbs enable_tbs wine_fn_config_makefile dlls/tdh enable_tdh wine_fn_config_makefile dlls/tdi.sys enable_tdi_sys wine_fn_config_makefile dlls/threadpoolwinrt enable_threadpoolwinrt +wine_fn_config_makefile dlls/threadpoolwinrt/tests enable_tests wine_fn_config_makefile dlls/toolhelp.dll16 enable_win16 wine_fn_config_makefile dlls/traffic enable_traffic wine_fn_config_makefile dlls/twain.dll16 enable_win16 diff --git a/configure.ac b/configure.ac index 2d94a28a7e3..f5361fde783 100644 --- a/configure.ac +++ b/configure.ac @@ -3063,6 +3063,7 @@ WINE_CONFIG_MAKEFILE(dlls/tbs) WINE_CONFIG_MAKEFILE(dlls/tdh) WINE_CONFIG_MAKEFILE(dlls/tdi.sys) WINE_CONFIG_MAKEFILE(dlls/threadpoolwinrt) +WINE_CONFIG_MAKEFILE(dlls/threadpoolwinrt/tests) WINE_CONFIG_MAKEFILE(dlls/toolhelp.dll16,enable_win16) WINE_CONFIG_MAKEFILE(dlls/traffic) WINE_CONFIG_MAKEFILE(dlls/twain.dll16,enable_win16) diff --git a/dlls/threadpoolwinrt/main.c b/dlls/threadpoolwinrt/main.c index 9795abb38d8..3ba0837cfc6 100644 --- a/dlls/threadpoolwinrt/main.c +++ b/dlls/threadpoolwinrt/main.c @@ -17,6 +17,7 @@ */
#include <stdarg.h> +#include <assert.h>
#define COBJMACROS #include "windef.h" @@ -52,6 +53,13 @@ struct threadpool_factory LONG refcount; };
+struct async_action +{ + IAsyncAction IAsyncAction_iface; + IAsyncInfo IAsyncInfo_iface; + LONG refcount; +}; + static inline struct threadpool_factory *impl_from_IActivationFactory(IActivationFactory *iface) { return CONTAINING_RECORD(iface, struct threadpool_factory, IActivationFactory_iface); @@ -62,6 +70,373 @@ static inline struct threadpool_factory *impl_from_IThreadPoolStatics(IThreadPoo return CONTAINING_RECORD(iface, struct threadpool_factory, IThreadPoolStatics_iface); }
+static inline struct async_action *impl_from_IAsyncAction(IAsyncAction *iface) +{ + return CONTAINING_RECORD(iface, struct async_action, IAsyncAction_iface); +} + +static inline struct async_action *impl_from_IAsyncInfo(IAsyncInfo *iface) +{ + return CONTAINING_RECORD(iface, struct async_action, IAsyncInfo_iface); +} + +static HRESULT STDMETHODCALLTYPE async_action_QueryInterface(IAsyncAction *iface, REFIID iid, void **out) +{ + struct async_action *action = impl_from_IAsyncAction(iface); + + TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); + + if (IsEqualIID(iid, &IID_IAsyncAction) + || IsEqualIID(iid, &IID_IInspectable) + || IsEqualIID(iid, &IID_IUnknown)) + { + *out = iface; + } + else if (IsEqualIID(iid, &IID_IAsyncInfo)) + { + *out = &action->IAsyncInfo_iface; + } + else + { + *out = NULL; + WARN("Unsupported interface %s.\n", debugstr_guid(iid)); + } + + IUnknown_AddRef((IUnknown *)*out); + return S_OK; +} + +static ULONG STDMETHODCALLTYPE async_action_AddRef(IAsyncAction *iface) +{ + struct async_action *action = impl_from_IAsyncAction(iface); + ULONG refcount = InterlockedIncrement(&action->refcount); + + TRACE("iface %p, refcount %lu.\n", iface, refcount); + + return refcount; +} + +static ULONG STDMETHODCALLTYPE async_action_Release(IAsyncAction *iface) +{ + struct async_action *action = impl_from_IAsyncAction(iface); + ULONG refcount = InterlockedDecrement(&action->refcount); + + TRACE("iface %p, refcount %lu.\n", iface, refcount); + + if (!refcount) + free(action); + + return refcount; +} + +static HRESULT STDMETHODCALLTYPE async_action_GetIids( + IAsyncAction *iface, ULONG *iid_count, IID **iids) +{ + FIXME("iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE async_action_GetRuntimeClassName( + IAsyncAction *iface, HSTRING *class_name) +{ + FIXME("iface %p, class_name %p stub!\n", iface, class_name); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE async_action_GetTrustLevel( + IAsyncAction *iface, TrustLevel *trust_level) +{ + FIXME("iface %p, trust_level %p stub!\n", iface, trust_level); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE async_action_put_Completed(IAsyncAction *iface, IAsyncActionCompletedHandler *handler) +{ + FIXME("iface %p, handler %p stub!\n", iface, handler); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE async_action_get_Completed(IAsyncAction *iface, IAsyncActionCompletedHandler **handler) +{ + FIXME("iface %p, handler %p stub!\n", iface, handler); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE async_action_GetResults(IAsyncAction *iface) +{ + FIXME("iface %p stub!\n", iface); + + return E_NOTIMPL; +} + +static const IAsyncActionVtbl async_action_vtbl = +{ + async_action_QueryInterface, + async_action_AddRef, + async_action_Release, + async_action_GetIids, + async_action_GetRuntimeClassName, + async_action_GetTrustLevel, + async_action_put_Completed, + async_action_get_Completed, + async_action_GetResults, +}; + +static HRESULT STDMETHODCALLTYPE async_info_QueryInterface(IAsyncInfo *iface, REFIID iid, void **out) +{ + struct async_action *action = impl_from_IAsyncInfo(iface); + return IAsyncAction_QueryInterface(&action->IAsyncAction_iface, iid, out); +} + +static ULONG STDMETHODCALLTYPE async_info_AddRef(IAsyncInfo *iface) +{ + struct async_action *action = impl_from_IAsyncInfo(iface); + return IAsyncAction_AddRef(&action->IAsyncAction_iface); +} + +static ULONG STDMETHODCALLTYPE async_info_Release(IAsyncInfo *iface) +{ + struct async_action *action = impl_from_IAsyncInfo(iface); + return IAsyncAction_AddRef(&action->IAsyncAction_iface); +} + +static HRESULT STDMETHODCALLTYPE async_info_GetIids(IAsyncInfo *iface, ULONG *iid_count, IID **iids) +{ + struct async_action *action = impl_from_IAsyncInfo(iface); + return IAsyncAction_GetIids(&action->IAsyncAction_iface, iid_count, iids); +} + +static HRESULT STDMETHODCALLTYPE async_info_GetRuntimeClassName(IAsyncInfo *iface, HSTRING *class_name) +{ + struct async_action *action = impl_from_IAsyncInfo(iface); + return IAsyncAction_GetRuntimeClassName(&action->IAsyncAction_iface, class_name); +} + +static HRESULT STDMETHODCALLTYPE async_info_GetTrustLevel(IAsyncInfo *iface, TrustLevel *trust_level) +{ + struct async_action *action = impl_from_IAsyncInfo(iface); + return IAsyncAction_GetTrustLevel(&action->IAsyncAction_iface, trust_level); +} + +static HRESULT STDMETHODCALLTYPE async_info_get_Id(IAsyncInfo *iface, UINT32 *id) +{ + FIXME("iface %p, id %p stub!\n", iface, id); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE async_info_get_Status(IAsyncInfo *iface, AsyncStatus *status) +{ + FIXME("iface %p, status %p stub!\n", iface, status); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE async_info_get_ErrorCode(IAsyncInfo *iface, HRESULT *error_code) +{ + FIXME("iface %p, error_code %p stub!\n", iface, error_code); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE async_info_Cancel(IAsyncInfo *iface) +{ + FIXME("iface %p stub!\n", iface); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE async_info_Close(IAsyncInfo *iface) +{ + FIXME("iface %p stub!\n", iface); + + return E_NOTIMPL; +} + +static const IAsyncInfoVtbl async_info_vtbl = +{ + async_info_QueryInterface, + async_info_AddRef, + async_info_Release, + async_info_GetIids, + async_info_GetRuntimeClassName, + async_info_GetTrustLevel, + async_info_get_Id, + async_info_get_Status, + async_info_get_ErrorCode, + async_info_Cancel, + 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; + + *ret = &object->IAsyncAction_iface; + + return S_OK; +} + +struct work_item +{ + IWorkItemHandler *handler; + IAsyncAction *action; +}; + +static void release_work_item(struct work_item *item) +{ + IWorkItemHandler_Release(item->handler); + IAsyncAction_Release(item->action); + free(item); +} + +static HRESULT alloc_work_item(IWorkItemHandler *handler, struct work_item **ret) +{ + struct work_item *object; + HRESULT hr; + + *ret = NULL; + + if (!(object = calloc(1, sizeof(*object)))) + return E_OUTOFMEMORY; + + if (FAILED(hr = async_action_create(&object->action))) + { + free(object); + return hr; + } + + IWorkItemHandler_AddRef((object->handler = handler)); + + *ret = object; + + 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; + TP_POOL *pool; +}; + +static struct thread_pool pools[3]; + +static BOOL CALLBACK pool_init_once(INIT_ONCE *init_once, void *param, void **context) +{ + struct thread_pool *pool = param; + + if (!(pool->pool = CreateThreadpool(NULL))) return FALSE; + + SetThreadpoolThreadMaximum(pool->pool, 10); + + 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) +{ + 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; + + work = CreateThreadpoolWork(pool_work_callback, item, NULL); + SubmitThreadpoolWork(work); + + return S_OK; +} + +static HRESULT run_async(IWorkItemHandler *handler, WorkItemPriority priority, WorkItemOptions options, + IAsyncAction **action) +{ + struct work_item *item; + HANDLE thread; + HRESULT hr; + + *action = NULL; + + if (!handler) + return E_INVALIDARG; + + if (priority < WorkItemPriority_Low || priority > WorkItemPriority_High) + return E_INVALIDARG; + + if (FAILED(hr = alloc_work_item(handler, &item))) + return hr; + + if (options == WorkItemOptions_TimeSliced) + { + 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()); + hr = HRESULT_FROM_WIN32(GetLastError()); + release_work_item(item); + return hr; + } + + if (priority != WorkItemPriority_Normal) + { + SetThreadPriority(thread, priority == WorkItemPriority_High ? THREAD_PRIORITY_HIGHEST : THREAD_PRIORITY_LOWEST); + ResumeThread(thread); + } + CloseHandle(thread); + } + else + { + hr = submit_threadpool_work(item, priority); + } + + if (FAILED(hr)) + { + release_work_item(item); + return hr; + } + + IAsyncAction_AddRef((*action = item->action)); + + return hr; +} + static HRESULT STDMETHODCALLTYPE threadpool_factory_QueryInterface( IActivationFactory *iface, REFIID iid, void **out) { @@ -195,23 +570,26 @@ static HRESULT STDMETHODCALLTYPE threadpool_statics_GetTrustLevel( static HRESULT STDMETHODCALLTYPE threadpool_statics_RunAsync( IThreadPoolStatics *iface, IWorkItemHandler *handler, IAsyncAction **operation) { - FIXME("iface %p, handler %p, operation %p stub!\n", iface, handler, operation); - return E_NOTIMPL; + TRACE("iface %p, handler %p, operation %p.\n", iface, handler, operation); + + return run_async(handler, WorkItemPriority_Normal, WorkItemOptions_None, operation); }
static HRESULT STDMETHODCALLTYPE threadpool_statics_RunWithPriorityAsync( IThreadPoolStatics *iface, IWorkItemHandler *handler, WorkItemPriority priority, IAsyncAction **operation) { - FIXME("iface %p, handler %p, priority %d, operation %p stub!\n", iface, handler, priority, operation); - return E_NOTIMPL; + TRACE("iface %p, handler %p, priority %d, operation %p.\n", iface, handler, priority, operation); + + return run_async(handler, priority, WorkItemOptions_None, operation); }
static HRESULT STDMETHODCALLTYPE threadpool_statics_RunWithPriorityAndOptionsAsync( IThreadPoolStatics *iface, IWorkItemHandler *handler, WorkItemPriority priority, WorkItemOptions options, IAsyncAction **operation) { - FIXME("iface %p, handler %p, priority %d, options %d, operation %p stub!\n", iface, handler, priority, options, operation); - return E_NOTIMPL; + TRACE("iface %p, handler %p, priority %d, options %d, operation %p.\n", iface, handler, priority, options, operation); + + return run_async(handler, priority, options, operation); }
static const struct IThreadPoolStaticsVtbl threadpool_statics_vtbl = diff --git a/dlls/threadpoolwinrt/tests/Makefile.in b/dlls/threadpoolwinrt/tests/Makefile.in new file mode 100644 index 00000000000..ca1206d68da --- /dev/null +++ b/dlls/threadpoolwinrt/tests/Makefile.in @@ -0,0 +1,5 @@ +TESTDLL = threadpoolwinrt.dll +IMPORTS = combase uuid + +C_SRCS = \ + threadpool.c diff --git a/dlls/threadpoolwinrt/tests/threadpool.c b/dlls/threadpoolwinrt/tests/threadpool.c new file mode 100644 index 00000000000..2a6ba32d93b --- /dev/null +++ b/dlls/threadpoolwinrt/tests/threadpool.c @@ -0,0 +1,292 @@ +/* + * Copyright 2022 Nikolay Sivov 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 + */ +#define COBJMACROS +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winstring.h" + +#include "initguid.h" +#include "roapi.h" + +#define WIDL_using_Windows_Foundation +#define WIDL_using_Windows_Foundation_Collections +#include "windows.foundation.h" +#define WIDL_using_Windows_System_Threading +#include "windows.system.threading.h" + +#include "wine/test.h" + +#define check_interface(a, b, c) check_interface_(__LINE__, a, b, c) +static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOOL supported) +{ + IUnknown *iface = iface_ptr; + HRESULT hr, expected_hr; + IUnknown *unk; + + expected_hr = supported ? S_OK : E_NOINTERFACE; + + hr = IUnknown_QueryInterface(iface, iid, (void **)&unk); + ok_(__FILE__, line)(hr == expected_hr, "Got hr %#lx, expected %#lx.\n", hr, expected_hr); + if (SUCCEEDED(hr)) + IUnknown_Release(unk); +} + +static const WCHAR *class_name = L"Windows.System.Threading.ThreadPool"; + +static void test_interfaces(void) +{ + IThreadPoolStatics *threadpool_statics; + IActivationFactory *factory; + HSTRING classid; + HRESULT hr; + + hr = RoInitialize(RO_INIT_MULTITHREADED); + ok(SUCCEEDED(hr), "Unexpected hr %#lx.\n", hr); + + hr = WindowsCreateString(class_name, wcslen(class_name), &classid); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = RoGetActivationFactory(classid, &IID_IActivationFactory, (void **)&factory); + ok(hr == S_OK || broken(hr == REGDB_E_CLASSNOTREG), "Unexpected hr %#lx.\n", hr); + if (hr == REGDB_E_CLASSNOTREG) + { + win_skip("%s runtimeclass not registered, skipping tests.\n", wine_dbgstr_w(class_name)); + return; + } + + check_interface(factory, &IID_IInspectable, TRUE); + check_interface(factory, &IID_IAgileObject, TRUE); + check_interface(factory, &IID_IThreadPoolStatics, TRUE); + + hr = IActivationFactory_QueryInterface(factory, &IID_IThreadPoolStatics, (void **)&threadpool_statics); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + check_interface(threadpool_statics, &IID_IInspectable, TRUE); + check_interface(threadpool_statics, &IID_IAgileObject, TRUE); + + IThreadPoolStatics_Release(threadpool_statics); + IActivationFactory_Release(factory); + WindowsDeleteString(classid); + + RoUninitialize(); +} + +struct work_item +{ + IWorkItemHandler IWorkItemHandler_iface; + LONG refcount; + HANDLE event; +}; + +static struct work_item * impl_from_IWorkItemHandler(IWorkItemHandler *iface) +{ + return CONTAINING_RECORD(iface, struct work_item, IWorkItemHandler_iface); +} + +static HRESULT STDMETHODCALLTYPE work_item_QueryInterface(IWorkItemHandler *iface, REFIID riid, void **obj) +{ + if (IsEqualIID(riid, &IID_IWorkItemHandler) + || IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + IWorkItemHandler_AddRef(iface); + return S_OK; + } + + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG STDMETHODCALLTYPE work_item_AddRef(IWorkItemHandler *iface) +{ + struct work_item *item = impl_from_IWorkItemHandler(iface); + return InterlockedIncrement(&item->refcount); +} + +static ULONG STDMETHODCALLTYPE work_item_Release(IWorkItemHandler *iface) +{ + struct work_item *item = impl_from_IWorkItemHandler(iface); + ULONG refcount = InterlockedDecrement(&item->refcount); + + if (!refcount) + { + CloseHandle(item->event); + free(item); + } + + return refcount; +} + +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; + + 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); + + hr = IAsyncAction_GetResults(action); + 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); + + SetEvent(item->event); + + return S_OK; +} + +static const IWorkItemHandlerVtbl work_item_vtbl = +{ + work_item_QueryInterface, + work_item_AddRef, + work_item_Release, + work_item_Invoke, +}; + +static HRESULT create_work_item(IWorkItemHandler **item) +{ + struct work_item *object; + + *item = NULL; + + if (!(object = calloc(1, sizeof(*object)))) + return E_OUTOFMEMORY; + + object->IWorkItemHandler_iface.lpVtbl = &work_item_vtbl; + object->refcount = 1; + object->event = CreateEventW(NULL, FALSE, FALSE, NULL); + + *item = &object->IWorkItemHandler_iface; + + return S_OK; +} + +static void test_RunAsync(void) +{ + IActivationFactory *factory = NULL; + IThreadPoolStatics *threadpool_statics; + IWorkItemHandler *item_iface; + struct work_item *item; + IAsyncAction *action; + HSTRING classid; + HRESULT hr; + DWORD ret; + + hr = RoInitialize(RO_INIT_MULTITHREADED); + ok(SUCCEEDED(hr), "Unexpected hr %#lx.\n", hr); + + hr = WindowsCreateString(class_name, wcslen(class_name), &classid); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = RoGetActivationFactory(classid, &IID_IActivationFactory, (void **)&factory); + ok(hr == S_OK || broken(hr == REGDB_E_CLASSNOTREG), "Unexpected hr %#lx.\n", hr); + if (hr == REGDB_E_CLASSNOTREG) + return; + + hr = IActivationFactory_QueryInterface(factory, &IID_IThreadPoolStatics, (void **)&threadpool_statics); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IThreadPoolStatics_RunAsync(threadpool_statics, NULL, &action); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + + hr = create_work_item(&item_iface); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + item = impl_from_IWorkItemHandler(item_iface); + + hr = IThreadPoolStatics_RunWithPriorityAsync(threadpool_statics, item_iface, WorkItemPriority_High + 1, &action); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + + hr = IThreadPoolStatics_RunAsync(threadpool_statics, item_iface, &action); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ret = WaitForSingleObject(item->event, 1000); + ok(!ret, "Unexpected wait result %lu.\n", ret); + + check_interface(action, &IID_IAsyncAction, TRUE); + check_interface(action, &IID_IAsyncInfo, TRUE); + check_interface(action, &IID_IInspectable, TRUE); + + IAsyncAction_Release(action); + + hr = IThreadPoolStatics_RunWithPriorityAsync(threadpool_statics, item_iface, WorkItemPriority_Normal, &action); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ret = WaitForSingleObject(item->event, 1000); + ok(!ret, "Unexpected wait result %lu.\n", ret); + IAsyncAction_Release(action); + + 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); + IAsyncAction_Release(action); + + hr = IThreadPoolStatics_RunWithPriorityAndOptionsAsync(threadpool_statics, item_iface, WorkItemPriority_Low, + 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); + IAsyncAction_Release(action); + + hr = IThreadPoolStatics_RunWithPriorityAndOptionsAsync(threadpool_statics, item_iface, WorkItemPriority_High, + 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); + IAsyncAction_Release(action); + + IWorkItemHandler_Release(item_iface); + + IThreadPoolStatics_Release(threadpool_statics); + IActivationFactory_Release(factory); + + WindowsDeleteString(classid); + + RoUninitialize(); +} + +START_TEST(threadpool) +{ + test_interfaces(); + test_RunAsync(); +}
Bernhard Kölbl (@besentv) commented about dlls/threadpoolwinrt/main.c:
- IActivationFactory IActivationFactory_iface;
- IThreadPoolStatics IThreadPoolStatics_iface;
- LONG refcount;
+};
+static inline struct threadpool_factory *impl_from_IActivationFactory(IActivationFactory *iface) +{
- return CONTAINING_RECORD(iface, struct threadpool_factory, IActivationFactory_iface);
+}
+static inline struct threadpool_factory *impl_from_IThreadPoolStatics(IThreadPoolStatics *iface) +{
- return CONTAINING_RECORD(iface, struct threadpool_factory, IThreadPoolStatics_iface);
+}
+static HRESULT STDMETHODCALLTYPE threadpool_factory_QueryInterface(
We usually apply WINAPI instead of STDMETHODCALLTYPE to WinRT functions to reduce line length. Also in most cases you could put the arguments on the same line as the function name.
(Additionally, we kinda agreed on using ntdll style (spaces after function braces), but that isn't so necessary.)
Bernhard Kölbl (@besentv) commented about dlls/threadpoolwinrt/main.c:
- threadpool_statics_Release,
- /* IInspectable methods */
- threadpool_statics_GetIids,
- threadpool_statics_GetRuntimeClassName,
- threadpool_statics_GetTrustLevel,
- /* IThreadPoolStatics methods */
- threadpool_statics_RunAsync,
- threadpool_statics_RunWithPriorityAsync,
- threadpool_statics_RunWithPriorityAndOptionsAsync,
+};
+static struct threadpool_factory threadpool_factory = +{
- .IActivationFactory_iface.lpVtbl = &threadpool_factory_vtbl,
- .IThreadPoolStatics_iface.lpVtbl = &threadpool_statics_vtbl,
+};
Initialize .refcount to 1.
On Mon Sep 19 14:10:56 2022 +0000, Bernhard Kölbl wrote:
Initialize .refcount to 1.
Why?
On Mon Sep 19 14:10:00 2022 +0000, Bernhard Kölbl wrote:
We usually apply WINAPI instead of STDMETHODCALLTYPE to WinRT functions to reduce line length. Also in most cases you could put the arguments on the same line as the function name. (Additionally, we kinda agreed on using ntdll style (spaces after function braces), but that isn't so necessary.)
STDMETHODCALLTYPE is used in wintypes, windows.media.devices, windows.globalization, and windows.gaming.input tests. So it's not really consistent. Regarding spaces, I don't see why style of one winrt module would extend to another. If it's a generally preferable style now, I don't remember it was mentioned anywhere.
Bernhard Kölbl (@besentv) commented about dlls/threadpoolwinrt/main.c:
- FIXME("clsid %s, riid %s, out %p stub!\n", debugstr_guid(clsid), debugstr_guid(riid), out);
- return CLASS_E_CLASSNOTAVAILABLE;
+}
+HRESULT WINAPI DllGetActivationFactory(HSTRING classid, IActivationFactory **factory) +{
- const WCHAR *name = WindowsGetStringRawBuffer(classid, NULL);
- TRACE("classid %s, factory %p.\n", debugstr_hstring(classid), factory);
- *factory = NULL;
- if (!wcscmp(name, RuntimeClass_Windows_System_Threading_ThreadPool))
- {
*factory = &threadpool_factory.IActivationFactory_iface;
IUnknown_AddRef(*factory);
`IInspectable_AddRef( (*factory = &threadpool_factory.IActivationFactory_iface) );` makes it a one-liner.
Or alternatively `IInspectable_QueryInterface( &threadpool_factory.IActivationFactory_iface, &IID_IActivationFactory, (void **)factory );`
Bernhard Kölbl (@besentv) commented about dlls/threadpoolwinrt/tests/threadpool.c:
+#define check_interface(a, b, c) check_interface_(__LINE__, a, b, c) +static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOOL supported) +{
- IUnknown *iface = iface_ptr;
- HRESULT hr, expected_hr;
- IUnknown *unk;
- expected_hr = supported ? S_OK : E_NOINTERFACE;
- hr = IUnknown_QueryInterface(iface, iid, (void **)&unk);
- ok_(__FILE__, line)(hr == expected_hr, "Got hr %#lx, expected %#lx.\n", hr, expected_hr);
- if (SUCCEEDED(hr))
IUnknown_Release(unk);
+}
+static const WCHAR *class_name = L"Windows.System.Threading.ThreadPool";
This name is a little ambiguous, given there is also the class ThreadPoolTimer. Maybe `threadpool_class_name`?
Bernhard Kölbl (@besentv) commented about dlls/threadpoolwinrt/main.c:
ResumeThread(thread);
}
CloseHandle(thread);
- }
- else
- {
hr = submit_threadpool_work(item, priority);
- }
- if (FAILED(hr))
- {
release_work_item(item);
return hr;
- }
- IAsyncAction_AddRef((*action = item->action));
Maybe I'm not seeing this correctly, but I think you're potentially accessing freed memory here.
Because in `alloc_work_item` you create IAsyncAction with refcount 1, then sumbit the work to Thread/Threadpool and free the work item inside the callback including IAsyncAction.
On Mon Sep 19 14:15:43 2022 +0000, Nikolay Sivov wrote:
STDMETHODCALLTYPE is used in wintypes, windows.media.devices, windows.globalization, and windows.gaming.input tests. So it's not really consistent. Regarding spaces, I don't see why style of one winrt module would extend to another. If it's a generally preferable style now, I don't remember it was mentioned anywhere.
Regarding style, yeah, but shorter lines are still preferable, aren't they?
On Mon Sep 19 14:12:21 2022 +0000, Nikolay Sivov wrote:
Why?
WinRT factories/static ifaces usually have the default ref value as 1. You could probably test that in the next patch.
Just my 2cents.
Also, in case you need it, we have IAsyncAction implemented in Windows.Gaming.Input and Windows.Media.Speech. It seems to me, that these should actually use the implementation provided in this Dll instead of having their own.
On Mon Sep 19 14:16:16 2022 +0000, Bernhard Kölbl wrote:
`IInspectable_AddRef( (*factory = &threadpool_factory.IActivationFactory_iface) );` makes it a one-liner. Or alternatively `IInspectable_QueryInterface( &threadpool_factory.IActivationFactory_iface, &IID_IActivationFactory, (void **)factory );`
I don't think it matters.