Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
This should greatly reduce the burden of implementing WinRT classes.
None of the WinRT interfaces are using inheritance, and classes very often implement several interfaces, all deriving from IInspectable, and even if a v2 interface only adds a single method, it doesn't derive from the v1, and instead requires to reimplement the IInspectable methods and forward them to the default interface.
In addition, it looks like they also used COM aggregation extensively, and in these cases the forward has to be done to an outer IInspectable pointer.
include/inspectable.idl | 44 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+)
diff --git a/include/inspectable.idl b/include/inspectable.idl index 847d21da608..8b233e3da94 100644 --- a/include/inspectable.idl +++ b/include/inspectable.idl @@ -39,3 +39,47 @@ interface IInspectable : IUnknown }
typedef [unique] IInspectable *LPINSPECTABLE; + +cpp_quote("#ifdef __WINESRC__") +cpp_quote("#define DEFINE_IINSPECTABLE_EXPR( pfx, iface_type, impl_type, impl_from, iface_mem, expr ) \") +cpp_quote(" static inline impl_type *impl_from( iface_type *iface ) \") +cpp_quote(" { \") +cpp_quote(" return CONTAINING_RECORD( iface, impl_type, iface_mem ); \") +cpp_quote(" } \") +cpp_quote(" static HRESULT WINAPI pfx##_QueryInterface( iface_type *iface, REFIID iid, void **out ) \") +cpp_quote(" { \") +cpp_quote(" return IInspectable_QueryInterface( (IInspectable *)(expr), iid, out ); \") +cpp_quote(" } \") +cpp_quote(" static ULONG WINAPI pfx##_AddRef( iface_type *iface ) \") +cpp_quote(" { \") +cpp_quote(" return IInspectable_AddRef( (IInspectable *)(expr) ); \") +cpp_quote(" } \") +cpp_quote(" static ULONG WINAPI pfx##_Release( iface_type *iface ) \") +cpp_quote(" { \") +cpp_quote(" return IInspectable_Release( (IInspectable *)(expr) ); \") +cpp_quote(" } \") +cpp_quote(" static HRESULT WINAPI pfx##_GetIids( iface_type *iface, ULONG *iid_count, IID **iids ) \") +cpp_quote(" { \") +cpp_quote(" return IInspectable_GetIids( (IInspectable *)(expr), iid_count, iids ); \") +cpp_quote(" } \") +cpp_quote(" static HRESULT WINAPI pfx##_GetRuntimeClassName( iface_type *iface, HSTRING *class_name ) \") +cpp_quote(" { \") +cpp_quote(" return IInspectable_GetRuntimeClassName( (IInspectable *)(expr), class_name ); \") +cpp_quote(" } \") +cpp_quote(" static HRESULT WINAPI pfx##_GetTrustLevel( iface_type *iface, TrustLevel *trust_level ) \") +cpp_quote(" { \") +cpp_quote(" return IInspectable_GetTrustLevel( (IInspectable *)(expr), trust_level ); \") +cpp_quote(" }") +cpp_quote("#define DEFINE_IINSPECTABLE_OUTER_PFX( pfx, impl_pfx, iface_type, impl_type, outer ) \") +cpp_quote(" DEFINE_IINSPECTABLE_EXPR( pfx, iface_type, impl_type, impl_pfx##_from_##iface_type, \") +cpp_quote(" iface_type##_iface, impl_pfx##_from_##iface_type( iface )->outer )") +cpp_quote("#define DEFINE_IINSPECTABLE_OUTER( pfx, iface_type, impl_type, outer ) \") +cpp_quote(" DEFINE_IINSPECTABLE_EXPR( pfx, iface_type, impl_type, impl_from_##iface_type, \") +cpp_quote(" iface_type##_iface, impl_from_##iface_type( iface )->outer )") +cpp_quote("#define DEFINE_IINSPECTABLE_PFX( pfx, impl_pfx, iface_type, impl_type, member ) \") +cpp_quote(" DEFINE_IINSPECTABLE_EXPR( pfx, iface_type, impl_type, impl_pfx##_from_##iface_type, \") +cpp_quote(" iface_type##_iface, &impl_pfx##_from_##iface_type( iface )->member )") +cpp_quote("#define DEFINE_IINSPECTABLE( pfx, iface_type, impl_type, member ) \") +cpp_quote(" DEFINE_IINSPECTABLE_EXPR( pfx, iface_type, impl_type, impl_from_##iface_type, \") +cpp_quote(" iface_type##_iface, &impl_from_##iface_type( iface )->member )") +cpp_quote("#endif")
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/windows.gaming.input/controller.c | 41 +------------------------- dlls/windows.gaming.input/gamepad.c | 41 +------------------------- 2 files changed, 2 insertions(+), 80 deletions(-)
diff --git a/dlls/windows.gaming.input/controller.c b/dlls/windows.gaming.input/controller.c index 00ab9c5d91c..654d0795eac 100644 --- a/dlls/windows.gaming.input/controller.c +++ b/dlls/windows.gaming.input/controller.c @@ -35,11 +35,6 @@ static inline struct controller_statics *impl_from_IActivationFactory( IActivati return CONTAINING_RECORD( iface, struct controller_statics, IActivationFactory_iface ); }
-static inline struct controller_statics *impl_from_IRawGameControllerStatics( IRawGameControllerStatics *iface ) -{ - return CONTAINING_RECORD( iface, struct controller_statics, IRawGameControllerStatics_iface ); -} - static HRESULT WINAPI factory_QueryInterface( IActivationFactory *iface, REFIID iid, void **out ) { struct controller_statics *impl = impl_from_IActivationFactory( iface ); @@ -121,41 +116,7 @@ static const struct IActivationFactoryVtbl factory_vtbl = factory_ActivateInstance, };
-static HRESULT WINAPI statics_QueryInterface( IRawGameControllerStatics *iface, REFIID iid, void **out ) -{ - struct controller_statics *impl = impl_from_IRawGameControllerStatics( iface ); - return IActivationFactory_QueryInterface( &impl->IActivationFactory_iface, iid, out ); -} - -static ULONG WINAPI statics_AddRef( IRawGameControllerStatics *iface ) -{ - struct controller_statics *impl = impl_from_IRawGameControllerStatics( iface ); - return IActivationFactory_AddRef( &impl->IActivationFactory_iface ); -} - -static ULONG WINAPI statics_Release( IRawGameControllerStatics *iface ) -{ - struct controller_statics *impl = impl_from_IRawGameControllerStatics( iface ); - return IActivationFactory_Release( &impl->IActivationFactory_iface ); -} - -static HRESULT WINAPI statics_GetIids( IRawGameControllerStatics *iface, ULONG *iid_count, IID **iids ) -{ - struct controller_statics *impl = impl_from_IRawGameControllerStatics( iface ); - return IActivationFactory_Release( &impl->IActivationFactory_iface ); -} - -static HRESULT WINAPI statics_GetRuntimeClassName( IRawGameControllerStatics *iface, HSTRING *class_name ) -{ - struct controller_statics *impl = impl_from_IRawGameControllerStatics( iface ); - return IActivationFactory_Release( &impl->IActivationFactory_iface ); -} - -static HRESULT WINAPI statics_GetTrustLevel( IRawGameControllerStatics *iface, TrustLevel *trust_level ) -{ - struct controller_statics *impl = impl_from_IRawGameControllerStatics( iface ); - return IActivationFactory_Release( &impl->IActivationFactory_iface ); -} +DEFINE_IINSPECTABLE( statics, IRawGameControllerStatics, struct controller_statics, IActivationFactory_iface )
static HRESULT WINAPI statics_add_RawGameControllerAdded( IRawGameControllerStatics *iface, IEventHandler_RawGameController *value, EventRegistrationToken *token ) diff --git a/dlls/windows.gaming.input/gamepad.c b/dlls/windows.gaming.input/gamepad.c index e69568e2fb1..231e923b5e8 100644 --- a/dlls/windows.gaming.input/gamepad.c +++ b/dlls/windows.gaming.input/gamepad.c @@ -35,11 +35,6 @@ static inline struct gamepad_statics *impl_from_IActivationFactory( IActivationF return CONTAINING_RECORD( iface, struct gamepad_statics, IActivationFactory_iface ); }
-static inline struct gamepad_statics *impl_from_IGamepadStatics( IGamepadStatics *iface ) -{ - return CONTAINING_RECORD( iface, struct gamepad_statics, IGamepadStatics_iface ); -} - static HRESULT WINAPI factory_QueryInterface( IActivationFactory *iface, REFIID iid, void **out ) { struct gamepad_statics *impl = impl_from_IActivationFactory( iface ); @@ -121,41 +116,7 @@ static const struct IActivationFactoryVtbl factory_vtbl = factory_ActivateInstance, };
-static HRESULT WINAPI statics_QueryInterface( IGamepadStatics *iface, REFIID iid, void **out ) -{ - struct gamepad_statics *impl = impl_from_IGamepadStatics( iface ); - return IActivationFactory_QueryInterface( &impl->IActivationFactory_iface, iid, out ); -} - -static ULONG WINAPI statics_AddRef( IGamepadStatics *iface ) -{ - struct gamepad_statics *impl = impl_from_IGamepadStatics( iface ); - return IActivationFactory_AddRef( &impl->IActivationFactory_iface ); -} - -static ULONG WINAPI statics_Release( IGamepadStatics *iface ) -{ - struct gamepad_statics *impl = impl_from_IGamepadStatics( iface ); - return IActivationFactory_Release( &impl->IActivationFactory_iface ); -} - -static HRESULT WINAPI statics_GetIids( IGamepadStatics *iface, ULONG *iid_count, IID **iids ) -{ - struct gamepad_statics *impl = impl_from_IGamepadStatics( iface ); - return IActivationFactory_Release( &impl->IActivationFactory_iface ); -} - -static HRESULT WINAPI statics_GetRuntimeClassName( IGamepadStatics *iface, HSTRING *class_name ) -{ - struct gamepad_statics *impl = impl_from_IGamepadStatics( iface ); - return IActivationFactory_Release( &impl->IActivationFactory_iface ); -} - -static HRESULT WINAPI statics_GetTrustLevel( IGamepadStatics *iface, TrustLevel *trust_level ) -{ - struct gamepad_statics *impl = impl_from_IGamepadStatics( iface ); - return IActivationFactory_Release( &impl->IActivationFactory_iface ); -} +DEFINE_IINSPECTABLE( statics, IGamepadStatics, struct gamepad_statics, IActivationFactory_iface )
static HRESULT WINAPI statics_add_GamepadAdded( IGamepadStatics *iface, IEventHandler_Gamepad *value, EventRegistrationToken *token )
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/windows.gaming.input/Makefile.in | 1 + dlls/windows.gaming.input/main.c | 2 + dlls/windows.gaming.input/manager.c | 201 ++++++++++++++++++++++++++ dlls/windows.gaming.input/private.h | 4 +- 4 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 dlls/windows.gaming.input/manager.c
diff --git a/dlls/windows.gaming.input/Makefile.in b/dlls/windows.gaming.input/Makefile.in index 5031e72f08d..d7f93283bec 100644 --- a/dlls/windows.gaming.input/Makefile.in +++ b/dlls/windows.gaming.input/Makefile.in @@ -5,6 +5,7 @@ C_SRCS = \ controller.c \ gamepad.c \ main.c \ + manager.c \ vector.c
IDL_SRCS = classes.idl diff --git a/dlls/windows.gaming.input/main.c b/dlls/windows.gaming.input/main.c index aac21a0c33c..c050d1d5113 100644 --- a/dlls/windows.gaming.input/main.c +++ b/dlls/windows.gaming.input/main.c @@ -49,6 +49,8 @@ HRESULT WINAPI DllGetActivationFactory( HSTRING class_str, IActivationFactory ** IActivationFactory_AddRef( (*factory = controller_factory) ); if (!wcscmp( buffer, RuntimeClass_Windows_Gaming_Input_Gamepad )) IActivationFactory_AddRef( (*factory = gamepad_factory) ); + if (!wcscmp( buffer, RuntimeClass_Windows_Gaming_Input_Custom_GameControllerFactoryManager )) + IActivationFactory_AddRef( (*factory = manager_factory) );
if (*factory) return S_OK; return REGDB_E_CLASSNOTREG; diff --git a/dlls/windows.gaming.input/manager.c b/dlls/windows.gaming.input/manager.c new file mode 100644 index 00000000000..04f166b036f --- /dev/null +++ b/dlls/windows.gaming.input/manager.c @@ -0,0 +1,201 @@ +/* WinRT Windows.Gaming.Input implementation + * + * Copyright 2021 Rémi Bernon for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "private.h" + +#include "wine/debug.h" +#include "wine/list.h" + +WINE_DEFAULT_DEBUG_CHANNEL(input); + +struct manager_statics +{ + IActivationFactory IActivationFactory_iface; + IGameControllerFactoryManagerStatics IGameControllerFactoryManagerStatics_iface; + IGameControllerFactoryManagerStatics2 IGameControllerFactoryManagerStatics2_iface; + LONG ref; +}; + +static inline struct manager_statics *impl_from_IActivationFactory( IActivationFactory *iface ) +{ + return CONTAINING_RECORD( iface, struct manager_statics, IActivationFactory_iface ); +} + +static HRESULT WINAPI factory_QueryInterface( IActivationFactory *iface, REFIID iid, void **out ) +{ + struct manager_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 )) + { + IInspectable_AddRef( (*out = &impl->IActivationFactory_iface) ); + return S_OK; + } + + if (IsEqualGUID( iid, &IID_IGameControllerFactoryManagerStatics )) + { + IInspectable_AddRef( (*out = &impl->IGameControllerFactoryManagerStatics_iface) ); + return S_OK; + } + + if (IsEqualGUID( iid, &IID_IGameControllerFactoryManagerStatics2 )) + { + IInspectable_AddRef( (*out = &impl->IGameControllerFactoryManagerStatics2_iface) ); + 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 manager_statics *impl = impl_from_IActivationFactory( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + TRACE( "iface %p increasing refcount to %lu.\n", iface, ref ); + return ref; +} + +static ULONG WINAPI factory_Release( IActivationFactory *iface ) +{ + struct manager_statics *impl = impl_from_IActivationFactory( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + TRACE( "iface %p decreasing refcount 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( statics, IGameControllerFactoryManagerStatics, struct manager_statics, IActivationFactory_iface ) + +static HRESULT WINAPI +statics_RegisterCustomFactoryForGipInterface( IGameControllerFactoryManagerStatics *iface, + ICustomGameControllerFactory *factory, + GUID interface_id ) +{ + FIXME( "iface %p, factory %p, interface_id %s stub!\n", iface, factory, debugstr_guid(&interface_id) ); + return E_NOTIMPL; +} + +static HRESULT WINAPI +statics_RegisterCustomFactoryForHardwareId( IGameControllerFactoryManagerStatics *iface, + ICustomGameControllerFactory *factory, + UINT16 vendor_id, UINT16 product_id ) +{ + FIXME( "iface %p, factory %p, vendor_id %u, product_id %u stub!\n", iface, factory, vendor_id, product_id ); + return E_NOTIMPL; +} + +static HRESULT WINAPI +statics_RegisterCustomFactoryForXusbType( IGameControllerFactoryManagerStatics *iface, + ICustomGameControllerFactory *factory, + XusbDeviceType type, XusbDeviceSubtype subtype ) +{ + FIXME( "iface %p, factory %p, type %d, subtype %d stub!\n", iface, factory, type, subtype ); + return E_NOTIMPL; +} + +static const struct IGameControllerFactoryManagerStaticsVtbl statics_vtbl = +{ + statics_QueryInterface, + statics_AddRef, + statics_Release, + /* IInspectable methods */ + statics_GetIids, + statics_GetRuntimeClassName, + statics_GetTrustLevel, + /* IGameControllerFactoryManagerStatics methods */ + statics_RegisterCustomFactoryForGipInterface, + statics_RegisterCustomFactoryForHardwareId, + statics_RegisterCustomFactoryForXusbType, +}; + +DEFINE_IINSPECTABLE( statics2, IGameControllerFactoryManagerStatics2, struct manager_statics, IActivationFactory_iface ) + +static HRESULT WINAPI +statics2_TryGetFactoryControllerFromGameController( IGameControllerFactoryManagerStatics2 *iface, + ICustomGameControllerFactory *factory, + IGameController *controller, IGameController **value ) +{ + FIXME( "iface %p, factory %p, controller %p, value %p stub!\n", iface, factory, controller, value ); + return E_NOTIMPL; +} + +static const struct IGameControllerFactoryManagerStatics2Vtbl statics2_vtbl = +{ + statics2_QueryInterface, + statics2_AddRef, + statics2_Release, + /* IInspectable methods */ + statics2_GetIids, + statics2_GetRuntimeClassName, + statics2_GetTrustLevel, + /* IGameControllerFactoryManagerStatics2 methods */ + statics2_TryGetFactoryControllerFromGameController, +}; + +static struct manager_statics manager_statics = +{ + {&factory_vtbl}, + {&statics_vtbl}, + {&statics2_vtbl}, + 1, +}; + +IActivationFactory *manager_factory = &manager_statics.IActivationFactory_iface; diff --git a/dlls/windows.gaming.input/private.h b/dlls/windows.gaming.input/private.h index 612d11135f4..ba89af9199e 100644 --- a/dlls/windows.gaming.input/private.h +++ b/dlls/windows.gaming.input/private.h @@ -32,9 +32,11 @@ #define WIDL_using_Windows_Foundation_Collections #include "windows.foundation.h" #define WIDL_using_Windows_Gaming_Input -#include "windows.gaming.input.h" +#define WIDL_using_Windows_Gaming_Input_Custom +#include "windows.gaming.input.custom.h"
extern IActivationFactory *controller_factory; extern IActivationFactory *gamepad_factory; +extern IActivationFactory *manager_factory;
extern HRESULT vector_create( REFIID iid, REFIID view_iid, void **out );
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/windows.gaming.input/classes.idl | 15 +++++++++++++++ include/windows.gaming.input.custom.idl | 2 ++ include/windows.gaming.input.idl | 2 ++ 3 files changed, 19 insertions(+)
diff --git a/dlls/windows.gaming.input/classes.idl b/dlls/windows.gaming.input/classes.idl index c9cb91e3182..fd52d8ebf66 100644 --- a/dlls/windows.gaming.input/classes.idl +++ b/dlls/windows.gaming.input/classes.idl @@ -20,4 +20,19 @@
#pragma makedep register
+#ifdef __WIDL__ +#pragma winrt ns_prefix +#endif + +import "inspectable.idl"; +import "asyncinfo.idl"; +import "eventtoken.idl"; +import "windowscontracts.idl"; +import "windows.foundation.idl"; +import "windows.devices.haptics.idl"; +import "windows.gaming.input.forcefeedback.idl"; +import "windows.system.idl"; + +#define DO_NO_IMPORTS #include "windows.gaming.input.idl" +#include "windows.gaming.input.custom.idl" diff --git a/include/windows.gaming.input.custom.idl b/include/windows.gaming.input.custom.idl index a95ec9db482..fe20ce3d0cc 100644 --- a/include/windows.gaming.input.custom.idl +++ b/include/windows.gaming.input.custom.idl @@ -20,6 +20,7 @@ #pragma winrt ns_prefix #endif
+#ifndef DO_NO_IMPORTS import "inspectable.idl"; import "asyncinfo.idl"; import "eventtoken.idl"; @@ -27,6 +28,7 @@ import "windowscontracts.idl"; import "windows.foundation.idl"; import "windows.gaming.input.idl"; import "windows.storage.streams.idl"; +#endif
namespace Windows.Gaming.Input.Custom { typedef enum XusbDeviceSubtype XusbDeviceSubtype; diff --git a/include/windows.gaming.input.idl b/include/windows.gaming.input.idl index a7d5e71381d..90253b3a8f6 100644 --- a/include/windows.gaming.input.idl +++ b/include/windows.gaming.input.idl @@ -20,6 +20,7 @@ #pragma winrt ns_prefix #endif
+#ifndef DO_NO_IMPORTS import "inspectable.idl"; import "asyncinfo.idl"; import "eventtoken.idl"; @@ -28,6 +29,7 @@ import "windows.foundation.idl"; import "windows.devices.haptics.idl"; import "windows.gaming.input.forcefeedback.idl"; import "windows.system.idl"; +#endif
namespace Windows.Gaming.Input { typedef enum GamepadButtons GamepadButtons;
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/tests/hotplug.c | 141 +++++++++++++++++++++++++++++++++++- 1 file changed, 139 insertions(+), 2 deletions(-)
diff --git a/dlls/dinput/tests/hotplug.c b/dlls/dinput/tests/hotplug.c index 2f30cc19d9d..e8f5157d73f 100644 --- a/dlls/dinput/tests/hotplug.c +++ b/dlls/dinput/tests/hotplug.c @@ -45,7 +45,8 @@ #define WIDL_using_Windows_Foundation_Collections #include "windows.foundation.h" #define WIDL_using_Windows_Gaming_Input -#include "windows.gaming.input.h" +#define WIDL_using_Windows_Gaming_Input_Custom +#include "windows.gaming.input.custom.h"
#define MAKE_FUNC(f) static typeof(f) *p ## f MAKE_FUNC( RoGetActivationFactory ); @@ -527,6 +528,104 @@ static const IEventHandler_RawGameControllerVtbl controller_handler_vtbl = static struct controller_handler controller_removed = {{&controller_handler_vtbl}}; static struct controller_handler controller_added = {{&controller_handler_vtbl}};
+struct custom_factory +{ + ICustomGameControllerFactory ICustomGameControllerFactory_iface; + BOOL create_controller_called; +}; + +static inline struct custom_factory *impl_from_ICustomGameControllerFactory( ICustomGameControllerFactory *iface ) +{ + return CONTAINING_RECORD( iface, struct custom_factory, ICustomGameControllerFactory_iface ); +} + +static HRESULT WINAPI custom_factory_QueryInterface( ICustomGameControllerFactory *iface, REFIID iid, void **out ) +{ + struct custom_factory *impl = impl_from_ICustomGameControllerFactory( iface ); + + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IInspectable ) || + IsEqualGUID( iid, &IID_IAgileObject ) || + IsEqualGUID( iid, &IID_ICustomGameControllerFactory )) + { + IInspectable_AddRef( (*out = &impl->ICustomGameControllerFactory_iface) ); + return S_OK; + } + + ok( 0, "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI custom_factory_AddRef( ICustomGameControllerFactory *iface ) +{ + return 2; +} + +static ULONG WINAPI custom_factory_Release( ICustomGameControllerFactory *iface ) +{ + return 1; +} + +static HRESULT WINAPI custom_factory_GetIids( ICustomGameControllerFactory *iface, ULONG *iid_count, IID **iids ) +{ + ok( 0, "unexpected call\n" ); + return E_NOTIMPL; +} + +static HRESULT WINAPI custom_factory_GetRuntimeClassName( ICustomGameControllerFactory *iface, HSTRING *class_name ) +{ + ok( 0, "unexpected call\n" ); + return E_NOTIMPL; +} + +static HRESULT WINAPI custom_factory_GetTrustLevel( ICustomGameControllerFactory *iface, TrustLevel *trust_level ) +{ + ok( 0, "unexpected call\n" ); + return E_NOTIMPL; +} + +static HRESULT WINAPI custom_factory_CreateGameController( ICustomGameControllerFactory *iface, IGameControllerProvider *provider, + IInspectable **value ) +{ + struct custom_factory *impl = impl_from_ICustomGameControllerFactory( iface ); + + ok( !controller_added.invoked, "controller added handler invoked\n" ); + ok( !impl->create_controller_called, "unexpected call\n" ); + impl->create_controller_called = TRUE; + + return E_NOTIMPL; +} + +static HRESULT WINAPI custom_factory_OnGameControllerAdded( ICustomGameControllerFactory *iface, IGameController *value ) +{ + ok( 0, "unexpected call\n" ); + return E_NOTIMPL; +} + +static HRESULT WINAPI custom_factory_OnGameControllerRemoved( ICustomGameControllerFactory *iface, IGameController *value ) +{ + ok( 0, "unexpected call\n" ); + return E_NOTIMPL; +} + +static const struct ICustomGameControllerFactoryVtbl custom_factory_vtbl = +{ + custom_factory_QueryInterface, + custom_factory_AddRef, + custom_factory_Release, + /* IInspectable methods */ + custom_factory_GetIids, + custom_factory_GetRuntimeClassName, + custom_factory_GetTrustLevel, + /* ICustomGameControllerFactory methods */ + custom_factory_CreateGameController, + custom_factory_OnGameControllerAdded, + custom_factory_OnGameControllerRemoved, +}; + +static struct custom_factory custom_factory = {{&custom_factory_vtbl}}; + static LRESULT CALLBACK windows_gaming_input_wndproc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) { if (msg == WM_DEVICECHANGE) @@ -552,6 +651,7 @@ static LRESULT CALLBACK windows_gaming_input_wndproc( HWND hwnd, UINT msg, WPARA
static void test_windows_gaming_input(void) { + static const WCHAR *manager_class_name = RuntimeClass_Windows_Gaming_Input_Custom_GameControllerFactoryManager; static const WCHAR *class_name = RuntimeClass_Windows_Gaming_Input_RawGameController; DEV_BROADCAST_DEVICEINTERFACE_A iface_filter_a = { @@ -566,6 +666,10 @@ static void test_windows_gaming_input(void) .lpszClassName = L"devnotify", .lpfnWndProc = windows_gaming_input_wndproc, }; + IGameControllerFactoryManagerStatics2 *manager_statics2; + IRawGameController *raw_controller, *tmp_raw_controller; + IGameController *game_controller, *tmp_game_controller; + IGameControllerFactoryManagerStatics *manager_statics; EventRegistrationToken controller_removed_token; IVectorView_RawGameController *controller_view; EventRegistrationToken controller_added_token; @@ -594,11 +698,24 @@ static void test_windows_gaming_input(void) return; }
+ hr = pWindowsCreateString( manager_class_name, wcslen( manager_class_name ), &str ); + ok( hr == S_OK, "WindowsCreateString failed, hr %#lx\n", hr ); + hr = pRoGetActivationFactory( str, &IID_IGameControllerFactoryManagerStatics, (void **)&manager_statics ); + ok( hr == S_OK, "RoGetActivationFactory failed, hr %#lx\n", hr ); + hr = pRoGetActivationFactory( str, &IID_IGameControllerFactoryManagerStatics2, (void **)&manager_statics2 ); + ok( hr == S_OK, "RoGetActivationFactory failed, hr %#lx\n", hr ); + pWindowsDeleteString( str ); + controller_added.event = CreateEventW( NULL, FALSE, FALSE, NULL ); ok( !!controller_added.event, "CreateEventW failed, error %lu\n", GetLastError() ); controller_removed.event = CreateEventW( NULL, FALSE, FALSE, NULL ); ok( !!controller_removed.event, "CreateEventW failed, error %lu\n", GetLastError() );
+ hr = IGameControllerFactoryManagerStatics_RegisterCustomFactoryForHardwareId( manager_statics, &custom_factory.ICustomGameControllerFactory_iface, + LOWORD(EXPECT_VIDPID), HIWORD(EXPECT_VIDPID) ); + todo_wine + ok( hr == S_OK, "RegisterCustomFactoryForHardwareId returned %#lx\n", hr ); + hr = IRawGameControllerStatics_add_RawGameControllerAdded( statics, &controller_added.IEventHandler_RawGameController_iface, &controller_added_token ); ok( hr == S_OK, "add_RawGameControllerAdded returned %#lx\n", hr ); @@ -633,6 +750,7 @@ static void test_windows_gaming_input(void)
ok( controller_added.invoked, "controller added handler not invoked\n" ); ok( !controller_removed.invoked, "controller removed handler invoked\n" ); + ok( custom_factory.create_controller_called, "CreateGameController not called\n" );
hr = IVectorView_RawGameController_get_Size( controller_view, &size ); ok( hr == S_OK, "get_Size returned %#lx\n", hr ); @@ -645,6 +763,23 @@ static void test_windows_gaming_input(void) hr = IVectorView_RawGameController_get_Size( controller_view, &size ); ok( hr == S_OK, "get_Size returned %#lx\n", hr ); ok( size == 1, "got size %u\n", size ); + hr = IVectorView_RawGameController_GetAt( controller_view, 0, &raw_controller ); + ok( hr == S_OK, "GetAt returned %#lx\n", hr ); + hr = IRawGameController_QueryInterface( raw_controller, &IID_IGameController, (void **)&game_controller ); + ok( hr == S_OK, "QueryInterface returned %#lx\n", hr ); + + hr = IGameControllerFactoryManagerStatics2_TryGetFactoryControllerFromGameController( manager_statics2, + &custom_factory.ICustomGameControllerFactory_iface, game_controller, &tmp_game_controller ); + ok( hr == S_OK, "TryGetFactoryControllerFromGameController returned %#lx\n", hr ); + ok( !tmp_game_controller, "got controller %p\n", tmp_game_controller ); + + hr = IRawGameControllerStatics_FromGameController( statics, game_controller, &tmp_raw_controller ); + ok( hr == S_OK, "FromGameController returned %#lx\n", hr ); + ok( tmp_raw_controller == raw_controller, "got controller %p\n", tmp_raw_controller ); + IRawGameController_Release( tmp_raw_controller ); + + IGameController_Release( game_controller ); + IRawGameController_Release( raw_controller );
SetEvent( stop_event ); wait_for_events( 1, &controller_removed.event, INFINITE ); @@ -672,8 +807,10 @@ static void test_windows_gaming_input(void) ok( hr == S_OK, "remove_RawGameControllerRemoved returned %#lx\n", hr );
IVectorView_RawGameController_Release( controller_view ); - IRawGameControllerStatics_Release( statics );
+ IGameControllerFactoryManagerStatics2_Release( manager_statics2 ); + IGameControllerFactoryManagerStatics_Release( manager_statics ); + IRawGameControllerStatics_Release( statics ); WaitForSingleObject( thread, INFINITE ); CloseHandle( thread ); CloseHandle( stop_event );