[PATCH v2 1/6] windows.gaming.input: Implement IRawGameControllerStatics_get_RawGameControllers.

Rémi Bernon rbernon at codeweavers.com
Thu Mar 10 06:05:47 CST 2022


It is important to add RawGameController instances to the vector in the
initialization callback, because some games check the vector, as well
as the Gamepad class vector in the OnGameControllerAdded callback.

This also removes the OnGameControllerAdded failure case, to avoid
leaking controllers that were already added to the controller vector,
and instead rely on the OnGameControllerRemoved call to do the cleanup.

Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---

v2: * Initialize controller state in GetReading calls,

    * Fix IWineGameControllerProvider query failure support in the class
      destruction.

 dlls/dinput/tests/joystick8.c          |  9 +--
 dlls/windows.gaming.input/controller.c | 82 +++++++++++++++++++++-----
 dlls/windows.gaming.input/manager.c    |  6 +-
 3 files changed, 70 insertions(+), 27 deletions(-)

diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c
index 2d801aacda2..e74e76482f9 100644
--- a/dlls/dinput/tests/joystick8.c
+++ b/dlls/dinput/tests/joystick8.c
@@ -3340,17 +3340,10 @@ static void test_windows_gaming_input(void)
     ok( hr == S_OK, "get_RawGameControllers returned %#lx\n", hr );
     hr = IVectorView_RawGameController_get_Size( controllers_view, &size );
     ok( hr == S_OK, "get_Size returned %#lx\n", hr );
-    todo_wine
     ok( size == 1, "got size %u\n", size );
     hr = IVectorView_RawGameController_GetAt( controllers_view, 0, &raw_controller );
-    todo_wine
     ok( hr == S_OK, "GetAt returned %#lx\n", hr );
     IVectorView_RawGameController_Release( controllers_view );
-    if (hr != S_OK)
-    {
-        IRawGameControllerStatics_Release( controller_statics );
-        goto done;
-    }
 
     /* HID gamepads aren't exposed as WGI gamepads on Windows */
 
@@ -3372,6 +3365,7 @@ static void test_windows_gaming_input(void)
     check_interface( raw_controller, &IID_IInspectable, TRUE );
     check_interface( raw_controller, &IID_IAgileObject, TRUE );
     check_interface( raw_controller, &IID_IRawGameController, TRUE );
+    todo_wine
     check_interface( raw_controller, &IID_IRawGameController2, TRUE );
     check_interface( raw_controller, &IID_IGameController, TRUE );
     check_interface( raw_controller, &IID_IGamepad, FALSE );
@@ -3384,6 +3378,7 @@ static void test_windows_gaming_input(void)
     check_interface( game_controller, &IID_IInspectable, TRUE );
     check_interface( game_controller, &IID_IAgileObject, TRUE );
     check_interface( game_controller, &IID_IRawGameController, TRUE );
+    todo_wine
     check_interface( game_controller, &IID_IRawGameController2, TRUE );
     check_interface( game_controller, &IID_IGameController, TRUE );
     check_interface( game_controller, &IID_IGamepad, FALSE );
diff --git a/dlls/windows.gaming.input/controller.c b/dlls/windows.gaming.input/controller.c
index 9fb1b1a69a2..51ede5a0e47 100644
--- a/dlls/windows.gaming.input/controller.c
+++ b/dlls/windows.gaming.input/controller.c
@@ -24,6 +24,36 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(input);
 
