From: Rémi Bernon rbernon@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@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..58378304a26 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( 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) ]