[PATCH v2 3/6] windows.gaming.input: Implement IForceFeedbackEffect interface for ConstantForceEffect.

Rémi Bernon wine at gitlab.winehq.org
Fri May 13 03:01:15 CDT 2022


From: Rémi Bernon <rbernon at codeweavers.com>

Using COM aggregation and a new IWineForceFeedbackEffectImpl interface,
deriving from IUnknown as it is only used internally.

Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
 dlls/dinput/tests/force_feedback.c          |   3 +-
 dlls/windows.gaming.input/constant_effect.c |  21 +++-
 dlls/windows.gaming.input/force_feedback.c  | 133 ++++++++++++++++++++
 dlls/windows.gaming.input/private.h         |   3 +
 dlls/windows.gaming.input/provider.idl      |  14 +++
 5 files changed, 168 insertions(+), 6 deletions(-)

diff --git a/dlls/dinput/tests/force_feedback.c b/dlls/dinput/tests/force_feedback.c
index e688f575704..bbd9ed2310b 100644
--- a/dlls/dinput/tests/force_feedback.c
+++ b/dlls/dinput/tests/force_feedback.c
@@ -5628,10 +5628,8 @@ static void test_windows_gaming_input(void)
     IActivationFactory_Release( activation_factory );
 
     hr = IInspectable_QueryInterface( tmp_inspectable, &IID_IForceFeedbackEffect, (void **)&effect );
-    todo_wine
     ok( hr == S_OK, "QueryInterface returned %#lx\n", hr );
     IInspectable_Release( tmp_inspectable );
-    if (hr != S_OK) goto skip_tests;
 
     hr = IForceFeedbackEffect_QueryInterface( effect, &IID_IConstantForceEffect, (void **)&constant_effect );
     ok( hr == S_OK, "QueryInterface returned %#lx\n", hr );
@@ -5670,6 +5668,7 @@ static void test_windows_gaming_input(void)
     hr = IForceFeedbackMotor_LoadEffectAsync( motor, effect, &result_async );
     todo_wine
     ok( hr == S_OK, "LoadEffectAsync returned %#lx\n", hr );
+    if (hr != S_OK) goto skip_tests;
     result_async_handler = default_result_async_handler;
     result_async_handler.event = CreateEventW( NULL, FALSE, FALSE, NULL );
     ok( !!result_async_handler.event, "CreateEventW failed, error %lu\n", GetLastError() );
diff --git a/dlls/windows.gaming.input/constant_effect.c b/dlls/windows.gaming.input/constant_effect.c
index a491d49c18c..ae0c0f9904d 100644
--- a/dlls/windows.gaming.input/constant_effect.c
+++ b/dlls/windows.gaming.input/constant_effect.c
@@ -25,6 +25,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(input);
 struct constant_effect
 {
     IConstantForceEffect IConstantForceEffect_iface;
+    IWineForceFeedbackEffectImpl *IWineForceFeedbackEffectImpl_inner;
     LONG ref;
 };
 
@@ -48,9 +49,7 @@ static HRESULT WINAPI effect_QueryInterface( IConstantForceEffect *iface, REFIID
         return S_OK;
     }
 
-    FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) );
-    *out = NULL;
-    return E_NOINTERFACE;
+    return IWineForceFeedbackEffectImpl_QueryInterface( impl->IWineForceFeedbackEffectImpl_inner, iid, out );
 }
 
 static ULONG WINAPI effect_AddRef( IConstantForceEffect *iface )
@@ -68,7 +67,13 @@ static ULONG WINAPI effect_Release( IConstantForceEffect *iface )
 
     TRACE( "iface %p decreasing refcount to %lu.\n", iface, ref );
 
-    if (!ref) free( impl );
+    if (!ref)
+    {
+        /* guard against re-entry if inner releases an outer iface */
+        InterlockedIncrement( &impl->ref );
+        IWineForceFeedbackEffectImpl_Release( impl->IWineForceFeedbackEffectImpl_inner );
+        free( impl );
+    }
 
     return ref;
 }
