From: Paul Gofman pgofman@codeweavers.com
--- dlls/windows.gaming.input/async.c | 62 ++++++++++++--------- dlls/windows.gaming.input/async_private.idl | 2 +- dlls/windows.gaming.input/force_feedback.c | 20 +++++-- 3 files changed, 51 insertions(+), 33 deletions(-)
diff --git a/dlls/windows.gaming.input/async.c b/dlls/windows.gaming.input/async.c index bf356eabbab..7ac73faf3d6 100644 --- a/dlls/windows.gaming.input/async.c +++ b/dlls/windows.gaming.input/async.c @@ -175,6 +175,39 @@ static HRESULT WINAPI async_impl_get_Result( IAsyncInfoImpl *iface, PROPVARIANT return hr; }
+static BOOL async_info_complete( struct async_info *impl, BOOL called_async ) +{ + IInspectable *operation = impl->IInspectable_outer; + PROPVARIANT result = {0}; + HRESULT hr; + + hr = impl->callback( impl->invoker, impl->param, &result, called_async ); + if (!called_async && hr == STATUS_PENDING) return FALSE; + + EnterCriticalSection( &impl->cs ); + if (impl->status != Closed) impl->status = FAILED(hr) ? Error : Completed; + PropVariantCopy( &impl->result, &result ); + impl->hr = hr; + + if (impl->handler != NULL && impl->handler != HANDLER_NOT_SET) + { + IAsyncOperationCompletedHandlerImpl *handler = impl->handler; + AsyncStatus status = impl->status; + impl->handler = NULL; /* Prevent concurrent invoke. */ + LeaveCriticalSection( &impl->cs ); + + IAsyncOperationCompletedHandlerImpl_Invoke( handler, operation, status ); + IAsyncOperationCompletedHandlerImpl_Release( handler ); + } + else LeaveCriticalSection( &impl->cs ); + + /* release refcount acquired in Start */ + IInspectable_Release( operation ); + + PropVariantClear( &result ); + return TRUE; +} + static HRESULT WINAPI async_impl_Start( IAsyncInfoImpl *iface ) { struct async_info *impl = impl_from_IAsyncInfoImpl( iface ); @@ -183,7 +216,7 @@ static HRESULT WINAPI async_impl_Start( IAsyncInfoImpl *iface )
/* keep the async alive in the callback */ IInspectable_AddRef( impl->IInspectable_outer ); - SubmitThreadpoolWork( impl->async_run_work ); + if (!async_info_complete( impl, FALSE )) SubmitThreadpoolWork( impl->async_run_work );
return S_OK; } @@ -305,33 +338,8 @@ static const struct IAsyncInfoVtbl async_info_vtbl = static void CALLBACK async_info_callback( TP_CALLBACK_INSTANCE *instance, void *iface, TP_WORK *work ) { struct async_info *impl = impl_from_IAsyncInfoImpl( iface ); - IInspectable *operation = impl->IInspectable_outer; - PROPVARIANT result = {0}; - HRESULT hr; - - hr = impl->callback( impl->invoker, impl->param, &result ); - - EnterCriticalSection( &impl->cs ); - if (impl->status != Closed) impl->status = FAILED(hr) ? Error : Completed; - PropVariantCopy( &impl->result, &result ); - impl->hr = hr;
- if (impl->handler != NULL && impl->handler != HANDLER_NOT_SET) - { - IAsyncOperationCompletedHandlerImpl *handler = impl->handler; - AsyncStatus status = impl->status; - impl->handler = NULL; /* Prevent concurrent invoke. */ - LeaveCriticalSection( &impl->cs ); - - IAsyncOperationCompletedHandlerImpl_Invoke( handler, operation, status ); - IAsyncOperationCompletedHandlerImpl_Release( handler ); - } - else LeaveCriticalSection( &impl->cs ); - - /* release refcount acquired in Start */ - IInspectable_Release( operation ); - - PropVariantClear( &result ); + async_info_complete( impl, TRUE ); }
static HRESULT async_info_create( IUnknown *invoker, IUnknown *param, async_operation_callback callback, diff --git a/dlls/windows.gaming.input/async_private.idl b/dlls/windows.gaming.input/async_private.idl index 10741572601..40ea63ca4c1 100644 --- a/dlls/windows.gaming.input/async_private.idl +++ b/dlls/windows.gaming.input/async_private.idl @@ -42,5 +42,5 @@ namespace Wine.Internal { HRESULT Start(); }
- typedef HRESULT (*async_operation_callback)( IUnknown *invoker, IUnknown *param, PROPVARIANT *result ); + typedef HRESULT (*async_operation_callback)( IUnknown *invoker, IUnknown *param, PROPVARIANT *result, BOOL called_async ); } diff --git a/dlls/windows.gaming.input/force_feedback.c b/dlls/windows.gaming.input/force_feedback.c index a8631e60c4a..4fb9f09c6ff 100644 --- a/dlls/windows.gaming.input/force_feedback.c +++ b/dlls/windows.gaming.input/force_feedback.c @@ -601,7 +601,7 @@ static HRESULT WINAPI motor_get_SupportedAxes( IForceFeedbackMotor *iface, enum return hr; }
-static HRESULT motor_load_effect_async( IUnknown *invoker, IUnknown *param, PROPVARIANT *result ) +static HRESULT motor_load_effect_async( IUnknown *invoker, IUnknown *param, PROPVARIANT *result, BOOL called_async ) { struct effect *effect = impl_from_IForceFeedbackEffect( (IForceFeedbackEffect *)param ); IForceFeedbackMotor *motor = (IForceFeedbackMotor *)invoker; @@ -610,6 +610,8 @@ static HRESULT motor_load_effect_async( IUnknown *invoker, IUnknown *param, PROP IDirectInputEffect *dinput_effect; HRESULT hr;
+ if (!called_async) return STATUS_PENDING; + EnterCriticalSection( &effect->cs );
if (FAILED(hr = IForceFeedbackMotor_get_SupportedAxes( motor, &supported_axes ))) @@ -692,11 +694,13 @@ static HRESULT WINAPI motor_StopAllEffects( IForceFeedbackMotor *iface ) return IDirectInputDevice8_SendForceFeedbackCommand( impl->device, DISFFC_STOPALL ); }
-static HRESULT motor_try_disable_async( IUnknown *invoker, IUnknown *param, PROPVARIANT *result ) +static HRESULT motor_try_disable_async( IUnknown *invoker, IUnknown *param, PROPVARIANT *result, BOOL called_async ) { struct motor *impl = impl_from_IForceFeedbackMotor( (IForceFeedbackMotor *)invoker ); HRESULT hr;
+ if (!called_async) return STATUS_PENDING; + hr = IDirectInputDevice8_SendForceFeedbackCommand( impl->device, DISFFC_SETACTUATORSOFF ); result->vt = VT_BOOL; result->boolVal = SUCCEEDED(hr); @@ -710,11 +714,13 @@ static HRESULT WINAPI motor_TryDisableAsync( IForceFeedbackMotor *iface, IAsyncO return async_operation_boolean_create( (IUnknown *)iface, NULL, motor_try_disable_async, async_op ); }
-static HRESULT motor_try_enable_async( IUnknown *invoker, IUnknown *param, PROPVARIANT *result ) +static HRESULT motor_try_enable_async( IUnknown *invoker, IUnknown *param, PROPVARIANT *result, BOOL called_async ) { struct motor *impl = impl_from_IForceFeedbackMotor( (IForceFeedbackMotor *)invoker ); HRESULT hr;
+ if (!called_async) return STATUS_PENDING; + hr = IDirectInputDevice8_SendForceFeedbackCommand( impl->device, DISFFC_SETACTUATORSON ); result->vt = VT_BOOL; result->boolVal = SUCCEEDED(hr); @@ -728,11 +734,13 @@ static HRESULT WINAPI motor_TryEnableAsync( IForceFeedbackMotor *iface, IAsyncOp return async_operation_boolean_create( (IUnknown *)iface, NULL, motor_try_enable_async, async_op ); }
-static HRESULT motor_try_reset_async( IUnknown *invoker, IUnknown *param, PROPVARIANT *result ) +static HRESULT motor_try_reset_async( IUnknown *invoker, IUnknown *param, PROPVARIANT *result, BOOL called_async ) { struct motor *impl = impl_from_IForceFeedbackMotor( (IForceFeedbackMotor *)invoker ); HRESULT hr;
+ if (!called_async) return STATUS_PENDING; + hr = IDirectInputDevice8_SendForceFeedbackCommand( impl->device, DISFFC_RESET ); result->vt = VT_BOOL; result->boolVal = SUCCEEDED(hr); @@ -746,12 +754,14 @@ static HRESULT WINAPI motor_TryResetAsync( IForceFeedbackMotor *iface, IAsyncOpe return async_operation_boolean_create( (IUnknown *)iface, NULL, motor_try_reset_async, async_op ); }
-static HRESULT motor_unload_effect_async( IUnknown *iface, IUnknown *param, PROPVARIANT *result ) +static HRESULT motor_unload_effect_async( IUnknown *iface, IUnknown *param, PROPVARIANT *result, BOOL called_async ) { struct effect *effect = impl_from_IForceFeedbackEffect( (IForceFeedbackEffect *)param ); IDirectInputEffect *dinput_effect; HRESULT hr;
+ if (!called_async) return STATUS_PENDING; + EnterCriticalSection( &effect->cs ); dinput_effect = effect->effect; effect->effect = NULL;