+static CRITICAL_SECTION controller_cs;
+static CRITICAL_SECTION_DEBUG controller_cs_debug =
+{
+    0, 0, &controller_cs,
+    { &controller_cs_debug.ProcessLocksList, &controller_cs_debug.ProcessLocksList },
+      0, 0, { (DWORD_PTR)(__FILE__ ": controller_cs") }
+};
+static CRITICAL_SECTION controller_cs = { &controller_cs_debug, -1, 0, 0, 0, 0 };
+
+static IVector_RawGameController *controllers;
+
+static HRESULT init_controllers(void)
+{
+    static const struct vector_iids iids =
+    {
+        .vector = &IID_IVector_RawGameController,
+        .view = &IID_IVectorView_RawGameController,
+        .iterable = &IID_IIterable_RawGameController,
+        .iterator = &IID_IIterator_RawGameController,
+    };
+    HRESULT hr;
+
+    EnterCriticalSection( &controller_cs );
+    if (controllers) hr = S_OK;
+    else hr = vector_create( &iids, (void **)&controllers );
+    LeaveCriticalSection( &controller_cs );
+
+    return hr;
+}
+
 struct controller
 {
     IGameControllerImpl IGameControllerImpl_iface;
@@ -118,13 +148,19 @@ static HRESULT WINAPI controller_Initialize( IGameControllerImpl *iface, IGameCo
                                              IGameControllerProvider *provider )
 {
     struct controller *impl = impl_from_IGameControllerImpl( iface );
+    HRESULT hr;
 
     TRACE( "iface %p, outer %p, provider %p.\n", iface, outer, provider );
 
     impl->IGameController_outer = outer;
     IGameControllerProvider_AddRef( (impl->provider = provider) );
 
-    return S_OK;
+    EnterCriticalSection( &controller_cs );
+    if (SUCCEEDED(hr = init_controllers()))
+        hr = IVector_RawGameController_Append( controllers, &impl->IRawGameController_iface );
+    LeaveCriticalSection( &controller_cs );
+
+    return hr;
 }
 
 static const struct IGameControllerImplVtbl controller_vtbl =
@@ -381,23 +417,14 @@ static HRESULT WINAPI statics_remove_RawGameControllerRemoved( IRawGameControlle
 
 static HRESULT WINAPI statics_get_RawGameControllers( IRawGameControllerStatics *iface, IVectorView_RawGameController **value )
 {
-    static const struct vector_iids iids =
-    {
-        .vector = &IID_IVector_RawGameController,
-        .view = &IID_IVectorView_RawGameController,
-        .iterable = &IID_IIterable_RawGameController,
-        .iterator = &IID_IIterator_RawGameController,
-    };
-    IVector_RawGameController *controllers;
     HRESULT hr;
 
     TRACE( "iface %p, value %p.\n", iface, value );
 
-    if (SUCCEEDED(hr = vector_create( &iids, (void **)&controllers )))
-    {
+    EnterCriticalSection( &controller_cs );
+    if (SUCCEEDED(hr = init_controllers()))
         hr = IVector_RawGameController_GetView( controllers, value );
-        IVector_RawGameController_Release( controllers );
-    }
+    LeaveCriticalSection( &controller_cs );
 
     return hr;
 }
@@ -468,8 +495,33 @@ static HRESULT WINAPI controller_factory_OnGameControllerAdded( ICustomGameContr
 
 static HRESULT WINAPI controller_factory_OnGameControllerRemoved( ICustomGameControllerFactory *iface, IGameController *value )
 {
-    FIXME( "iface %p, value %p stub!\n", iface, value );
-    return E_NOTIMPL;
+    IRawGameController *controller;
+    BOOLEAN found;
+    UINT32 index;
+    HRESULT hr;
+
+    TRACE( "iface %p, value %p.\n", iface, value );
+
+    if (FAILED(hr = IGameController_QueryInterface( value, &IID_IRawGameController, (void **)&controller )))
+        return hr;
+
+    EnterCriticalSection( &controller_cs );
+    if (SUCCEEDED(hr = init_controllers()))
+    {
+        if (FAILED(hr = IVector_RawGameController_IndexOf( controllers, controller, &index, &found )) || !found)
+            WARN( "Could not find controller %p, hr %#lx!\n", controller, hr );
+        else
+            hr = IVector_RawGameController_RemoveAt( controllers, index );
+    }
+    LeaveCriticalSection( &controller_cs );
+
+    if (FAILED(hr))
+        WARN( "Failed to remove controller %p, hr %#lx!\n", controller, hr );
+    else if (found)
+        TRACE( "Removed controller %p.\n", controller );
+    IRawGameController_Release( controller );
+
+    return S_OK;
 }
 
 static const struct ICustomGameControllerFactoryVtbl controller_factory_vtbl =
diff --git a/dlls/windows.gaming.input/manager.c b/dlls/windows.gaming.input/manager.c
index 489588a68ab..6a8963a1fc4 100644
--- a/dlls/windows.gaming.input/manager.c
+++ b/dlls/windows.gaming.input/manager.c
@@ -502,11 +502,7 @@ void manager_on_provider_created( IGameControllerProvider *provider )
         controller = LIST_ENTRY( entry, struct controller, entry );
         hr = ICustomGameControllerFactory_OnGameControllerAdded( controller->factory,
                                                                  &controller->IGameController_iface );
-        if (FAILED(hr))
-        {
-            list_remove( &controller->entry );
-            IGameController_Release( &controller->IGameController_iface );
-        }
+        if (FAILED(hr)) WARN( "OnGameControllerAdded failed, hr %#lx\n", hr );
         if (next == &controller_list) break;
     }
 
-- 
2.35.1




More information about the wine-devel mailing list