@@ -192,6 +197,7 @@ static HRESULT WINAPI activation_GetTrustLevel( IActivationFactory *iface, Trust
 static HRESULT WINAPI activation_ActivateInstance( IActivationFactory *iface, IInspectable **instance )
 {
     struct constant_effect *impl;
+    HRESULT hr;
 
     TRACE( "iface %p, instance %p.\n", iface, instance );
 
@@ -199,6 +205,13 @@ static HRESULT WINAPI activation_ActivateInstance( IActivationFactory *iface, II
     impl->IConstantForceEffect_iface.lpVtbl = &effect_vtbl;
     impl->ref = 1;
 
+    if (FAILED(hr = force_feedback_effect_create( (IInspectable *)&impl->IConstantForceEffect_iface,
+                                                  &impl->IWineForceFeedbackEffectImpl_inner )))
+    {
+        free( impl );
+        return hr;
+    }
+
     *instance = (IInspectable *)&impl->IConstantForceEffect_iface;
     TRACE( "created ConstantForceEffect %p\n", *instance );
     return S_OK;
diff --git a/dlls/windows.gaming.input/force_feedback.c b/dlls/windows.gaming.input/force_feedback.c
index 3fdcc636bbd..ab29a179c6a 100644
--- a/dlls/windows.gaming.input/force_feedback.c
+++ b/dlls/windows.gaming.input/force_feedback.c
@@ -27,6 +27,139 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(input);
 
+struct effect
+{
+    IWineForceFeedbackEffectImpl IWineForceFeedbackEffectImpl_iface;
+    IForceFeedbackEffect IForceFeedbackEffect_iface;
+    IInspectable *IInspectable_outer;
+    LONG ref;
+};
+
+static inline struct effect *impl_from_IWineForceFeedbackEffectImpl( IWineForceFeedbackEffectImpl *iface )
+{
+    return CONTAINING_RECORD( iface, struct effect, IWineForceFeedbackEffectImpl_iface );
+}
+
+static HRESULT WINAPI effect_impl_QueryInterface( IWineForceFeedbackEffectImpl *iface, REFIID iid, void **out )
+{
+    struct effect *impl = impl_from_IWineForceFeedbackEffectImpl( 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_IWineForceFeedbackEffectImpl ))
+    {
+        IWineForceFeedbackEffectImpl_AddRef( (*out = &impl->IWineForceFeedbackEffectImpl_iface) );
+        return S_OK;
+    }
+
+    if (IsEqualGUID( iid, &IID_IForceFeedbackEffect ))
+    {
+        IInspectable_AddRef( (*out = &impl->IForceFeedbackEffect_iface) );
+        return S_OK;
+    }
+
+    FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) );
+    *out = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI effect_impl_AddRef( IWineForceFeedbackEffectImpl *iface )
+{
+    struct effect *impl = impl_from_IWineForceFeedbackEffectImpl( iface );
+    ULONG ref = InterlockedIncrement( &impl->ref );
+    TRACE( "iface %p increasing refcount to %lu.\n", iface, ref );
+    return ref;
+}
+
+static ULONG WINAPI effect_impl_Release( IWineForceFeedbackEffectImpl *iface )
+{
+    struct effect *impl = impl_from_IWineForceFeedbackEffectImpl( iface );
+    ULONG ref = InterlockedDecrement( &impl->ref );
+
+    TRACE( "iface %p decreasing refcount to %lu.\n", iface, ref );
+
+    if (!ref) free( impl );
+
+    return ref;
+}
+
+static const struct IWineForceFeedbackEffectImplVtbl effect_impl_vtbl =
+{
+    effect_impl_QueryInterface,
+    effect_impl_AddRef,
+    effect_impl_Release,
+    /* IWineForceFeedbackEffectImpl methods */
+};
+
+DEFINE_IINSPECTABLE_OUTER( effect, IForceFeedbackEffect, struct effect, IInspectable_outer )
+
+static HRESULT WINAPI effect_get_Gain( IForceFeedbackEffect *iface, DOUBLE *value )
+{
+    FIXME( "iface %p, value %p stub!\n", iface, value );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI effect_put_Gain( IForceFeedbackEffect *iface, DOUBLE value )
+{
+    FIXME( "iface %p, value %f stub!\n", iface, value );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI effect_get_State( IForceFeedbackEffect *iface, ForceFeedbackEffectState *value )
+{
+    FIXME( "iface %p, value %p stub!\n", iface, value );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI effect_Start( IForceFeedbackEffect *iface )
+{
+    FIXME( "iface %p stub!\n", iface );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI effect_Stop( IForceFeedbackEffect *iface )
+{
+    FIXME( "iface %p stub!\n", iface );
+    return E_NOTIMPL;
+}
+
+static const struct IForceFeedbackEffectVtbl effect_vtbl =
+{
+    effect_QueryInterface,
+    effect_AddRef,
+    effect_Release,
+    /* IInspectable methods */
+    effect_GetIids,
+    effect_GetRuntimeClassName,
+    effect_GetTrustLevel,
+    /* IForceFeedbackEffect methods */
+    effect_get_Gain,
+    effect_put_Gain,
+    effect_get_State,
+    effect_Start,
+    effect_Stop,
+};
+
+HRESULT force_feedback_effect_create( IInspectable *outer, IWineForceFeedbackEffectImpl **out )
+{
+    struct effect *impl;
+
+    TRACE( "outer %p, out %p\n", outer, out );
+
+    if (!(impl = calloc( 1, sizeof(*impl) ))) return E_OUTOFMEMORY;
+    impl->IWineForceFeedbackEffectImpl_iface.lpVtbl = &effect_impl_vtbl;
+    impl->IForceFeedbackEffect_iface.lpVtbl = &effect_vtbl;
+    impl->IInspectable_outer = outer;
+    impl->ref = 1;
+
+    *out = &impl->IWineForceFeedbackEffectImpl_iface;
+    TRACE( "created ForceFeedbackEffect %p\n", *out );
+    return S_OK;
+}
+
 struct motor
 {
     IForceFeedbackMotor IForceFeedbackMotor_iface;
diff --git a/dlls/windows.gaming.input/private.h b/dlls/windows.gaming.input/private.h
index 9bbaae5554b..f8edff61455 100644
--- a/dlls/windows.gaming.input/private.h
+++ b/dlls/windows.gaming.input/private.h
@@ -42,6 +42,8 @@
 #include "wine/debug.h"
 #include "wine/list.h"
 
+#include "provider.h"
+
 extern HINSTANCE windows_gaming_input;
 extern ICustomGameControllerFactory *controller_factory;
 extern ICustomGameControllerFactory *gamepad_factory;
@@ -69,6 +71,7 @@ extern HRESULT event_handlers_remove( struct list *list, EventRegistrationToken
 extern void event_handlers_notify( struct list *list, IInspectable *element );
 
 extern HRESULT force_feedback_motor_create( IDirectInputDevice8W *device, IForceFeedbackMotor **out );
+extern HRESULT force_feedback_effect_create( enum WineForceFeedbackEffectType type, IInspectable *outer, IWineForceFeedbackEffectImpl **out );
 
 typedef HRESULT (WINAPI *async_operation_callback)( IUnknown *invoker, IUnknown *param, PROPVARIANT *result );
 extern HRESULT async_operation_boolean_create( IUnknown *invoker, IUnknown *param, async_operation_callback callback,
diff --git a/dlls/windows.gaming.input/provider.idl b/dlls/windows.gaming.input/provider.idl
index af5fbff05df..fbfa15f4100 100644
--- a/dlls/windows.gaming.input/provider.idl
+++ b/dlls/windows.gaming.input/provider.idl
@@ -34,6 +34,7 @@ import "windows.gaming.input.forcefeedback.idl";
 
 namespace Windows.Gaming.Input.Custom {
     typedef enum WineGameControllerType WineGameControllerType;
+    typedef enum WineForceFeedbackEffectType WineForceFeedbackEffectType;
     typedef struct WineGameControllerState WineGameControllerState;
     typedef struct WineGameControllerVibration WineGameControllerVibration;
     interface IWineGameControllerProvider;
@@ -49,6 +50,11 @@ namespace Windows.Gaming.Input.Custom {
         RacingWheel = 2,
     };
 
+    enum WineForceFeedbackEffectType
+    {
+        Constant = 1,
+    };
+
     struct WineGameControllerState
     {
         UINT64 timestamp;
@@ -94,6 +100,14 @@ namespace Windows.Gaming.Input.Custom {
         [propget] HRESULT ForceFeedbackMotor([out, retval] Windows.Gaming.Input.ForceFeedback.ForceFeedbackMotor **motor);
     }
 
+    [
+        uuid(27833469-7760-417e-adbe-e011a66e16ee)
+    ]
+    interface IWineForceFeedbackEffectImpl : IUnknown
+        requires Windows.Gaming.Input.ForceFeedback.IForceFeedbackEffect
+    {
+    }
+
     [
         uuid(83f377ee-c799-11ec-9d64-0242ac120002)
     ]
-- 
GitLab


https://gitlab.winehq.org/wine/wine/-/merge_requests/62



More information about the wine-devel mailing list