When COM aggregation is involved it is important to add a reference to the returned iface and not to the inner object.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
The series also supsersedes 229017 in PATCH 5, with some fixups for the missing attributes and incorrect method case.
dlls/windows.gaming.input/controller.c | 6 ++---- dlls/windows.gaming.input/gamepad.c | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-)
diff --git a/dlls/windows.gaming.input/controller.c b/dlls/windows.gaming.input/controller.c index 654d0795eac..75ead342004 100644 --- a/dlls/windows.gaming.input/controller.c +++ b/dlls/windows.gaming.input/controller.c @@ -46,15 +46,13 @@ static HRESULT WINAPI factory_QueryInterface( IActivationFactory *iface, REFIID IsEqualGUID( iid, &IID_IAgileObject ) || IsEqualGUID( iid, &IID_IActivationFactory )) { - IUnknown_AddRef( iface ); - *out = iface; + IInspectable_AddRef( (*out = &impl->IActivationFactory_iface) ); return S_OK; }
if (IsEqualGUID( iid, &IID_IRawGameControllerStatics )) { - IUnknown_AddRef( iface ); - *out = &impl->IRawGameControllerStatics_iface; + IInspectable_AddRef( (*out = &impl->IRawGameControllerStatics_iface) ); return S_OK; }
diff --git a/dlls/windows.gaming.input/gamepad.c b/dlls/windows.gaming.input/gamepad.c index 231e923b5e8..ab95b4c8d89 100644 --- a/dlls/windows.gaming.input/gamepad.c +++ b/dlls/windows.gaming.input/gamepad.c @@ -46,15 +46,13 @@ static HRESULT WINAPI factory_QueryInterface( IActivationFactory *iface, REFIID IsEqualGUID( iid, &IID_IAgileObject ) || IsEqualGUID( iid, &IID_IActivationFactory )) { - IUnknown_AddRef( iface ); - *out = iface; + IInspectable_AddRef( (*out = &impl->IActivationFactory_iface) ); return S_OK; }
if (IsEqualGUID( iid, &IID_IGamepadStatics )) { - IUnknown_AddRef( iface ); - *out = &impl->IGamepadStatics_iface; + IInspectable_AddRef( (*out = &impl->IGamepadStatics_iface) ); return S_OK; }
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/windows.gaming.input/controller.c | 46 +++++++++++++++++++++++++- dlls/windows.gaming.input/main.c | 5 +-- dlls/windows.gaming.input/private.h | 2 +- 3 files changed, 49 insertions(+), 4 deletions(-)
diff --git a/dlls/windows.gaming.input/controller.c b/dlls/windows.gaming.input/controller.c index 75ead342004..27c5d6ebd32 100644 --- a/dlls/windows.gaming.input/controller.c +++ b/dlls/windows.gaming.input/controller.c @@ -27,6 +27,7 @@ struct controller_statics { IActivationFactory IActivationFactory_iface; IRawGameControllerStatics IRawGameControllerStatics_iface; + ICustomGameControllerFactory ICustomGameControllerFactory_iface; LONG ref; };
@@ -56,6 +57,12 @@ static HRESULT WINAPI factory_QueryInterface( IActivationFactory *iface, REFIID return S_OK; }
+ if (IsEqualGUID( iid, &IID_ICustomGameControllerFactory )) + { + IInspectable_AddRef( (*out = &impl->ICustomGameControllerFactory_iface) ); + return S_OK; + } + FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); *out = NULL; return E_NOINTERFACE; @@ -189,11 +196,48 @@ static const struct IRawGameControllerStaticsVtbl statics_vtbl = statics_FromGameController, };
+DEFINE_IINSPECTABLE( controller_factory, ICustomGameControllerFactory, struct controller_statics, IActivationFactory_iface ) + +static HRESULT WINAPI controller_factory_CreateGameController( ICustomGameControllerFactory *iface, IGameControllerProvider *provider, + IInspectable **value ) +{ + FIXME( "iface %p, provider %p, value %p stub!\n", iface, provider, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI controller_factory_OnGameControllerAdded( ICustomGameControllerFactory *iface, IGameController *value ) +{ + FIXME( "iface %p, value %p stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI controller_factory_OnGameControllerRemoved( ICustomGameControllerFactory *iface, IGameController *value ) +{ + FIXME( "iface %p, value %p stub!\n", iface, value ); + return E_NOTIMPL; +} + +static const struct ICustomGameControllerFactoryVtbl controller_factory_vtbl = +{ + controller_factory_QueryInterface, + controller_factory_AddRef, + controller_factory_Release, + /* IInspectable methods */ + controller_factory_GetIids, + controller_factory_GetRuntimeClassName, + controller_factory_GetTrustLevel, + /* ICustomGameControllerFactory methods */ + controller_factory_CreateGameController, + controller_factory_OnGameControllerAdded, + controller_factory_OnGameControllerRemoved, +}; + static struct controller_statics controller_statics = { {&factory_vtbl}, {&statics_vtbl}, + {&controller_factory_vtbl}, 1, };
-IActivationFactory *controller_factory = &controller_statics.IActivationFactory_iface; +ICustomGameControllerFactory *controller_factory = &controller_statics.ICustomGameControllerFactory_iface; diff --git a/dlls/windows.gaming.input/main.c b/dlls/windows.gaming.input/main.c index 03d47e1ce2f..d4bfec108ef 100644 --- a/dlls/windows.gaming.input/main.c +++ b/dlls/windows.gaming.input/main.c @@ -169,6 +169,7 @@ HRESULT WINAPI DllGetActivationFactory( HSTRING class_str, IActivationFactory ** { static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT; const WCHAR *buffer = WindowsGetStringRawBuffer( class_str, NULL ); + HRESULT hr = S_OK;
TRACE( "class %s, factory %p.\n", debugstr_w(buffer), factory );
@@ -177,13 +178,13 @@ HRESULT WINAPI DllGetActivationFactory( HSTRING class_str, IActivationFactory ** *factory = NULL;
if (!wcscmp( buffer, RuntimeClass_Windows_Gaming_Input_RawGameController )) - IActivationFactory_AddRef( (*factory = controller_factory) ); + hr = ICustomGameControllerFactory_QueryInterface( controller_factory, &IID_IActivationFactory, (void **)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; + if (SUCCEEDED(hr) && *factory) return S_OK; return REGDB_E_CLASSNOTREG; }
diff --git a/dlls/windows.gaming.input/private.h b/dlls/windows.gaming.input/private.h index a0bd45b3f20..fbec3d8189d 100644 --- a/dlls/windows.gaming.input/private.h +++ b/dlls/windows.gaming.input/private.h @@ -36,7 +36,7 @@ #include "windows.gaming.input.custom.h"
extern HINSTANCE windows_gaming_input; -extern IActivationFactory *controller_factory; +extern ICustomGameControllerFactory *controller_factory; extern IActivationFactory *gamepad_factory; extern IActivationFactory *manager_factory;
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/windows.gaming.input/gamepad.c | 46 ++++++++++++++++++++++++++++- dlls/windows.gaming.input/main.c | 2 +- dlls/windows.gaming.input/private.h | 2 +- 3 files changed, 47 insertions(+), 3 deletions(-)
diff --git a/dlls/windows.gaming.input/gamepad.c b/dlls/windows.gaming.input/gamepad.c index ab95b4c8d89..3793021d22c 100644 --- a/dlls/windows.gaming.input/gamepad.c +++ b/dlls/windows.gaming.input/gamepad.c @@ -27,6 +27,7 @@ struct gamepad_statics { IActivationFactory IActivationFactory_iface; IGamepadStatics IGamepadStatics_iface; + ICustomGameControllerFactory ICustomGameControllerFactory_iface; LONG ref; };
@@ -56,6 +57,12 @@ static HRESULT WINAPI factory_QueryInterface( IActivationFactory *iface, REFIID return S_OK; }
+ if (IsEqualGUID( iid, &IID_ICustomGameControllerFactory )) + { + IInspectable_AddRef( (*out = &impl->ICustomGameControllerFactory_iface) ); + return S_OK; + } + FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); *out = NULL; return E_NOINTERFACE; @@ -181,11 +188,48 @@ static const struct IGamepadStaticsVtbl statics_vtbl = statics_get_Gamepads, };
+DEFINE_IINSPECTABLE( controller_factory, ICustomGameControllerFactory, struct gamepad_statics, IActivationFactory_iface ) + +static HRESULT WINAPI controller_factory_CreateGameController( ICustomGameControllerFactory *iface, IGameControllerProvider *provider, + IInspectable **value ) +{ + FIXME( "iface %p, provider %p, value %p stub!\n", iface, provider, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI controller_factory_OnGameControllerAdded( ICustomGameControllerFactory *iface, IGameController *value ) +{ + FIXME( "iface %p, value %p stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI controller_factory_OnGameControllerRemoved( ICustomGameControllerFactory *iface, IGameController *value ) +{ + FIXME( "iface %p, value %p stub!\n", iface, value ); + return E_NOTIMPL; +} + +static const struct ICustomGameControllerFactoryVtbl controller_factory_vtbl = +{ + controller_factory_QueryInterface, + controller_factory_AddRef, + controller_factory_Release, + /* IInspectable methods */ + controller_factory_GetIids, + controller_factory_GetRuntimeClassName, + controller_factory_GetTrustLevel, + /* ICustomGameControllerFactory methods */ + controller_factory_CreateGameController, + controller_factory_OnGameControllerAdded, + controller_factory_OnGameControllerRemoved, +}; + static struct gamepad_statics gamepad_statics = { {&factory_vtbl}, {&statics_vtbl}, + {&controller_factory_vtbl}, 1, };
-IActivationFactory *gamepad_factory = &gamepad_statics.IActivationFactory_iface; +ICustomGameControllerFactory *gamepad_factory = &gamepad_statics.ICustomGameControllerFactory_iface; diff --git a/dlls/windows.gaming.input/main.c b/dlls/windows.gaming.input/main.c index d4bfec108ef..e71043fcb0f 100644 --- a/dlls/windows.gaming.input/main.c +++ b/dlls/windows.gaming.input/main.c @@ -180,7 +180,7 @@ HRESULT WINAPI DllGetActivationFactory( HSTRING class_str, IActivationFactory ** if (!wcscmp( buffer, RuntimeClass_Windows_Gaming_Input_RawGameController )) hr = ICustomGameControllerFactory_QueryInterface( controller_factory, &IID_IActivationFactory, (void **)factory ); if (!wcscmp( buffer, RuntimeClass_Windows_Gaming_Input_Gamepad )) - IActivationFactory_AddRef( (*factory = gamepad_factory) ); + hr = ICustomGameControllerFactory_QueryInterface( gamepad_factory, &IID_IActivationFactory, (void **)factory ); if (!wcscmp( buffer, RuntimeClass_Windows_Gaming_Input_Custom_GameControllerFactoryManager )) IActivationFactory_AddRef( (*factory = manager_factory) );
diff --git a/dlls/windows.gaming.input/private.h b/dlls/windows.gaming.input/private.h index fbec3d8189d..24d0609aa7e 100644 --- a/dlls/windows.gaming.input/private.h +++ b/dlls/windows.gaming.input/private.h @@ -37,7 +37,7 @@
extern HINSTANCE windows_gaming_input; extern ICustomGameControllerFactory *controller_factory; -extern IActivationFactory *gamepad_factory; +extern ICustomGameControllerFactory *gamepad_factory; extern IActivationFactory *manager_factory;
extern HRESULT vector_create( REFIID iid, REFIID view_iid, void **out );
This is more likely some specialized interface of a parameterized type, used to create mixin types, but we have no way and no clue where it comes from or how it should be declared.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/windows.gaming.input/provider.idl | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/dlls/windows.gaming.input/provider.idl b/dlls/windows.gaming.input/provider.idl index dc67a94acaa..d6c4f1d16ec 100644 --- a/dlls/windows.gaming.input/provider.idl +++ b/dlls/windows.gaming.input/provider.idl @@ -34,6 +34,16 @@ namespace Windows.Gaming.Input.Custom { interface IWineGameControllerProvider; runtimeclass WineGameControllerProvider;
+ [ + uuid(06e58977-7684-4dc5-bad1-cda52a4aa06d) + ] + interface IGameControllerImpl : IInspectable + requires Windows.Gaming.Input.Custom.IGameControllerInputSink + { + HRESULT Initialize([in] Windows.Gaming.Input.IGameController *outer, + [in] Windows.Gaming.Input.Custom.IGameControllerProvider *provider); + } + [ exclusiveto(Windows.Gaming.Input.Custom.WineGameControllerProvider), uuid(8967b6ef-a4de-4b9a-984a-9f920b4d1b26)
From: Alistair Leslie-Hughes leslie_alistair@hotmail.com
Signed-off-by: Alistair Leslie-Hughes leslie_alistair@hotmail.com Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- include/windows.foundation.collections.idl | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/include/windows.foundation.collections.idl b/include/windows.foundation.collections.idl index 7576f331172..ed1f5e30793 100644 --- a/include/windows.foundation.collections.idl +++ b/include/windows.foundation.collections.idl @@ -73,6 +73,15 @@ cpp_quote("#endif") ] delegate HRESULT TypedEventHandler<TSender, TArgs>([in] TSender sender, [in] TArgs args);
+ [ + contract(Windows.Foundation.FoundationContract, 1.0), + uuid(61c17706-2d65-11e0-9ae8-d48564015472) + ] + interface IReference<T> : IInspectable + { + [propget] HRESULT Value([out, retval] T *value); + } + namespace Collections { [
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- include/Makefile.in | 1 + include/windows.devices.power.idl | 15 +++++++++++++ include/windows.foundation.idl | 1 + include/windows.system.power.idl | 37 +++++++++++++++++++++++++++++++ 4 files changed, 54 insertions(+) create mode 100644 include/windows.system.power.idl
diff --git a/include/Makefile.in b/include/Makefile.in index ae551abd4c0..9578c557af7 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -792,6 +792,7 @@ SOURCES = \ windows.media.speechsynthesis.idl \ windows.storage.streams.idl \ windows.system.idl \ + windows.system.power.idl \ windows.system.userprofile.idl \ windowscontracts.idl \ windowsx.h \ diff --git a/include/windows.devices.power.idl b/include/windows.devices.power.idl index 4bf2599686c..f91c8fac6e3 100644 --- a/include/windows.devices.power.idl +++ b/include/windows.devices.power.idl @@ -22,11 +22,26 @@
import "inspectable.idl"; import "windows.foundation.idl"; +import "windows.system.power.idl";
namespace Windows.Devices.Power { interface IBatteryReport; runtimeclass BatteryReport;
+ [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + exclusiveto(Windows.Devices.Power.BatteryReport), + uuid(c9858c3a-4e13-420a-a8d0-24f18f395401) + ] + interface IBatteryReport : IInspectable + { + [propget] HRESULT ChargeRateInMilliwatts([out, retval] Windows.Foundation.IReference<INT32> **value); + [propget] HRESULT DesignCapacityInMilliwattHours([out, retval] Windows.Foundation.IReference<INT32> **value); + [propget] HRESULT FullChargeCapacityInMilliwattHours([out, retval] Windows.Foundation.IReference<INT32> **value); + [propget] HRESULT RemainingCapacityInMilliwattHours([out, retval] Windows.Foundation.IReference<INT32> **value); + [propget] HRESULT Status([out, retval] Windows.System.Power.BatteryStatus *value); + } + [ contract(Windows.Foundation.UniversalApiContract, 1.0), marshaling_behavior(agile), diff --git a/include/windows.foundation.idl b/include/windows.foundation.idl index 50e134d3900..a92a5d82424 100644 --- a/include/windows.foundation.idl +++ b/include/windows.foundation.idl @@ -167,6 +167,7 @@ namespace Windows { interface Windows.Foundation.Collections.IMapView<HSTRING, Windows.Foundation.Collections.IVectorView<HSTRING>*>; interface Windows.Foundation.AsyncOperationCompletedHandler<boolean>; interface Windows.Foundation.IAsyncOperation<boolean>; + interface Windows.Foundation.IReference<INT32>; } } } diff --git a/include/windows.system.power.idl b/include/windows.system.power.idl new file mode 100644 index 00000000000..366042dbf2f --- /dev/null +++ b/include/windows.system.power.idl @@ -0,0 +1,37 @@ +/* + * Copyright 2022 Rémi Bernon for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef __WIDL__ +#pragma winrt ns_prefix +#endif + +import "inspectable.idl"; +import "windows.foundation.idl"; + +namespace Windows.System.Power { + typedef enum BatteryStatus BatteryStatus; + + [contract(Windows.Foundation.UniversalApiContract, 1.0)] + enum BatteryStatus + { + NotPresent = 0, + Discharging = 1, + Idle = 2, + Charging = 3, + }; +}
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/windows.gaming.input/manager.c | 276 +++++++++++++++++++++++++++- dlls/windows.gaming.input/private.h | 1 + 2 files changed, 275 insertions(+), 2 deletions(-)
diff --git a/dlls/windows.gaming.input/manager.c b/dlls/windows.gaming.input/manager.c index e6366256fe7..ec1ae6a3880 100644 --- a/dlls/windows.gaming.input/manager.c +++ b/dlls/windows.gaming.input/manager.c @@ -18,12 +18,211 @@ */
#include "private.h" +#include "provider.h"
#include "wine/debug.h" #include "wine/list.h"
WINE_DEFAULT_DEBUG_CHANNEL(input);
+static CRITICAL_SECTION manager_cs; +static CRITICAL_SECTION_DEBUG manager_cs_debug = +{ + 0, 0, &manager_cs, + { &manager_cs_debug.ProcessLocksList, &manager_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": manager_cs") } +}; +static CRITICAL_SECTION manager_cs = { &manager_cs_debug, -1, 0, 0, 0, 0 }; + +static struct list controller_list = LIST_INIT( controller_list ); + +struct controller +{ + IGameController IGameController_iface; + IGameControllerBatteryInfo IGameControllerBatteryInfo_iface; + IInspectable *IInspectable_inner; + LONG ref; + + struct list entry; + IGameControllerProvider *provider; + ICustomGameControllerFactory *factory; +}; + +static inline struct controller *impl_from_IGameController( IGameController *iface ) +{ + return CONTAINING_RECORD( iface, struct controller, IGameController_iface ); +} + +static HRESULT WINAPI controller_QueryInterface( IGameController *iface, REFIID iid, void **out ) +{ + struct controller *impl = impl_from_IGameController( 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_IGameController )) + { + IInspectable_AddRef( (*out = &impl->IGameController_iface) ); + return S_OK; + } + + if (IsEqualGUID( iid, &IID_IGameControllerBatteryInfo )) + { + IInspectable_AddRef( (*out = &impl->IGameControllerBatteryInfo_iface) ); + return S_OK; + } + + return IInspectable_QueryInterface( impl->IInspectable_inner, iid, out ); +} + +static ULONG WINAPI controller_AddRef( IGameController *iface ) +{ + struct controller *impl = impl_from_IGameController( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + TRACE( "iface %p increasing refcount to %lu.\n", iface, ref ); + return ref; +} + +static ULONG WINAPI controller_Release( IGameController *iface ) +{ + struct controller *impl = impl_from_IGameController( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + + TRACE( "iface %p decreasing refcount to %lu.\n", iface, ref ); + + if (!ref) + { + InterlockedIncrement( &impl->ref ); + IInspectable_Release( impl->IInspectable_inner ); + ICustomGameControllerFactory_Release( impl->factory ); + IGameControllerProvider_Release( impl->provider ); + list_remove( &impl->entry ); + free( impl ); + } + + return ref; +} + +static HRESULT WINAPI controller_GetIids( IGameController *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 controller_GetRuntimeClassName( IGameController *iface, HSTRING *class_name ) +{ + struct controller *impl = impl_from_IGameController( iface ); + return IInspectable_GetRuntimeClassName( impl->IInspectable_inner, class_name ); +} + +static HRESULT WINAPI controller_GetTrustLevel( IGameController *iface, TrustLevel *trust_level ) +{ + struct controller *impl = impl_from_IGameController( iface ); + return IInspectable_GetTrustLevel( impl->IInspectable_inner, trust_level ); +} + +static HRESULT WINAPI controller_add_HeadsetConnected( IGameController *iface, ITypedEventHandler_IGameController_Headset *handler, + EventRegistrationToken *token ) +{ + FIXME( "iface %p, handler %p, token %p stub!\n", iface, handler, token ); + return E_NOTIMPL; +} + +static HRESULT WINAPI controller_remove_HeadsetConnected( IGameController *iface, EventRegistrationToken token ) +{ + FIXME( "iface %p, token %I64x stub!\n", iface, token.value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI controller_add_HeadsetDisconnected( IGameController *iface, ITypedEventHandler_IGameController_Headset *handler, + EventRegistrationToken *token ) +{ + FIXME( "iface %p, handler %p, token %p stub!\n", iface, handler, token ); + return E_NOTIMPL; +} + +static HRESULT WINAPI controller_remove_HeadsetDisconnected( IGameController *iface, EventRegistrationToken token ) +{ + FIXME( "iface %p, token %I64x stub!\n", iface, token.value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI controller_add_UserChanged( IGameController *iface, + ITypedEventHandler_IGameController_UserChangedEventArgs *handler, + EventRegistrationToken *token ) +{ + FIXME( "iface %p, handler %p, token %p stub!\n", iface, handler, token ); + return E_NOTIMPL; +} + +static HRESULT WINAPI controller_remove_UserChanged( IGameController *iface, EventRegistrationToken token ) +{ + FIXME( "iface %p, token %I64x stub!\n", iface, token.value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI controller_get_Headset( IGameController *iface, IHeadset **value ) +{ + FIXME( "iface %p, value %p stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI controller_get_IsWireless( IGameController *iface, boolean *value ) +{ + FIXME( "iface %p, value %p stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI controller_get_User( IGameController *iface, __x_ABI_CWindows_CSystem_CIUser **value ) +{ + FIXME( "iface %p, value %p stub!\n", iface, value ); + return E_NOTIMPL; +} + +static const struct IGameControllerVtbl controller_vtbl = +{ + controller_QueryInterface, + controller_AddRef, + controller_Release, + /* IInspectable methods */ + controller_GetIids, + controller_GetRuntimeClassName, + controller_GetTrustLevel, + /* IGameController methods */ + controller_add_HeadsetConnected, + controller_remove_HeadsetConnected, + controller_add_HeadsetDisconnected, + controller_remove_HeadsetDisconnected, + controller_add_UserChanged, + controller_remove_UserChanged, + controller_get_Headset, + controller_get_IsWireless, + controller_get_User, +}; + +DEFINE_IINSPECTABLE( battery, IGameControllerBatteryInfo, struct controller, IGameController_iface ) + +static HRESULT WINAPI battery_TryGetBatteryReport( IGameControllerBatteryInfo *iface, IBatteryReport **value ) +{ + FIXME( "iface %p, value %p stub!\n", iface, value ); + return E_NOTIMPL; +} + +static const struct IGameControllerBatteryInfoVtbl battery_vtbl = +{ + battery_QueryInterface, + battery_AddRef, + battery_Release, + /* IInspectable methods */ + battery_GetIids, + battery_GetRuntimeClassName, + battery_GetTrustLevel, + /* IGameControllerBatteryInfo methods */ + battery_TryGetBatteryReport, +}; + struct manager_statics { IActivationFactory IActivationFactory_iface; @@ -200,12 +399,85 @@ static struct manager_statics manager_statics =
IActivationFactory *manager_factory = &manager_statics.IActivationFactory_iface;
+static HRESULT controller_create( ICustomGameControllerFactory *factory, IGameControllerProvider *provider, + struct controller **out ) +{ + IGameControllerImpl *inner_impl; + struct controller *impl; + HRESULT hr; + + if (!(impl = malloc(sizeof(*impl)))) return E_OUTOFMEMORY; + impl->IGameController_iface.lpVtbl = &controller_vtbl; + impl->IGameControllerBatteryInfo_iface.lpVtbl = &battery_vtbl; + impl->ref = 1; + + if (FAILED(hr = ICustomGameControllerFactory_CreateGameController( factory, provider, &impl->IInspectable_inner ))) + WARN( "Failed to create game controller, hr %#lx\n", hr ); + else if (FAILED(hr = IInspectable_QueryInterface( impl->IInspectable_inner, &IID_IGameControllerImpl, (void **)&inner_impl ))) + WARN( "Failed to find IGameControllerImpl iface, hr %#lx\n", hr ); + else + { + if (FAILED(hr = IGameControllerImpl_Initialize( inner_impl, &impl->IGameController_iface, provider ))) + WARN( "Failed to initialize game controller, hr %#lx\n", hr ); + IGameControllerImpl_Release( inner_impl ); + } + + if (FAILED(hr)) + { + if (impl->IInspectable_inner) IInspectable_Release( impl->IInspectable_inner ); + free( impl ); + return hr; + } + + ICustomGameControllerFactory_AddRef( (impl->factory = factory) ); + IGameControllerProvider_AddRef( (impl->provider = provider) ); + + EnterCriticalSection( &manager_cs ); + list_add_tail( &controller_list, &impl->entry ); + LeaveCriticalSection( &manager_cs ); + + *out = impl; + return S_OK; +} + void manager_on_provider_created( IGameControllerProvider *provider ) { - FIXME( "provider %p stub!\n", provider ); + struct controller *entries[16]; + ULONG i, count = 0; + HRESULT hr; + + TRACE( "provider %p\n", provider ); + + if (SUCCEEDED(controller_create( controller_factory, provider, entries + count ))) count++; + + EnterCriticalSection( &manager_cs ); + for (i = 0; i < count; ++i) + { + hr = ICustomGameControllerFactory_OnGameControllerAdded( entries[i]->factory, + &entries[i]->IGameController_iface ); + if (FAILED(hr)) IGameController_Release( &entries[i]->IGameController_iface ); + } + LeaveCriticalSection( &manager_cs ); }
void manager_on_provider_removed( IGameControllerProvider *provider ) { - FIXME( "provider %p stub!\n", provider ); + struct controller *entry, *next; + + TRACE( "provider %p\n", provider ); + + EnterCriticalSection( &manager_cs ); + LIST_FOR_EACH_ENTRY( entry, &controller_list, struct controller, entry ) + { + if (entry->provider != provider) continue; + ICustomGameControllerFactory_OnGameControllerRemoved( entry->factory, + &entry->IGameController_iface ); + } + + LIST_FOR_EACH_ENTRY_SAFE( entry, next, &controller_list, struct controller, entry ) + { + if (entry->provider != provider) continue; + IGameController_Release( &entry->IGameController_iface ); + } + LeaveCriticalSection( &manager_cs ); } diff --git a/dlls/windows.gaming.input/private.h b/dlls/windows.gaming.input/private.h index 24d0609aa7e..27dbdb8416c 100644 --- a/dlls/windows.gaming.input/private.h +++ b/dlls/windows.gaming.input/private.h @@ -31,6 +31,7 @@ #define WIDL_using_Windows_Foundation #define WIDL_using_Windows_Foundation_Collections #include "windows.foundation.h" +#define WIDL_using_Windows_Devices_Power #define WIDL_using_Windows_Gaming_Input #define WIDL_using_Windows_Gaming_Input_Custom #include "windows.gaming.input.custom.h"