Needed by Paint.NET installer.
-- v3: coremessaging: Partially implement CreateDispatcherQueueController(). coremessaging/tests: Add CreateDispatcherQueueController() tests. coremessaging/tests: Add IDispatcherQueueControllerStatics::CreateOnDedicatedThread() tests. coremessaging: Add IDispatcherQueueControllerStatics stub.
From: Mohamad Al-Jaf mohamadaljaf@gmail.com
--- configure.ac | 1 + dlls/coremessaging/Makefile.in | 4 +- dlls/coremessaging/classes.idl | 24 ++++ dlls/coremessaging/coremessaging.spec | 2 +- dlls/coremessaging/main.c | 141 ++++++++++++++++++++++- dlls/coremessaging/private.h | 74 ++++++++++++ dlls/coremessaging/tests/Makefile.in | 5 + dlls/coremessaging/tests/coremessaging.c | 90 +++++++++++++++ include/windows.system.idl | 2 + 9 files changed, 340 insertions(+), 3 deletions(-) create mode 100644 dlls/coremessaging/classes.idl create mode 100644 dlls/coremessaging/private.h create mode 100644 dlls/coremessaging/tests/Makefile.in create mode 100644 dlls/coremessaging/tests/coremessaging.c
diff --git a/configure.ac b/configure.ac index d1d07bc8f37..06da342bd4f 100644 --- a/configure.ac +++ b/configure.ac @@ -2495,6 +2495,7 @@ WINE_CONFIG_MAKEFILE(dlls/concrt140) WINE_CONFIG_MAKEFILE(dlls/concrt140/tests) WINE_CONFIG_MAKEFILE(dlls/connect) WINE_CONFIG_MAKEFILE(dlls/coremessaging) +WINE_CONFIG_MAKEFILE(dlls/coremessaging/tests) WINE_CONFIG_MAKEFILE(dlls/credui) WINE_CONFIG_MAKEFILE(dlls/credui/tests) WINE_CONFIG_MAKEFILE(dlls/crtdll) diff --git a/dlls/coremessaging/Makefile.in b/dlls/coremessaging/Makefile.in index 0aa0fc43a9b..049d9d7e0a3 100644 --- a/dlls/coremessaging/Makefile.in +++ b/dlls/coremessaging/Makefile.in @@ -1,4 +1,6 @@ -MODULE = coremessaging.dll +MODULE = coremessaging.dll +IMPORTS = combase
SOURCES = \ + classes.idl \ main.c diff --git a/dlls/coremessaging/classes.idl b/dlls/coremessaging/classes.idl new file mode 100644 index 00000000000..a7509d2a658 --- /dev/null +++ b/dlls/coremessaging/classes.idl @@ -0,0 +1,24 @@ +/* + * Runtime Classes for coremessaging.dll + * + * Copyright (C) 2025 Mohamad Al-Jaf + * + * 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 + +#define _CORE_MESSAGING +#include "windows.system.idl" diff --git a/dlls/coremessaging/coremessaging.spec b/dlls/coremessaging/coremessaging.spec index 58f2be2dc8e..fb98c802077 100644 --- a/dlls/coremessaging/coremessaging.spec +++ b/dlls/coremessaging/coremessaging.spec @@ -18,7 +18,7 @@ @ stdcall CreateDispatcherQueueController(long long long ptr) @ stub CreateDispatcherQueueForCurrentThread @ stdcall -private DllCanUnloadNow() -@ stub DllGetActivationFactory +@ stdcall -private DllGetActivationFactory(ptr ptr) @ stub DllGetClassObject @ stub GetDispatcherQueueForCurrentThread @ stub MsgBlobCreateShared diff --git a/dlls/coremessaging/main.c b/dlls/coremessaging/main.c index 4944f28a49a..5bb4a99ee57 100644 --- a/dlls/coremessaging/main.c +++ b/dlls/coremessaging/main.c @@ -17,11 +17,150 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
+#include "initguid.h" +#include "private.h" #include "dispatcherqueue.h" -#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(messaging);
+struct dispatcher_queue_controller_statics +{ + IActivationFactory IActivationFactory_iface; + IDispatcherQueueControllerStatics IDispatcherQueueControllerStatics_iface; + LONG ref; +}; + +static inline struct dispatcher_queue_controller_statics *impl_from_IActivationFactory( IActivationFactory *iface ) +{ + return CONTAINING_RECORD( iface, struct dispatcher_queue_controller_statics, IActivationFactory_iface ); +} + +static HRESULT WINAPI factory_QueryInterface( IActivationFactory *iface, REFIID iid, void **out ) +{ + struct dispatcher_queue_controller_statics *impl = 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 )) + { + *out = &impl->IActivationFactory_iface; + IInspectable_AddRef( *out ); + return S_OK; + } + + if (IsEqualGUID( iid, &IID_IDispatcherQueueControllerStatics )) + { + *out = &impl->IDispatcherQueueControllerStatics_iface; + IInspectable_AddRef( *out ); + return S_OK; + } + + FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI factory_AddRef( IActivationFactory *iface ) +{ + struct dispatcher_queue_controller_statics *impl = impl_from_IActivationFactory( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + TRACE( "iface %p increasing ref to %lu.\n", iface, ref ); + return ref; +} + +static ULONG WINAPI factory_Release( IActivationFactory *iface ) +{ + struct dispatcher_queue_controller_statics *impl = impl_from_IActivationFactory( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + TRACE( "iface %p decreasing ref to %lu.\n", iface, ref ); + return ref; +} + +static HRESULT WINAPI 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 WINAPI factory_GetRuntimeClassName( IActivationFactory *iface, HSTRING *class_name ) +{ + FIXME( "iface %p, class_name %p stub!\n", iface, class_name ); + return E_NOTIMPL; +} + +static HRESULT WINAPI factory_GetTrustLevel( IActivationFactory *iface, TrustLevel *trust_level ) +{ + FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level ); + return E_NOTIMPL; +} + +static HRESULT WINAPI factory_ActivateInstance( IActivationFactory *iface, IInspectable **instance ) +{ + FIXME( "iface %p, instance %p stub!\n", iface, instance ); + return E_NOTIMPL; +} + +static const struct IActivationFactoryVtbl factory_vtbl = +{ + factory_QueryInterface, + factory_AddRef, + factory_Release, + /* IInspectable methods */ + factory_GetIids, + factory_GetRuntimeClassName, + factory_GetTrustLevel, + /* IActivationFactory methods */ + factory_ActivateInstance, +}; + +DEFINE_IINSPECTABLE( dispatcher_queue_controller_statics, IDispatcherQueueControllerStatics, struct dispatcher_queue_controller_statics, IActivationFactory_iface ) + +static HRESULT WINAPI dispatcher_queue_controller_statics_CreateOnDedicatedThread( IDispatcherQueueControllerStatics *iface, IDispatcherQueueController **result ) +{ + FIXME( "iface %p, result %p stub!\n", iface, result ); + return E_NOTIMPL; +} + +static const struct IDispatcherQueueControllerStaticsVtbl dispatcher_queue_controller_statics_vtbl = +{ + dispatcher_queue_controller_statics_QueryInterface, + dispatcher_queue_controller_statics_AddRef, + dispatcher_queue_controller_statics_Release, + /* IInspectable methods */ + dispatcher_queue_controller_statics_GetIids, + dispatcher_queue_controller_statics_GetRuntimeClassName, + dispatcher_queue_controller_statics_GetTrustLevel, + /* IDispatcherQueueControllerStatics methods */ + dispatcher_queue_controller_statics_CreateOnDedicatedThread, +}; + +static struct dispatcher_queue_controller_statics dispatcher_queue_controller_statics = +{ + {&factory_vtbl}, + {&dispatcher_queue_controller_statics_vtbl}, + 1, +}; + +static IActivationFactory *dispatcher_queue_controller_factory = &dispatcher_queue_controller_statics.IActivationFactory_iface; + +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_DispatcherQueueController )) + IActivationFactory_QueryInterface( dispatcher_queue_controller_factory, &IID_IActivationFactory, (void **)factory ); + + if (*factory) return S_OK; + return CLASS_E_CLASSNOTAVAILABLE; +} + HRESULT WINAPI CreateDispatcherQueueController( DispatcherQueueOptions options, PDISPATCHERQUEUECONTROLLER *queue_controller ) { FIXME( "options.dwSize = %lu, options.threadType = %d, options.apartmentType = %d, queue_controller %p stub!\n", diff --git a/dlls/coremessaging/private.h b/dlls/coremessaging/private.h new file mode 100644 index 00000000000..9fb1c95e008 --- /dev/null +++ b/dlls/coremessaging/private.h @@ -0,0 +1,74 @@ +/* WinRT coremessaging.dll Implementation + * + * Copyright (C) 2025 Mohamad Al-Jaf + * + * 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> +#include <stddef.h> + +#define COBJMACROS +#include "windef.h" +#include "winbase.h" +#include "winstring.h" + +#include "activation.h" +#include "roapi.h" + +#include "wine/debug.h" + +#define WIDL_using_Windows_Foundation +#include "windows.foundation.h" +#define WIDL_using_Windows_System +#include "windows.system.h" + +#define DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from, iface_mem, expr ) \ + static inline impl_type *impl_from( iface_type *iface ) \ + { \ + return CONTAINING_RECORD( iface, impl_type, iface_mem ); \ + } \ + static HRESULT WINAPI pfx##_QueryInterface( iface_type *iface, REFIID iid, void **out ) \ + { \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_QueryInterface( (IInspectable *)(expr), iid, out ); \ + } \ + static ULONG WINAPI pfx##_AddRef( iface_type *iface ) \ + { \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_AddRef( (IInspectable *)(expr) ); \ + } \ + static ULONG WINAPI pfx##_Release( iface_type *iface ) \ + { \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_Release( (IInspectable *)(expr) ); \ + } \ + static HRESULT WINAPI pfx##_GetIids( iface_type *iface, ULONG *iid_count, IID **iids ) \ + { \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_GetIids( (IInspectable *)(expr), iid_count, iids ); \ + } \ + static HRESULT WINAPI pfx##_GetRuntimeClassName( iface_type *iface, HSTRING *class_name ) \ + { \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_GetRuntimeClassName( (IInspectable *)(expr), class_name ); \ + } \ + static HRESULT WINAPI pfx##_GetTrustLevel( iface_type *iface, TrustLevel *trust_level ) \ + { \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_GetTrustLevel( (IInspectable *)(expr), trust_level ); \ + } +#define DEFINE_IINSPECTABLE( pfx, iface_type, impl_type, base_iface ) \ + DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from_##iface_type, iface_type##_iface, &impl->base_iface ) diff --git a/dlls/coremessaging/tests/Makefile.in b/dlls/coremessaging/tests/Makefile.in new file mode 100644 index 00000000000..b048cbe204e --- /dev/null +++ b/dlls/coremessaging/tests/Makefile.in @@ -0,0 +1,5 @@ +TESTDLL = coremessaging.dll +IMPORTS = combase + +SOURCES = \ + coremessaging.c diff --git a/dlls/coremessaging/tests/coremessaging.c b/dlls/coremessaging/tests/coremessaging.c new file mode 100644 index 00000000000..83d00b6261f --- /dev/null +++ b/dlls/coremessaging/tests/coremessaging.c @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2025 Mohamad Al-Jaf + * + * 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 "initguid.h" +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" +#include "winstring.h" + +#include "roapi.h" + +#define WIDL_using_Windows_Foundation +#include "windows.foundation.h" +#define WIDL_using_Windows_System +#include "windows.system.h" + +#include "wine/test.h" + +#define check_interface( obj, iid ) check_interface_( __LINE__, obj, iid ) +static void check_interface_( unsigned int line, void *obj, const IID *iid ) +{ + IUnknown *iface = obj; + IUnknown *unk; + HRESULT hr; + + hr = IUnknown_QueryInterface( iface, iid, (void **)&unk ); + ok_(__FILE__, line)( hr == S_OK, "got hr %#lx.\n", hr ); + IUnknown_Release( unk ); +} + +static void test_DispatcherQueueController_Statics(void) +{ + static const WCHAR *dispatcher_queue_controller_statics_name = L"Windows.System.DispatcherQueueController"; + IDispatcherQueueControllerStatics *dispatcher_queue_controller_statics = (void *)0xdeadbeef; + IActivationFactory *factory = (void *)0xdeadbeef; + HSTRING str = NULL; + HRESULT hr; + LONG ref; + + hr = WindowsCreateString( dispatcher_queue_controller_statics_name, wcslen( dispatcher_queue_controller_statics_name ), &str ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + hr = RoGetActivationFactory( str, &IID_IActivationFactory, (void **)&factory ); + WindowsDeleteString( str ); + ok( hr == S_OK || broken(hr == REGDB_E_CLASSNOTREG), "got hr %#lx.\n", hr ); + if (hr == REGDB_E_CLASSNOTREG) + { + win_skip( "%s runtimeclass not registered, skipping tests.\n", wine_dbgstr_w( dispatcher_queue_controller_statics_name ) ); + return; + } + + check_interface( factory, &IID_IUnknown ); + check_interface( factory, &IID_IInspectable ); + check_interface( factory, &IID_IAgileObject ); + + hr = IActivationFactory_QueryInterface( factory, &IID_IDispatcherQueueControllerStatics, (void **)&dispatcher_queue_controller_statics ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + + ref = IDispatcherQueueControllerStatics_Release( dispatcher_queue_controller_statics ); + ok( ref == 2, "got ref %ld.\n", ref ); + ref = IActivationFactory_Release( factory ); + ok( ref == 1, "got ref %ld.\n", ref ); +} + +START_TEST(coremessaging) +{ + HRESULT hr; + + hr = RoInitialize( RO_INIT_MULTITHREADED ); + ok( hr == S_OK, "RoInitialize failed, hr %#lx\n", hr ); + + test_DispatcherQueueController_Statics(); + + RoUninitialize(); +} diff --git a/include/windows.system.idl b/include/windows.system.idl index 3a349edd4f8..152d4b6d901 100644 --- a/include/windows.system.idl +++ b/include/windows.system.idl @@ -462,6 +462,7 @@ namespace Windows.System [default] interface Windows.System.IDispatcherQueueTimer; }
+#ifndef _CORE_MESSAGING [ contract(Windows.Foundation.UniversalApiContract, 1.0), marshaling_behavior(agile), @@ -472,6 +473,7 @@ namespace Windows.System { [default] interface Windows.System.IUser; } +#endif
[ contract(Windows.Foundation.UniversalApiContract, 1.0),
From: Mohamad Al-Jaf mohamadaljaf@gmail.com
--- dlls/coremessaging/Makefile.in | 5 +- dlls/coremessaging/tests/Makefile.in | 2 +- dlls/coremessaging/tests/coremessaging.c | 269 +++++++++++++++++++++++ 3 files changed, 273 insertions(+), 3 deletions(-)
diff --git a/dlls/coremessaging/Makefile.in b/dlls/coremessaging/Makefile.in index 049d9d7e0a3..25de74385c5 100644 --- a/dlls/coremessaging/Makefile.in +++ b/dlls/coremessaging/Makefile.in @@ -1,5 +1,6 @@ -MODULE = coremessaging.dll -IMPORTS = combase +MODULE = coremessaging.dll +IMPORTS = combase +IMPORTLIB = coremessaging
SOURCES = \ classes.idl \ diff --git a/dlls/coremessaging/tests/Makefile.in b/dlls/coremessaging/tests/Makefile.in index b048cbe204e..c8947c28c50 100644 --- a/dlls/coremessaging/tests/Makefile.in +++ b/dlls/coremessaging/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = coremessaging.dll -IMPORTS = combase +IMPORTS = combase coremessaging user32
SOURCES = \ coremessaging.c diff --git a/dlls/coremessaging/tests/coremessaging.c b/dlls/coremessaging/tests/coremessaging.c index 83d00b6261f..a32bdf721b4 100644 --- a/dlls/coremessaging/tests/coremessaging.c +++ b/dlls/coremessaging/tests/coremessaging.c @@ -30,6 +30,8 @@ #define WIDL_using_Windows_System #include "windows.system.h"
+#include "dispatcherqueue.h" + #include "wine/test.h"
#define check_interface( obj, iid ) check_interface_( __LINE__, obj, iid ) @@ -44,14 +46,189 @@ static void check_interface_( unsigned int line, void *obj, const IID *iid ) IUnknown_Release( unk ); }
+struct typed_event_handler_dispatcher_queue +{ + ITypedEventHandler_DispatcherQueue_IInspectable ITypedEventHandler_DispatcherQueue_IInspectable_iface; + LONG ref; + + HANDLE event; +}; + +static struct typed_event_handler_dispatcher_queue *impl_from_ITypedEventHandler_DispatcherQueue_IInspectable( ITypedEventHandler_DispatcherQueue_IInspectable *iface ) +{ + return CONTAINING_RECORD( iface, struct typed_event_handler_dispatcher_queue, ITypedEventHandler_DispatcherQueue_IInspectable_iface ); +} + +static HRESULT WINAPI typed_event_handler_dispatcher_queue_QueryInterface( ITypedEventHandler_DispatcherQueue_IInspectable *iface, REFIID iid, void **out ) +{ + if (IsEqualGUID( iid, &IID_ITypedEventHandler_DispatcherQueue_IInspectable ) || + IsEqualGUID( iid, &IID_IAgileObject ) || + IsEqualGUID( iid, &IID_IInspectable ) || + IsEqualGUID( iid, &IID_IUnknown )) + { + *out = iface; + ITypedEventHandler_DispatcherQueue_IInspectable_AddRef( iface ); + return S_OK; + } + + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI typed_event_handler_dispatcher_queue_AddRef( ITypedEventHandler_DispatcherQueue_IInspectable *iface ) +{ + struct typed_event_handler_dispatcher_queue *handler = impl_from_ITypedEventHandler_DispatcherQueue_IInspectable( iface ); + return InterlockedIncrement( &handler->ref ); +} + +static ULONG WINAPI typed_event_handler_dispatcher_queue_Release( ITypedEventHandler_DispatcherQueue_IInspectable *iface ) +{ + struct typed_event_handler_dispatcher_queue *handler = impl_from_ITypedEventHandler_DispatcherQueue_IInspectable( iface ); + ULONG ref = InterlockedDecrement( &handler->ref ); + + if (!ref) + { + CloseHandle( handler->event ); + free( handler ); + } + + return ref; +} + +static HRESULT WINAPI typed_event_handler_dispatcher_queue_Invoke( ITypedEventHandler_DispatcherQueue_IInspectable *iface, IDispatcherQueue *queue, IInspectable *inspectable ) +{ + struct typed_event_handler_dispatcher_queue *handler = impl_from_ITypedEventHandler_DispatcherQueue_IInspectable( iface ); + + SetEvent( handler->event ); + return S_OK; +} + +static const ITypedEventHandler_DispatcherQueue_IInspectableVtbl typed_event_handler_dispatcher_queue_vtbl = +{ + typed_event_handler_dispatcher_queue_QueryInterface, + typed_event_handler_dispatcher_queue_AddRef, + typed_event_handler_dispatcher_queue_Release, + typed_event_handler_dispatcher_queue_Invoke, +}; + +static HRESULT create_typed_event_handler_dispatcher_queue( ITypedEventHandler_DispatcherQueue_IInspectable **handler ) +{ + struct typed_event_handler_dispatcher_queue *impl; + + *handler = NULL; + + if (!(impl = calloc( 1, sizeof( *impl ) ))) return E_OUTOFMEMORY; + + impl->ITypedEventHandler_DispatcherQueue_IInspectable_iface.lpVtbl = &typed_event_handler_dispatcher_queue_vtbl; + impl->ref = 1; + impl->event = CreateEventW( NULL, FALSE, FALSE, NULL ); + + *handler = &impl->ITypedEventHandler_DispatcherQueue_IInspectable_iface; + return S_OK; +} + +struct dispatcher_queue_handler +{ + IDispatcherQueueHandler IDispatcherQueueHandler_iface; + LONG ref; + + HANDLE event; +}; + +static struct dispatcher_queue_handler *impl_from_IDispatcherQueueHandler( IDispatcherQueueHandler *iface ) +{ + return CONTAINING_RECORD( iface, struct dispatcher_queue_handler, IDispatcherQueueHandler_iface ); +} + +static HRESULT WINAPI dispatcher_queue_handler_QueryInterface( IDispatcherQueueHandler *iface, REFIID iid, void **out ) +{ + if (IsEqualGUID( iid, &IID_IDispatcherQueueHandler ) || + IsEqualGUID( iid, &IID_IAgileObject ) || + IsEqualGUID( iid, &IID_IInspectable ) || + IsEqualGUID( iid, &IID_IUnknown )) + { + *out = iface; + IDispatcherQueueHandler_AddRef( iface ); + return S_OK; + } + + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI dispatcher_queue_handler_AddRef( IDispatcherQueueHandler *iface ) +{ + struct dispatcher_queue_handler *handler = impl_from_IDispatcherQueueHandler( iface ); + return InterlockedIncrement( &handler->ref ); +} + +static ULONG WINAPI dispatcher_queue_handler_Release( IDispatcherQueueHandler *iface ) +{ + struct dispatcher_queue_handler *handler = impl_from_IDispatcherQueueHandler( iface ); + ULONG ref = InterlockedDecrement( &handler->ref ); + + if (!ref) + { + CloseHandle( handler->event ); + free( handler ); + } + + return ref; +} + +static HRESULT WINAPI dispatcher_queue_handler_Invoke( IDispatcherQueueHandler *iface ) +{ + struct dispatcher_queue_handler *handler = impl_from_IDispatcherQueueHandler( iface ); + + SetEvent( handler->event ); + return S_OK; +} + +static const IDispatcherQueueHandlerVtbl dispatcher_queue_handler_vtbl = +{ + dispatcher_queue_handler_QueryInterface, + dispatcher_queue_handler_AddRef, + dispatcher_queue_handler_Release, + dispatcher_queue_handler_Invoke, +}; + +static HRESULT create_dispatcher_queue_handler( IDispatcherQueueHandler **handler ) +{ + struct dispatcher_queue_handler *impl; + + *handler = NULL; + + if (!(impl = calloc( 1, sizeof( *impl ) ))) return E_OUTOFMEMORY; + + impl->IDispatcherQueueHandler_iface.lpVtbl = &dispatcher_queue_handler_vtbl; + impl->ref = 1; + impl->event = CreateEventW( NULL, FALSE, FALSE, NULL ); + + *handler = &impl->IDispatcherQueueHandler_iface; + return S_OK; +} + static void test_DispatcherQueueController_Statics(void) { static const WCHAR *dispatcher_queue_controller_statics_name = L"Windows.System.DispatcherQueueController"; IDispatcherQueueControllerStatics *dispatcher_queue_controller_statics = (void *)0xdeadbeef; + ITypedEventHandler_DispatcherQueue_IInspectable *event_handler_iface = (void *)0xdeadbeef; + struct typed_event_handler_dispatcher_queue *event_handler = (void *)0xdeadbeef; + IDispatcherQueueController *dispatcher_queue_controller = (void *)0xdeadbeef; + IDispatcherQueueHandler *handler_iface = (void *)0xdeadbeef; + IDispatcherQueue2 *dispatcher_queue2 = (void *)0xdeadbeef; + IDispatcherQueue *dispatcher_queue = (void *)0xdeadbeef; IActivationFactory *factory = (void *)0xdeadbeef; + IAsyncAction *operation = (void *)0xdeadbeef; + IAsyncInfo *async_info = (void *)0xdeadbeef; + EventRegistrationToken token; + AsyncStatus status; HSTRING str = NULL; + boolean result; HRESULT hr; + DWORD ret; LONG ref; + MSG msg;
hr = WindowsCreateString( dispatcher_queue_controller_statics_name, wcslen( dispatcher_queue_controller_statics_name ), &str ); ok( hr == S_OK, "got hr %#lx.\n", hr ); @@ -71,6 +248,98 @@ static void test_DispatcherQueueController_Statics(void) hr = IActivationFactory_QueryInterface( factory, &IID_IDispatcherQueueControllerStatics, (void **)&dispatcher_queue_controller_statics ); ok( hr == S_OK, "got hr %#lx.\n", hr );
+ hr = IDispatcherQueueControllerStatics_CreateOnDedicatedThread( dispatcher_queue_controller_statics, NULL ); + todo_wine + ok( hr == E_POINTER || hr == 0x80000005 /* E_POINTER #if !defined(_WIN32) && defined(_MAC) */, "got hr %#lx.\n", hr ); + hr = IDispatcherQueueControllerStatics_CreateOnDedicatedThread( dispatcher_queue_controller_statics, &dispatcher_queue_controller ); + todo_wine + ok( hr == S_OK, "got hr %#lx.\n", hr ); + if (FAILED(hr)) goto done; + + hr = IDispatcherQueueController_get_DispatcherQueue( dispatcher_queue_controller, NULL ); + todo_wine + ok( hr == E_POINTER || hr == 0x80000005 /* E_POINTER #if !defined(_WIN32) && defined(_MAC) */, "got hr %#lx.\n", hr ); + hr = IDispatcherQueueController_get_DispatcherQueue( dispatcher_queue_controller, &dispatcher_queue ); + todo_wine + ok( hr == S_OK, "got hr %#lx.\n", hr ); + + check_interface( dispatcher_queue, &IID_IUnknown ); + check_interface( dispatcher_queue, &IID_IInspectable ); + check_interface( dispatcher_queue, &IID_IAgileObject ); + + hr = create_dispatcher_queue_handler( &handler_iface ); + ok( hr == S_OK, "Unexpected hr %#lx.\n", hr ); + + hr = IDispatcherQueue_TryEnqueue( dispatcher_queue, handler_iface, &result ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + ok( result == TRUE, "got result %d.\n", result ); + + hr = IDispatcherQueue_QueryInterface( dispatcher_queue, &IID_IDispatcherQueue2, (void **)&dispatcher_queue2 ); + ok( hr == S_OK || broken(hr == E_NOINTERFACE) /* w1064v1709 */, "got hr %#lx.\n", hr ); + if (SUCCEEDED(hr)) + { + hr = IDispatcherQueue2_get_HasThreadAccess( dispatcher_queue2, &result ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + ok( result == FALSE, "got result %d.\n", result ); + ref = IDispatcherQueue2_Release( dispatcher_queue2 ); + ok( ref == 3, "got ref %ld.\n", ref ); + } + + hr = create_typed_event_handler_dispatcher_queue( &event_handler_iface ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + event_handler = impl_from_ITypedEventHandler_DispatcherQueue_IInspectable( event_handler_iface ); + hr = IDispatcherQueue_add_ShutdownCompleted( dispatcher_queue, event_handler_iface, &token ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + + hr = IDispatcherQueueController_ShutdownQueueAsync( dispatcher_queue_controller, NULL ); + ok( hr == E_POINTER || hr == 0x80000005 /* E_POINTER #if #if !defined(_WIN32) && defined(_MAC) */, "got hr %#lx.\n", hr ); + hr = IDispatcherQueueController_ShutdownQueueAsync( dispatcher_queue_controller, &operation ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + + hr = IAsyncAction_QueryInterface( operation, &IID_IAsyncInfo, (void **)&async_info ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + + check_interface( operation, &IID_IAsyncAction ); + check_interface( operation, &IID_IAsyncInfo ); + check_interface( operation, &IID_IAgileObject ); + check_interface( operation, &IID_IInspectable ); + + hr = IAsyncInfo_get_Status( async_info, &status ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + ok( status == Started, "got status %d.\n", status ); + while (PeekMessageW( &msg, NULL, 0, 0, PM_REMOVE )) + { + TranslateMessage( &msg ); + DispatchMessageW( &msg ); + } + ret = WaitForSingleObject( event_handler->event, INFINITE ); + ok( !ret, "Unexpected wait result %lu.\n", ret ); + hr = IAsyncInfo_get_Status( async_info, &status ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + ok( status == Completed, "got status %d.\n", status ); + + hr = IAsyncInfo_Close( async_info ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + ref = IAsyncInfo_Release( async_info ); + ok( ref == 2, "got ref %ld.\n", ref ); + ref = IAsyncAction_Release( operation ); + ok( ref == 1, "got ref %ld.\n", ref ); + hr = IDispatcherQueue_remove_ShutdownCompleted( dispatcher_queue, token ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + + hr = IDispatcherQueue_TryEnqueue( dispatcher_queue, handler_iface, &result ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + ok( result == FALSE, "got result %d.\n", result ); + + ref = ITypedEventHandler_DispatcherQueue_IInspectable_Release( event_handler_iface ); + ok( ref == 0, "got ref %ld.\n", ref ); + ref = IDispatcherQueueHandler_Release( handler_iface ); + ok( ref == 0, "got ref %ld.\n", ref ); + ref = IDispatcherQueue_Release( dispatcher_queue ); + flaky ok( ref == 1, "got ref %ld.\n", ref ); + ref = IDispatcherQueueController_Release( dispatcher_queue_controller ); + flaky ok( ref == 0, "got ref %ld.\n", ref ); +done: ref = IDispatcherQueueControllerStatics_Release( dispatcher_queue_controller_statics ); ok( ref == 2, "got ref %ld.\n", ref ); ref = IActivationFactory_Release( factory );
From: Mohamad Al-Jaf mohamadaljaf@gmail.com
--- dlls/coremessaging/tests/coremessaging.c | 153 +++++++++++++++++++++++ 1 file changed, 153 insertions(+)
diff --git a/dlls/coremessaging/tests/coremessaging.c b/dlls/coremessaging/tests/coremessaging.c index a32bdf721b4..54f3fd5483d 100644 --- a/dlls/coremessaging/tests/coremessaging.c +++ b/dlls/coremessaging/tests/coremessaging.c @@ -208,6 +208,158 @@ static HRESULT create_dispatcher_queue_handler( IDispatcherQueueHandler **handle return S_OK; }
+#define check_create_dispatcher_queue_controller( size, thread_type, apartment_type, expected_hr ) \ + check_create_dispatcher_queue_controller_( __LINE__, size, thread_type, apartment_type, expected_hr ) +static void check_create_dispatcher_queue_controller_( unsigned int line, DWORD size, DISPATCHERQUEUE_THREAD_TYPE thread_type, \ + DISPATCHERQUEUE_THREAD_APARTMENTTYPE apartment_type, HRESULT expected_hr ) +{ + ITypedEventHandler_DispatcherQueue_IInspectable *event_handler_iface = NULL; + struct typed_event_handler_dispatcher_queue *event_handler = NULL; + IDispatcherQueueController *dispatcher_queue_controller = NULL; + IDispatcherQueueHandler *handler_iface = NULL; + IDispatcherQueue2 *dispatcher_queue2 = NULL; + IDispatcherQueue *dispatcher_queue = NULL; + struct DispatcherQueueOptions options; + IAsyncAction *operation = NULL; + IAsyncInfo *async_info = NULL; + EventRegistrationToken token; + AsyncStatus status; + boolean result; + HRESULT hr; + DWORD ret; + LONG ref; + MSG msg; + + memset( &options, 0, sizeof( options ) ); + options.dwSize = size; + options.threadType = thread_type; + options.apartmentType = apartment_type; + + hr = CreateDispatcherQueueController( options, &dispatcher_queue_controller ); + todo_wine + ok_(__FILE__, line)( hr == expected_hr, "got CreateDispatcherQueueController hr %#lx.\n", hr ); + if (FAILED(hr)) return; + + hr = IDispatcherQueueController_get_DispatcherQueue( dispatcher_queue_controller, &dispatcher_queue ); + todo_wine + ok_(__FILE__, line)( hr == S_OK, "got IDispatcherQueueController_get_DispatcherQueue hr %#lx.\n", hr ); + if (FAILED(hr)) goto done; + + hr = IDispatcherQueue_QueryInterface( dispatcher_queue, &IID_IDispatcherQueue2, (void **)&dispatcher_queue2 ); + ok_(__FILE__, line)( hr == S_OK || broken(hr == E_NOINTERFACE) /* w1064v1709 */, "got IDispatcherQueue_QueryInterface hr %#lx.\n", hr ); + if (SUCCEEDED(hr)) + { + hr = IDispatcherQueue2_get_HasThreadAccess( dispatcher_queue2, &result ); + ok_(__FILE__, line)( hr == S_OK, "got IDispatcherQueue2_get_HasThreadAccess hr %#lx.\n", hr ); + ok_(__FILE__, line)( result == (thread_type == DQTYPE_THREAD_CURRENT ? TRUE : FALSE), "got IDispatcherQueue2_get_HasThreadAccess result %d.\n", result ); + ref = IDispatcherQueue2_Release( dispatcher_queue2 ); + ok_(__FILE__, line)( ref == (thread_type == DQTYPE_THREAD_CURRENT ? 2 : 3), "got IDispatcherQueue2_Release ref %ld.\n", ref ); + } + + hr = create_dispatcher_queue_handler( &handler_iface ); + ok_(__FILE__, line)( hr == S_OK, "create_dispatcher_queue_handler failed, hr %#lx.\n", hr ); + + hr = IDispatcherQueue_TryEnqueue( dispatcher_queue, handler_iface, &result ); + ok_(__FILE__, line)( hr == S_OK, "got IDispatcherQueue_TryEnqueue hr %#lx.\n", hr ); + ok_(__FILE__, line)( result == TRUE, "got IDispatcherQueue_TryEnqueue result %d.\n", result ); + + hr = create_typed_event_handler_dispatcher_queue( &event_handler_iface ); + ok_(__FILE__, line)( hr == S_OK, "create_typed_event_handler_dispatcher_queue failed, hr %#lx.\n", hr ); + event_handler = impl_from_ITypedEventHandler_DispatcherQueue_IInspectable( event_handler_iface ); + + hr = IDispatcherQueue_add_ShutdownCompleted( dispatcher_queue, event_handler_iface, &token ); + ok_(__FILE__, line)( hr == S_OK, "got IDispatcherQueue_add_ShutdownCompleted hr %#lx.\n", hr ); + hr = IDispatcherQueueController_ShutdownQueueAsync( dispatcher_queue_controller, &operation ); + ok_(__FILE__, line)( hr == S_OK, "got IDispatcherQueueController_ShutdownQueueAsync hr %#lx.\n", hr ); + + hr = IAsyncAction_QueryInterface( operation, &IID_IAsyncInfo, (void **)&async_info ); + ok_(__FILE__, line)( hr == S_OK, "got IAsyncAction_QueryInterface hr %#lx.\n", hr ); + + hr = IAsyncInfo_get_Status( async_info, &status ); + ok_(__FILE__, line)( hr == S_OK, "got IAsyncInfo_get_Status hr %#lx.\n", hr ); + ok_(__FILE__, line)( status == Started, "got IAsyncInfo_get_Status status %d.\n", status ); + while (PeekMessageW( &msg, NULL, 0, 0, PM_REMOVE )) + { + TranslateMessage( &msg ); + DispatchMessageW( &msg ); + } + ret = WaitForSingleObject( event_handler->event, INFINITE ); + ok_(__FILE__, line)( !ret, "Unexpected wait result %lu.\n", ret ); + hr = IAsyncInfo_get_Status( async_info, &status ); + ok_(__FILE__, line)( hr == S_OK, "got IAsyncInfo_get_Status hr %#lx.\n", hr ); + flaky ok_(__FILE__, line)( status == Completed, "got IAsyncInfo_get_Status status %d.\n", status ); + + hr = IAsyncInfo_Close( async_info ); + ok_(__FILE__, line)( hr == S_OK, "got IAsyncInfo_Close hr %#lx.\n", hr ); + ref = IAsyncInfo_Release( async_info ); + ok_(__FILE__, line)( ref == 2, "got IAsyncInfo_Release ref %ld.\n", ref ); + ref = IAsyncAction_Release( operation ); + ok_(__FILE__, line)( ref == 1, "got IAsyncAction_Release ref %ld.\n", ref ); + hr = IDispatcherQueue_remove_ShutdownCompleted( dispatcher_queue, token ); + ok_(__FILE__, line)( hr == S_OK, "got IDispatcherQueue_remove_ShutdownCompleted hr %#lx.\n", hr ); + + ref = ITypedEventHandler_DispatcherQueue_IInspectable_Release( event_handler_iface ); + ok_(__FILE__, line)( ref == 0, "got ITypedEventHandler_DispatcherQueue_IInspectable_Release ref %ld.\n", ref ); + ref = IDispatcherQueueHandler_Release( handler_iface ); + ok_(__FILE__, line)( ref == 0, "got IDispatcherQueueHandler_Release ref %ld.\n", ref ); + ref = IDispatcherQueue_Release( dispatcher_queue ); + flaky ok_(__FILE__, line)( ref == 1, "got IDispatcherQueue_Release ref %ld.\n", ref ); +done: + ref = IDispatcherQueueController_Release( dispatcher_queue_controller ); + flaky ok_(__FILE__, line)( ref == 0, "got IDispatcherQueueController_Release ref %ld.\n", ref ); +} + +static void test_CreateDispatcherQueueController(void) +{ + IDispatcherQueueController *dispatcher_queue_controller = (void *)0xdeadbeef; + struct DispatcherQueueOptions options = {0}; + HRESULT hr; + + hr = CreateDispatcherQueueController( options, NULL ); + todo_wine + ok( hr == E_POINTER || hr == 0x80000005 /* E_POINTER #if !defined(_WIN32) && defined(_MAC) */, "got hr %#lx.\n", hr ); + hr = CreateDispatcherQueueController( options, &dispatcher_queue_controller ); + todo_wine + ok( hr == E_INVALIDARG, "got hr %#lx.\n", hr ); + ok( dispatcher_queue_controller == (void *)0xdeadbeef, "got dispatcher_queue_controller %p.\n", dispatcher_queue_controller ); + + /* Invalid args */ + + check_create_dispatcher_queue_controller( 0, 0, DQTAT_COM_NONE, E_INVALIDARG ); + check_create_dispatcher_queue_controller( 0, 0, DQTAT_COM_ASTA, E_INVALIDARG ); + check_create_dispatcher_queue_controller( 0, 0, DQTAT_COM_STA, E_INVALIDARG ); + check_create_dispatcher_queue_controller( 0, DQTYPE_THREAD_CURRENT, DQTAT_COM_NONE, E_INVALIDARG ); + check_create_dispatcher_queue_controller( 0, DQTYPE_THREAD_CURRENT, DQTAT_COM_ASTA, E_INVALIDARG ); + check_create_dispatcher_queue_controller( 0, DQTYPE_THREAD_CURRENT, DQTAT_COM_STA, E_INVALIDARG ); + check_create_dispatcher_queue_controller( 0, DQTYPE_THREAD_DEDICATED, DQTAT_COM_NONE, E_INVALIDARG ); + check_create_dispatcher_queue_controller( 0, DQTYPE_THREAD_DEDICATED, DQTAT_COM_ASTA, E_INVALIDARG ); + check_create_dispatcher_queue_controller( 0, DQTYPE_THREAD_DEDICATED, DQTAT_COM_STA, E_INVALIDARG ); + check_create_dispatcher_queue_controller( sizeof( DispatcherQueueOptions ), 0, DQTAT_COM_NONE, E_INVALIDARG ); + check_create_dispatcher_queue_controller( sizeof( DispatcherQueueOptions ), 0, DQTAT_COM_ASTA, E_INVALIDARG ); + check_create_dispatcher_queue_controller( sizeof( DispatcherQueueOptions ), 0, DQTAT_COM_STA, E_INVALIDARG ); + check_create_dispatcher_queue_controller( sizeof( DispatcherQueueOptions ), 0xdeadbeef, DQTAT_COM_NONE, E_INVALIDARG ); + check_create_dispatcher_queue_controller( sizeof( DispatcherQueueOptions ), 0xdeadbeef, DQTAT_COM_ASTA, E_INVALIDARG ); + check_create_dispatcher_queue_controller( sizeof( DispatcherQueueOptions ), 0xdeadbeef, DQTAT_COM_STA, E_INVALIDARG ); + check_create_dispatcher_queue_controller( sizeof( DispatcherQueueOptions ) - 1, DQTYPE_THREAD_CURRENT, DQTAT_COM_NONE, E_INVALIDARG ); + check_create_dispatcher_queue_controller( sizeof( DispatcherQueueOptions ) + 1, DQTYPE_THREAD_CURRENT, DQTAT_COM_NONE, E_INVALIDARG ); + + if (0) /* Silently crashes in Windows */ + { + check_create_dispatcher_queue_controller( sizeof( DispatcherQueueOptions ), DQTYPE_THREAD_DEDICATED, 0xdeadbeef, S_OK ); + check_create_dispatcher_queue_controller( sizeof( DispatcherQueueOptions ), DQTYPE_THREAD_DEDICATED, DQTAT_COM_NONE, S_OK ); + } + + /* Valid args */ + + check_create_dispatcher_queue_controller( sizeof( DispatcherQueueOptions ), DQTYPE_THREAD_CURRENT, 0xdeadbeef, S_OK ); + check_create_dispatcher_queue_controller( sizeof( DispatcherQueueOptions ), DQTYPE_THREAD_CURRENT, DQTAT_COM_NONE, S_OK ); + check_create_dispatcher_queue_controller( sizeof( DispatcherQueueOptions ), DQTYPE_THREAD_CURRENT, DQTAT_COM_ASTA, S_OK ); + check_create_dispatcher_queue_controller( sizeof( DispatcherQueueOptions ), DQTYPE_THREAD_CURRENT, DQTAT_COM_STA, S_OK ); + + check_create_dispatcher_queue_controller( sizeof( DispatcherQueueOptions ), DQTYPE_THREAD_DEDICATED, DQTAT_COM_ASTA, S_OK ); + check_create_dispatcher_queue_controller( sizeof( DispatcherQueueOptions ), DQTYPE_THREAD_DEDICATED, DQTAT_COM_STA, S_OK ); +} + static void test_DispatcherQueueController_Statics(void) { static const WCHAR *dispatcher_queue_controller_statics_name = L"Windows.System.DispatcherQueueController"; @@ -354,6 +506,7 @@ START_TEST(coremessaging) ok( hr == S_OK, "RoInitialize failed, hr %#lx\n", hr );
test_DispatcherQueueController_Statics(); + test_CreateDispatcherQueueController();
RoUninitialize(); }
From: Mohamad Al-Jaf mohamadaljaf@gmail.com
Needed by Paint.NET. --- dlls/coremessaging/main.c | 301 ++++++++++++++++++++++- dlls/coremessaging/tests/coremessaging.c | 5 +- 2 files changed, 300 insertions(+), 6 deletions(-)
diff --git a/dlls/coremessaging/main.c b/dlls/coremessaging/main.c index 5bb4a99ee57..f4d9c889fa8 100644 --- a/dlls/coremessaging/main.c +++ b/dlls/coremessaging/main.c @@ -116,6 +116,290 @@ static const struct IActivationFactoryVtbl factory_vtbl = factory_ActivateInstance, };
+struct async_action +{ + IAsyncAction IAsyncAction_iface; + IAsyncInfo IAsyncInfo_iface; + LONG ref; +}; + +static inline struct async_action *impl_from_IAsyncAction( IAsyncAction *iface ) +{ + return CONTAINING_RECORD( iface, struct async_action, IAsyncAction_iface ); +} + +static HRESULT WINAPI async_action_QueryInterface( IAsyncAction *iface, REFIID iid, void **out ) +{ + struct async_action *impl = impl_from_IAsyncAction( 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_IAsyncAction )) + { + *out = &impl->IAsyncAction_iface; + IInspectable_AddRef( *out ); + return S_OK; + } + + if (IsEqualGUID( iid, &IID_IAsyncInfo )) + { + *out = &impl->IAsyncInfo_iface; + IInspectable_AddRef( *out ); + return S_OK; + } + + FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI async_action_AddRef( IAsyncAction *iface ) +{ + struct async_action *impl = impl_from_IAsyncAction( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + TRACE( "iface %p, ref %lu.\n", iface, ref ); + return ref; +} + +static ULONG WINAPI async_action_Release( IAsyncAction *iface ) +{ + struct async_action *impl = impl_from_IAsyncAction( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + + TRACE( "iface %p, ref %lu.\n", iface, ref ); + + if (!ref) free( impl ); + return ref; +} + +static HRESULT WINAPI 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 WINAPI async_action_GetRuntimeClassName( IAsyncAction *iface, HSTRING *class_name ) +{ + FIXME( "iface %p, class_name %p stub!\n", iface, class_name ); + return E_NOTIMPL; +} + +static HRESULT WINAPI async_action_GetTrustLevel( IAsyncAction *iface, TrustLevel *trust_level ) +{ + FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level ); + return E_NOTIMPL; +} + +static HRESULT WINAPI async_action_put_Completed( IAsyncAction *iface, IAsyncActionCompletedHandler *handler ) +{ + FIXME( "iface %p, handler %p stub!\n", iface, handler ); + return E_NOTIMPL; +} + +static HRESULT WINAPI async_action_get_Completed( IAsyncAction *iface, IAsyncActionCompletedHandler **handler ) +{ + FIXME( "iface %p, handler %p stub!\n", iface, handler ); + return E_NOTIMPL; +} + +static HRESULT WINAPI 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, + /* IInspectable methods */ + async_action_GetIids, + async_action_GetRuntimeClassName, + async_action_GetTrustLevel, + /* IAsyncAction methods */ + async_action_put_Completed, + async_action_get_Completed, + async_action_GetResults, +}; + +DEFINE_IINSPECTABLE( async_info, IAsyncInfo, struct async_action, IAsyncAction_iface ) + +static HRESULT WINAPI async_info_get_Id( IAsyncInfo *iface, UINT32 *id ) +{ + FIXME( "iface %p, id %p stub!\n", iface, id ); + return E_NOTIMPL; +} + +static HRESULT WINAPI async_info_get_Status( IAsyncInfo *iface, AsyncStatus *status ) +{ + FIXME( "iface %p, status %p stub!\n", iface, status ); + return E_NOTIMPL; +} + +static HRESULT WINAPI 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 WINAPI async_info_Cancel( IAsyncInfo *iface ) +{ + FIXME( "iface %p stub!\n", iface ); + return E_NOTIMPL; +} + +static HRESULT WINAPI 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, + /* IInspectable methods */ + async_info_GetIids, + async_info_GetRuntimeClassName, + async_info_GetTrustLevel, + /* IAsyncInfo methods */ + async_info_get_Id, + async_info_get_Status, + async_info_get_ErrorCode, + async_info_Cancel, + async_info_Close, +}; + +static HRESULT async_action_create( IAsyncAction **out ) +{ + struct async_action *impl; + + *out = NULL; + + if (!(impl = calloc( 1, sizeof( *impl ) ))) return E_OUTOFMEMORY; + + impl->IAsyncAction_iface.lpVtbl = &async_action_vtbl; + impl->IAsyncInfo_iface.lpVtbl = &async_info_vtbl; + impl->ref = 1; + + *out = &impl->IAsyncAction_iface; + return S_OK; +} + +struct dispatcher_queue_controller +{ + IDispatcherQueueController IDispatcherQueueController_iface; + LONG ref; + + IAsyncAction *action; +}; + +static inline struct dispatcher_queue_controller *impl_from_IDispatcherQueueController( IDispatcherQueueController *iface ) +{ + return CONTAINING_RECORD( iface, struct dispatcher_queue_controller, IDispatcherQueueController_iface ); +} + +static HRESULT WINAPI dispatcher_queue_controller_QueryInterface( IDispatcherQueueController *iface, REFIID iid, void **out ) +{ + struct dispatcher_queue_controller *impl = impl_from_IDispatcherQueueController( 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_IDispatcherQueueController )) + { + *out = &impl->IDispatcherQueueController_iface; + IInspectable_AddRef( *out ); + return S_OK; + } + + FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI dispatcher_queue_controller_AddRef( IDispatcherQueueController *iface ) +{ + struct dispatcher_queue_controller *impl = impl_from_IDispatcherQueueController( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + TRACE( "iface %p increasing ref to %lu.\n", iface, ref ); + return ref; +} + +static ULONG WINAPI dispatcher_queue_controller_Release( IDispatcherQueueController *iface ) +{ + struct dispatcher_queue_controller *impl = impl_from_IDispatcherQueueController( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + + TRACE( "iface %p decreasing ref to %lu.\n", iface, ref ); + + if (!ref) free( impl ); + return ref; +} + +static HRESULT WINAPI dispatcher_queue_controller_GetIids( IDispatcherQueueController *iface, ULONG *iid_count, IID **iids ) +{ + FIXME( "iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids ); + return E_NOTIMPL; +} + +static HRESULT WINAPI dispatcher_queue_controller_GetRuntimeClassName( IDispatcherQueueController *iface, HSTRING *class_name ) +{ + FIXME( "iface %p, class_name %p stub!\n", iface, class_name ); + return E_NOTIMPL; +} + +static HRESULT WINAPI dispatcher_queue_controller_GetTrustLevel( IDispatcherQueueController *iface, TrustLevel *trust_level ) +{ + FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level ); + return E_NOTIMPL; +} + +static HRESULT WINAPI dispatcher_queue_controller_get_DispatcherQueue( IDispatcherQueueController *iface, IDispatcherQueue **value ) +{ + FIXME( "iface %p, value %p stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI dispatcher_queue_controller_ShutdownQueueAsync( IDispatcherQueueController *iface, IAsyncAction **operation ) +{ + struct dispatcher_queue_controller *impl = impl_from_IDispatcherQueueController( iface ); + HRESULT hr; + + FIXME( "iface %p, operation %p stub!\n", iface, operation ); + + if (!operation) return E_POINTER; + if (FAILED(hr = async_action_create( &impl->action ))) + { + *operation = NULL; + return hr; + } + + *operation = impl->action; + return S_OK; +} + +static const struct IDispatcherQueueControllerVtbl dispatcher_queue_controller_vtbl = +{ + dispatcher_queue_controller_QueryInterface, + dispatcher_queue_controller_AddRef, + dispatcher_queue_controller_Release, + /* IInspectable methods */ + dispatcher_queue_controller_GetIids, + dispatcher_queue_controller_GetRuntimeClassName, + dispatcher_queue_controller_GetTrustLevel, + /* IDispatcherQueueController methods */ + dispatcher_queue_controller_get_DispatcherQueue, + dispatcher_queue_controller_ShutdownQueueAsync, +}; + DEFINE_IINSPECTABLE( dispatcher_queue_controller_statics, IDispatcherQueueControllerStatics, struct dispatcher_queue_controller_statics, IActivationFactory_iface )
static HRESULT WINAPI dispatcher_queue_controller_statics_CreateOnDedicatedThread( IDispatcherQueueControllerStatics *iface, IDispatcherQueueController **result ) @@ -163,7 +447,20 @@ HRESULT WINAPI DllGetActivationFactory( HSTRING classid, IActivationFactory **fa
HRESULT WINAPI CreateDispatcherQueueController( DispatcherQueueOptions options, PDISPATCHERQUEUECONTROLLER *queue_controller ) { - FIXME( "options.dwSize = %lu, options.threadType = %d, options.apartmentType = %d, queue_controller %p stub!\n", + struct dispatcher_queue_controller *impl; + + FIXME( "options.dwSize = %lu, options.threadType = %d, options.apartmentType = %d, queue_controller %p semi-stub!\n", options.dwSize, options.threadType, options.apartmentType, queue_controller ); - return E_NOTIMPL; + + if (!queue_controller) return E_POINTER; + if (options.dwSize != sizeof( DispatcherQueueOptions )) return E_INVALIDARG; + if (options.threadType != DQTYPE_THREAD_DEDICATED && options.threadType != DQTYPE_THREAD_CURRENT) return E_INVALIDARG; + if (!(impl = calloc( 1, sizeof( *impl ) ))) return E_OUTOFMEMORY; + + impl->IDispatcherQueueController_iface.lpVtbl = &dispatcher_queue_controller_vtbl; + impl->ref = 1; + + *queue_controller = &impl->IDispatcherQueueController_iface; + TRACE( "created IDispatcherQueueController %p.\n", *queue_controller ); + return S_OK; } diff --git a/dlls/coremessaging/tests/coremessaging.c b/dlls/coremessaging/tests/coremessaging.c index 54f3fd5483d..07c24892c3b 100644 --- a/dlls/coremessaging/tests/coremessaging.c +++ b/dlls/coremessaging/tests/coremessaging.c @@ -236,9 +236,8 @@ static void check_create_dispatcher_queue_controller_( unsigned int line, DWORD options.apartmentType = apartment_type;
hr = CreateDispatcherQueueController( options, &dispatcher_queue_controller ); - todo_wine ok_(__FILE__, line)( hr == expected_hr, "got CreateDispatcherQueueController hr %#lx.\n", hr ); - if (FAILED(hr)) return; + if (hr == E_INVALIDARG) return;
hr = IDispatcherQueueController_get_DispatcherQueue( dispatcher_queue_controller, &dispatcher_queue ); todo_wine @@ -316,10 +315,8 @@ static void test_CreateDispatcherQueueController(void) HRESULT hr;
hr = CreateDispatcherQueueController( options, NULL ); - todo_wine ok( hr == E_POINTER || hr == 0x80000005 /* E_POINTER #if !defined(_WIN32) && defined(_MAC) */, "got hr %#lx.\n", hr ); hr = CreateDispatcherQueueController( options, &dispatcher_queue_controller ); - todo_wine ok( hr == E_INVALIDARG, "got hr %#lx.\n", hr ); ok( dispatcher_queue_controller == (void *)0xdeadbeef, "got dispatcher_queue_controller %p.\n", dispatcher_queue_controller );
**v2** - Mark some tests as flaky
Rémi Bernon (@rbernon) commented about dlls/coremessaging/main.c:
factory_ActivateInstance,
};
+struct async_action +{
- IAsyncAction IAsyncAction_iface;
- IAsyncInfo IAsyncInfo_iface;
- LONG ref;
+};
Can we reuse `async.c` from `windows.gaming.input` or some other WinRT DLL? I can see that this apparently let us control the thread the asyncs are executed on (to the contrary to our current async implementation which always uses the thread pool) but maybe it doesn't really matter for now?
Rémi Bernon (@rbernon) commented about dlls/coremessaging/tests/coremessaging.c:
- hr = IAsyncAction_QueryInterface( operation, &IID_IAsyncInfo, (void **)&async_info );
- ok_(__FILE__, line)( hr == S_OK, "got IAsyncAction_QueryInterface hr %#lx.\n", hr );
- hr = IAsyncInfo_get_Status( async_info, &status );
- ok_(__FILE__, line)( hr == S_OK, "got IAsyncInfo_get_Status hr %#lx.\n", hr );
- ok_(__FILE__, line)( status == Started, "got IAsyncInfo_get_Status status %d.\n", status );
- while (PeekMessageW( &msg, NULL, 0, 0, PM_REMOVE ))
- {
TranslateMessage( &msg );
DispatchMessageW( &msg );
- }
- ret = WaitForSingleObject( event_handler->event, INFINITE );
- ok_(__FILE__, line)( !ret, "Unexpected wait result %lu.\n", ret );
- hr = IAsyncInfo_get_Status( async_info, &status );
- ok_(__FILE__, line)( hr == S_OK, "got IAsyncInfo_get_Status hr %#lx.\n", hr );
- flaky ok_(__FILE__, line)( status == Completed, "got IAsyncInfo_get_Status status %d.\n", status );
I don't think we want to introduce new flaky tests, it's meant to workaround existing tests that are difficult to stabilize but it's always preferable to either make the test pass reliably, or, maybe, not test the behavior if it's too difficult.