From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/windows.gaming.input/force_feedback.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/dlls/windows.gaming.input/force_feedback.c b/dlls/windows.gaming.input/force_feedback.c index a9a875c48e3..24810d1d787 100644 --- a/dlls/windows.gaming.input/force_feedback.c +++ b/dlls/windows.gaming.input/force_feedback.c @@ -111,11 +111,10 @@ static HRESULT WINAPI motor_get_AreEffectsPaused( IForceFeedbackMotor *iface, BO
TRACE( "iface %p, value %p.\n", iface, value );
- if (FAILED(hr = IDirectInputDevice8_GetForceFeedbackState( impl->device, &state ))) - return hr; + if (FAILED(hr = IDirectInputDevice8_GetForceFeedbackState( impl->device, &state ))) *value = FALSE; + else *value = (state & DIGFFS_PAUSED);
- *value = (state & DIGFFS_PAUSED); - return S_OK; + return hr; }
static HRESULT WINAPI motor_get_MasterGain( IForceFeedbackMotor *iface, double *value )
From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/windows.gaming.input/async.c | 23 +++++++++++++---------- dlls/windows.gaming.input/provider.idl | 3 +++ 2 files changed, 16 insertions(+), 10 deletions(-)
diff --git a/dlls/windows.gaming.input/async.c b/dlls/windows.gaming.input/async.c index 91ecdeb9550..6afbca96831 100644 --- a/dlls/windows.gaming.input/async.c +++ b/dlls/windows.gaming.input/async.c @@ -19,6 +19,7 @@ */
#include "private.h" +#include "provider.h"
#include "wine/debug.h"
@@ -33,7 +34,6 @@ struct async_bool IAsyncInfo IAsyncInfo_iface; LONG ref;
- IAsyncOperationCompletedHandler_boolean *handler; BOOLEAN result;
async_operation_boolean_callback callback; @@ -41,6 +41,7 @@ struct async_bool IInspectable *invoker;
CRITICAL_SECTION cs; + IWineAsyncOperationCompletedHandler *handler; AsyncStatus status; HRESULT hr; }; @@ -195,7 +196,7 @@ static ULONG WINAPI async_bool_Release( IAsyncOperation_boolean *iface ) if (!ref) { IAsyncInfo_Close( &impl->IAsyncInfo_iface ); - if (impl->handler && impl->handler != HANDLER_NOT_SET) IAsyncOperationCompletedHandler_boolean_Release( impl->handler ); + if (impl->handler && impl->handler != HANDLER_NOT_SET) IWineAsyncOperationCompletedHandler_Release( impl->handler ); IInspectable_Release( impl->invoker ); DeleteCriticalSection( &impl->cs ); free( impl ); @@ -223,8 +224,9 @@ static HRESULT WINAPI async_bool_GetTrustLevel( IAsyncOperation_boolean *iface, return E_NOTIMPL; }
-static HRESULT WINAPI async_bool_put_Completed( IAsyncOperation_boolean *iface, IAsyncOperationCompletedHandler_boolean *handler ) +static HRESULT WINAPI async_bool_put_Completed( IAsyncOperation_boolean *iface, IAsyncOperationCompletedHandler_boolean *bool_handler ) { + IWineAsyncOperationCompletedHandler *handler = (IWineAsyncOperationCompletedHandler *)bool_handler; struct async_bool *impl = impl_from_IAsyncOperation_boolean( iface ); HRESULT hr = S_OK;
@@ -235,7 +237,7 @@ static HRESULT WINAPI async_bool_put_Completed( IAsyncOperation_boolean *iface, else if (impl->handler != HANDLER_NOT_SET) hr = E_ILLEGAL_DELEGATE_ASSIGNMENT; else if ((impl->handler = handler)) { - IAsyncOperationCompletedHandler_boolean_AddRef( impl->handler ); + IWineAsyncOperationCompletedHandler_AddRef( impl->handler );
if (impl->status > Started) { @@ -244,8 +246,8 @@ static HRESULT WINAPI async_bool_put_Completed( IAsyncOperation_boolean *iface, impl->handler = NULL; /* Prevent concurrent invoke. */ LeaveCriticalSection( &impl->cs );
- IAsyncOperationCompletedHandler_boolean_Invoke( handler, operation, status ); - IAsyncOperationCompletedHandler_boolean_Release( handler ); + IWineAsyncOperationCompletedHandler_Invoke( handler, (IInspectable *)operation, status ); + IWineAsyncOperationCompletedHandler_Release( handler );
return S_OK; } @@ -255,8 +257,9 @@ static HRESULT WINAPI async_bool_put_Completed( IAsyncOperation_boolean *iface, return hr; }
-static HRESULT WINAPI async_bool_get_Completed( IAsyncOperation_boolean *iface, IAsyncOperationCompletedHandler_boolean **handler ) +static HRESULT WINAPI async_bool_get_Completed( IAsyncOperation_boolean *iface, IAsyncOperationCompletedHandler_boolean **bool_handler ) { + IWineAsyncOperationCompletedHandler **handler = (IWineAsyncOperationCompletedHandler **)bool_handler; struct async_bool *impl = impl_from_IAsyncOperation_boolean( iface ); HRESULT hr = S_OK;
@@ -321,13 +324,13 @@ static void CALLBACK async_run_cb( TP_CALLBACK_INSTANCE *instance, void *data, T
if (impl->handler != NULL && impl->handler != HANDLER_NOT_SET) { - IAsyncOperationCompletedHandler_boolean *handler = impl->handler; + IWineAsyncOperationCompletedHandler *handler = impl->handler; AsyncStatus status = impl->status; impl->handler = NULL; /* Prevent concurrent invoke. */ LeaveCriticalSection( &impl->cs );
- IAsyncOperationCompletedHandler_boolean_Invoke( handler, operation, status ); - IAsyncOperationCompletedHandler_boolean_Release( handler ); + IWineAsyncOperationCompletedHandler_Invoke( handler, (IInspectable *)operation, status ); + IWineAsyncOperationCompletedHandler_Release( handler ); } else LeaveCriticalSection( &impl->cs );
diff --git a/dlls/windows.gaming.input/provider.idl b/dlls/windows.gaming.input/provider.idl index 60eaab34506..5f718cb167b 100644 --- a/dlls/windows.gaming.input/provider.idl +++ b/dlls/windows.gaming.input/provider.idl @@ -38,6 +38,9 @@ namespace Windows.Gaming.Input.Custom { interface IWineGameControllerProvider; runtimeclass WineGameControllerProvider;
+ /* type-pruning version of AsyncOperationCompletedHandler<T> */ + delegate HRESULT WineAsyncOperationCompletedHandler([in] IInspectable *async, [in] AsyncStatus status); + enum WineGameControllerType { Joystick = 0,
From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/windows.gaming.input/async.c | 22 +++++++++++++++------- dlls/windows.gaming.input/force_feedback.c | 15 +++++++++------ dlls/windows.gaming.input/private.h | 4 ++-- 3 files changed, 26 insertions(+), 15 deletions(-)
diff --git a/dlls/windows.gaming.input/async.c b/dlls/windows.gaming.input/async.c index 6afbca96831..cce2729f06b 100644 --- a/dlls/windows.gaming.input/async.c +++ b/dlls/windows.gaming.input/async.c @@ -34,14 +34,13 @@ struct async_bool IAsyncInfo IAsyncInfo_iface; LONG ref;
- BOOLEAN result; - - async_operation_boolean_callback callback; + async_operation_callback callback; TP_WORK *async_run_work; IInspectable *invoker;
CRITICAL_SECTION cs; IWineAsyncOperationCompletedHandler *handler; + PROPVARIANT result; AsyncStatus status; HRESULT hr; }; @@ -197,6 +196,7 @@ static ULONG WINAPI async_bool_Release( IAsyncOperation_boolean *iface ) { IAsyncInfo_Close( &impl->IAsyncInfo_iface ); if (impl->handler && impl->handler != HANDLER_NOT_SET) IWineAsyncOperationCompletedHandler_Release( impl->handler ); + PropVariantClear( &impl->result ); IInspectable_Release( impl->invoker ); DeleteCriticalSection( &impl->cs ); free( impl ); @@ -276,19 +276,24 @@ static HRESULT WINAPI async_bool_get_Completed( IAsyncOperation_boolean *iface, static HRESULT WINAPI async_bool_GetResults( IAsyncOperation_boolean *iface, BOOLEAN *results ) { struct async_bool *impl = impl_from_IAsyncOperation_boolean( iface ); + PROPVARIANT result = {.vt = VT_BOOL}; HRESULT hr;
TRACE( "iface %p, results %p.\n", iface, results );
EnterCriticalSection( &impl->cs ); if (impl->status != Completed && impl->status != Error) hr = E_ILLEGAL_METHOD_CALL; + else if (impl->result.vt != result.vt) hr = E_UNEXPECTED; else { - *results = impl->result; + PropVariantCopy( &result, &impl->result ); + if (impl->result.vt == VT_UNKNOWN) PropVariantClear( &impl->result ); hr = impl->hr; } LeaveCriticalSection( &impl->cs );
+ *results = result.boolVal; + PropVariantClear( &result ); return hr; }
@@ -312,14 +317,15 @@ static void CALLBACK async_run_cb( TP_CALLBACK_INSTANCE *instance, void *data, T { IAsyncOperation_boolean *operation = data; struct async_bool *impl = impl_from_IAsyncOperation_boolean( operation ); - BOOLEAN result = FALSE; + PROPVARIANT result; HRESULT hr;
+ PropVariantInit( &result ); hr = impl->callback( impl->invoker, &result );
EnterCriticalSection( &impl->cs ); if (impl->status != Closed) impl->status = FAILED(hr) ? Error : Completed; - impl->result = result; + PropVariantCopy( &impl->result, &result ); impl->hr = hr;
if (impl->handler != NULL && impl->handler != HANDLER_NOT_SET) @@ -335,9 +341,10 @@ static void CALLBACK async_run_cb( TP_CALLBACK_INSTANCE *instance, void *data, T else LeaveCriticalSection( &impl->cs );
IAsyncOperation_boolean_Release( operation ); + PropVariantClear( &result ); }
-HRESULT async_operation_boolean_create( IInspectable *invoker, async_operation_boolean_callback callback, +HRESULT async_operation_boolean_create( IInspectable *invoker, async_operation_callback callback, IAsyncOperation_boolean **out ) { struct async_bool *impl; @@ -351,6 +358,7 @@ HRESULT async_operation_boolean_create( IInspectable *invoker, async_operation_b impl->handler = HANDLER_NOT_SET; impl->callback = callback; impl->status = Started; + impl->result.vt = VT_BOOL;
if (!(impl->async_run_work = CreateThreadpoolWork( async_run_cb, &impl->IAsyncOperation_boolean_iface, NULL ))) { diff --git a/dlls/windows.gaming.input/force_feedback.c b/dlls/windows.gaming.input/force_feedback.c index 24810d1d787..667c6d8d81b 100644 --- a/dlls/windows.gaming.input/force_feedback.c +++ b/dlls/windows.gaming.input/force_feedback.c @@ -212,13 +212,14 @@ static HRESULT WINAPI motor_StopAllEffects( IForceFeedbackMotor *iface ) return IDirectInputDevice8_SendForceFeedbackCommand( impl->device, DISFFC_STOPALL ); }
-static HRESULT WINAPI motor_try_disable_async( IInspectable *iface, BOOLEAN *result ) +static HRESULT WINAPI motor_try_disable_async( IInspectable *iface, PROPVARIANT *result ) { struct motor *impl = impl_from_IForceFeedbackMotor( (IForceFeedbackMotor *)iface ); HRESULT hr;
hr = IDirectInputDevice8_SendForceFeedbackCommand( impl->device, DISFFC_SETACTUATORSOFF ); - *result = SUCCEEDED(hr); + result->vt = VT_BOOL; + result->boolVal = SUCCEEDED(hr);
return hr; } @@ -229,13 +230,14 @@ static HRESULT WINAPI motor_TryDisableAsync( IForceFeedbackMotor *iface, IAsyncO return async_operation_boolean_create( (IInspectable *)iface, motor_try_disable_async, async_op ); }
-static HRESULT WINAPI motor_try_enable_async( IInspectable *iface, BOOLEAN *result ) +static HRESULT WINAPI motor_try_enable_async( IInspectable *iface, PROPVARIANT *result ) { struct motor *impl = impl_from_IForceFeedbackMotor( (IForceFeedbackMotor *)iface ); HRESULT hr;
hr = IDirectInputDevice8_SendForceFeedbackCommand( impl->device, DISFFC_SETACTUATORSON ); - *result = SUCCEEDED(hr); + result->vt = VT_BOOL; + result->boolVal = SUCCEEDED(hr);
return hr; } @@ -246,13 +248,14 @@ static HRESULT WINAPI motor_TryEnableAsync( IForceFeedbackMotor *iface, IAsyncOp return async_operation_boolean_create( (IInspectable *)iface, motor_try_enable_async, async_op ); }
-static HRESULT WINAPI motor_try_reset_async( IInspectable *iface, BOOLEAN *result ) +static HRESULT WINAPI motor_try_reset_async( IInspectable *iface, PROPVARIANT *result ) { struct motor *impl = impl_from_IForceFeedbackMotor( (IForceFeedbackMotor *)iface ); HRESULT hr;
hr = IDirectInputDevice8_SendForceFeedbackCommand( impl->device, DISFFC_RESET ); - *result = SUCCEEDED(hr); + result->vt = VT_BOOL; + result->boolVal = SUCCEEDED(hr);
return hr; } diff --git a/dlls/windows.gaming.input/private.h b/dlls/windows.gaming.input/private.h index 2c25aca9027..63c9c262f7a 100644 --- a/dlls/windows.gaming.input/private.h +++ b/dlls/windows.gaming.input/private.h @@ -67,8 +67,8 @@ extern void event_handlers_notify( struct list *list, IInspectable *element );
extern HRESULT force_feedback_motor_create( IDirectInputDevice8W *device, IForceFeedbackMotor **out );
-typedef HRESULT (WINAPI *async_operation_boolean_callback)( IInspectable *invoker, BOOLEAN *result ); -extern HRESULT async_operation_boolean_create( IInspectable *invoker, async_operation_boolean_callback callback, +typedef HRESULT (WINAPI *async_operation_callback)( IInspectable *invoker, PROPVARIANT *result ); +extern HRESULT async_operation_boolean_create( IInspectable *invoker, async_operation_callback callback, IAsyncOperation_boolean **out );
#define DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from, iface_mem, expr ) \
From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/windows.gaming.input/async.c | 350 +++++++++++++++++-------- dlls/windows.gaming.input/provider.idl | 12 + 2 files changed, 246 insertions(+), 116 deletions(-)
diff --git a/dlls/windows.gaming.input/async.c b/dlls/windows.gaming.input/async.c index cce2729f06b..f21e749cee6 100644 --- a/dlls/windows.gaming.input/async.c +++ b/dlls/windows.gaming.input/async.c @@ -28,10 +28,11 @@ WINE_DEFAULT_DEBUG_CHANNEL(input); #define Closed 4 #define HANDLER_NOT_SET ((void *)~(ULONG_PTR)0)
-struct async_bool +struct async_info { - IAsyncOperation_boolean IAsyncOperation_boolean_iface; + IWineAsyncInfoImpl IWineAsyncInfoImpl_iface; IAsyncInfo IAsyncInfo_iface; + IInspectable *IInspectable_outer; LONG ref;
async_operation_callback callback; @@ -45,11 +46,159 @@ struct async_bool HRESULT hr; };
-DEFINE_IINSPECTABLE( async_info, IAsyncInfo, struct async_bool, IAsyncOperation_boolean_iface ) +static inline struct async_info *impl_from_IWineAsyncInfoImpl( IWineAsyncInfoImpl *iface ) +{ + return CONTAINING_RECORD( iface, struct async_info, IWineAsyncInfoImpl_iface ); +} + +static HRESULT WINAPI async_impl_QueryInterface( IWineAsyncInfoImpl *iface, REFIID iid, void **out ) +{ + struct async_info *impl = impl_from_IWineAsyncInfoImpl( 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_IWineAsyncInfoImpl )) + { + IInspectable_AddRef( (*out = &impl->IWineAsyncInfoImpl_iface) ); + return S_OK; + } + + if (IsEqualGUID( iid, &IID_IAsyncInfo )) + { + IInspectable_AddRef( (*out = &impl->IAsyncInfo_iface) ); + return S_OK; + } + + WARN( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI async_impl_AddRef( IWineAsyncInfoImpl *iface ) +{ + struct async_info *impl = impl_from_IWineAsyncInfoImpl( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + TRACE( "iface %p, ref %lu.\n", iface, ref ); + return ref; +} + +static ULONG WINAPI async_impl_Release( IWineAsyncInfoImpl *iface ) +{ + struct async_info *impl = impl_from_IWineAsyncInfoImpl( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + TRACE( "iface %p, ref %lu.\n", iface, ref ); + + if (!ref) + { + if (impl->handler && impl->handler != HANDLER_NOT_SET) IWineAsyncOperationCompletedHandler_Release( impl->handler ); + IAsyncInfo_Close( &impl->IAsyncInfo_iface ); + IInspectable_Release( impl->invoker ); + DeleteCriticalSection( &impl->cs ); + free( impl ); + } + + return ref; +} + +static HRESULT WINAPI async_impl_put_Completed( IWineAsyncInfoImpl *iface, IWineAsyncOperationCompletedHandler *handler ) +{ + struct async_info *impl = impl_from_IWineAsyncInfoImpl( iface ); + HRESULT hr = S_OK; + + TRACE( "iface %p, handler %p.\n", iface, handler ); + + EnterCriticalSection( &impl->cs ); + if (impl->status == Closed) hr = E_ILLEGAL_METHOD_CALL; + else if (impl->handler != HANDLER_NOT_SET) hr = E_ILLEGAL_DELEGATE_ASSIGNMENT; + else if ((impl->handler = handler)) + { + IWineAsyncOperationCompletedHandler_AddRef( impl->handler ); + + if (impl->status > Started) + { + IInspectable *operation = impl->IInspectable_outer; + AsyncStatus status = impl->status; + impl->handler = NULL; /* Prevent concurrent invoke. */ + LeaveCriticalSection( &impl->cs ); + + IWineAsyncOperationCompletedHandler_Invoke( handler, operation, status ); + IWineAsyncOperationCompletedHandler_Release( handler ); + + return S_OK; + } + } + LeaveCriticalSection( &impl->cs ); + + return hr; +} + +static HRESULT WINAPI async_impl_get_Completed( IWineAsyncInfoImpl *iface, IWineAsyncOperationCompletedHandler **handler ) +{ + struct async_info *impl = impl_from_IWineAsyncInfoImpl( iface ); + HRESULT hr = S_OK; + + TRACE( "iface %p, handler %p.\n", iface, handler ); + + EnterCriticalSection( &impl->cs ); + if (impl->status == Closed) hr = E_ILLEGAL_METHOD_CALL; + *handler = (impl->handler != HANDLER_NOT_SET) ? impl->handler : NULL; + LeaveCriticalSection( &impl->cs ); + + return hr; +} + +static HRESULT WINAPI async_impl_get_Result( IWineAsyncInfoImpl *iface, PROPVARIANT *result ) +{ + struct async_info *impl = impl_from_IWineAsyncInfoImpl( iface ); + HRESULT hr = E_ILLEGAL_METHOD_CALL; + + TRACE( "iface %p, result %p.\n", iface, result ); + + EnterCriticalSection( &impl->cs ); + if (impl->status == Completed || impl->status == Error) + { + PropVariantCopy( result, &impl->result ); + hr = impl->hr; + } + LeaveCriticalSection( &impl->cs ); + + return hr; +} + +static HRESULT WINAPI async_impl_Start( IWineAsyncInfoImpl *iface ) +{ + struct async_info *impl = impl_from_IWineAsyncInfoImpl( iface ); + + TRACE( "iface %p.\n", iface ); + + /* keep the async alive in the callback */ + IInspectable_AddRef( impl->IInspectable_outer ); + SubmitThreadpoolWork( impl->async_run_work ); + + return S_OK; +} + +static const struct IWineAsyncInfoImplVtbl async_impl_vtbl = +{ + /* IUnknown methods */ + async_impl_QueryInterface, + async_impl_AddRef, + async_impl_Release, + /* IWineAsyncInfoImpl */ + async_impl_put_Completed, + async_impl_get_Completed, + async_impl_get_Result, + async_impl_Start, +}; + +DEFINE_IINSPECTABLE_OUTER( async_info, IAsyncInfo, struct async_info, IInspectable_outer )
static HRESULT WINAPI async_info_get_Id( IAsyncInfo *iface, UINT32 *id ) { - struct async_bool *impl = impl_from_IAsyncInfo( iface ); + struct async_info *impl = impl_from_IAsyncInfo( iface ); HRESULT hr = S_OK;
TRACE( "iface %p, id %p.\n", iface, id ); @@ -64,7 +213,7 @@ static HRESULT WINAPI async_info_get_Id( IAsyncInfo *iface, UINT32 *id )
static HRESULT WINAPI async_info_get_Status( IAsyncInfo *iface, AsyncStatus *status ) { - struct async_bool *impl = impl_from_IAsyncInfo( iface ); + struct async_info *impl = impl_from_IAsyncInfo( iface ); HRESULT hr = S_OK;
TRACE( "iface %p, status %p.\n", iface, status ); @@ -79,7 +228,7 @@ static HRESULT WINAPI async_info_get_Status( IAsyncInfo *iface, AsyncStatus *sta
static HRESULT WINAPI async_info_get_ErrorCode( IAsyncInfo *iface, HRESULT *error_code ) { - struct async_bool *impl = impl_from_IAsyncInfo( iface ); + struct async_info *impl = impl_from_IAsyncInfo( iface ); HRESULT hr = S_OK;
TRACE( "iface %p, error_code %p.\n", iface, error_code ); @@ -94,7 +243,7 @@ static HRESULT WINAPI async_info_get_ErrorCode( IAsyncInfo *iface, HRESULT *erro
static HRESULT WINAPI async_info_Cancel( IAsyncInfo *iface ) { - struct async_bool *impl = impl_from_IAsyncInfo( iface ); + struct async_info *impl = impl_from_IAsyncInfo( iface ); HRESULT hr = S_OK;
TRACE( "iface %p.\n", iface ); @@ -109,7 +258,7 @@ static HRESULT WINAPI async_info_Cancel( IAsyncInfo *iface )
static HRESULT WINAPI async_info_Close( IAsyncInfo *iface ) { - struct async_bool *impl = impl_from_IAsyncInfo( iface ); + struct async_info *impl = impl_from_IAsyncInfo( iface ); HRESULT hr = S_OK;
TRACE( "iface %p.\n", iface ); @@ -146,6 +295,70 @@ static const struct IAsyncInfoVtbl async_info_vtbl = async_info_Close, };
+static void CALLBACK async_info_callback( TP_CALLBACK_INSTANCE *instance, void *iface, TP_WORK *work ) +{ + struct async_info *impl = impl_from_IWineAsyncInfoImpl( iface ); + IInspectable *operation = impl->IInspectable_outer; + PROPVARIANT result; + HRESULT hr; + + hr = impl->callback( impl->invoker, &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) + { + IWineAsyncOperationCompletedHandler *handler = impl->handler; + AsyncStatus status = impl->status; + impl->handler = NULL; /* Prevent concurrent invoke. */ + LeaveCriticalSection( &impl->cs ); + + IWineAsyncOperationCompletedHandler_Invoke( handler, operation, status ); + IWineAsyncOperationCompletedHandler_Release( handler ); + } + else LeaveCriticalSection( &impl->cs ); + + /* release refcount acquired in Start */ + IInspectable_Release( operation ); + + PropVariantClear( &result ); +} + +static HRESULT async_info_create( IInspectable *invoker, async_operation_callback callback, + IInspectable *outer, IWineAsyncInfoImpl **out ) +{ + struct async_info *impl; + + if (!(impl = calloc( 1, sizeof(struct async_info) ))) return E_OUTOFMEMORY; + impl->IWineAsyncInfoImpl_iface.lpVtbl = &async_impl_vtbl; + impl->IAsyncInfo_iface.lpVtbl = &async_info_vtbl; + impl->IInspectable_outer = outer; + impl->ref = 1; + + impl->callback = callback; + impl->handler = HANDLER_NOT_SET; + impl->status = Started; + if (!(impl->async_run_work = CreateThreadpoolWork( async_info_callback, &impl->IWineAsyncInfoImpl_iface, NULL ))) + return HRESULT_FROM_WIN32( GetLastError() ); + + IInspectable_AddRef( (impl->invoker = invoker) ); + InitializeCriticalSection( &impl->cs ); + impl->cs.DebugInfo->Spare[0] = (DWORD_PTR)( __FILE__ ": async_info.cs" ); + + *out = &impl->IWineAsyncInfoImpl_iface; + return S_OK; +} + +struct async_bool +{ + IAsyncOperation_boolean IAsyncOperation_boolean_iface; + IWineAsyncInfoImpl *IWineAsyncInfoImpl_inner; + LONG ref; +}; + static inline struct async_bool *impl_from_IAsyncOperation_boolean( IAsyncOperation_boolean *iface ) { return CONTAINING_RECORD( iface, struct async_bool, IAsyncOperation_boolean_iface ); @@ -166,15 +379,7 @@ static HRESULT WINAPI async_bool_QueryInterface( IAsyncOperation_boolean *iface, return S_OK; }
- if (IsEqualGUID( iid, &IID_IAsyncInfo )) - { - IInspectable_AddRef( (*out = &impl->IAsyncInfo_iface) ); - return S_OK; - } - - WARN( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); - *out = NULL; - return E_NOINTERFACE; + return IWineAsyncInfoImpl_QueryInterface( impl->IWineAsyncInfoImpl_inner, iid, out ); }
static ULONG WINAPI async_bool_AddRef( IAsyncOperation_boolean *iface ) @@ -188,17 +393,14 @@ static ULONG WINAPI async_bool_AddRef( IAsyncOperation_boolean *iface ) static ULONG WINAPI async_bool_Release( IAsyncOperation_boolean *iface ) { struct async_bool *impl = impl_from_IAsyncOperation_boolean( iface ); - ULONG ref = InterlockedDecrement( &impl->ref ); TRACE( "iface %p, ref %lu.\n", iface, ref );
if (!ref) { - IAsyncInfo_Close( &impl->IAsyncInfo_iface ); - if (impl->handler && impl->handler != HANDLER_NOT_SET) IWineAsyncOperationCompletedHandler_Release( impl->handler ); - PropVariantClear( &impl->result ); - IInspectable_Release( impl->invoker ); - DeleteCriticalSection( &impl->cs ); + /* guard against re-entry if inner releases an outer iface */ + InterlockedIncrement( &impl->ref ); + IWineAsyncInfoImpl_Release( impl->IWineAsyncInfoImpl_inner ); free( impl ); }
@@ -228,49 +430,16 @@ static HRESULT WINAPI async_bool_put_Completed( IAsyncOperation_boolean *iface, { IWineAsyncOperationCompletedHandler *handler = (IWineAsyncOperationCompletedHandler *)bool_handler; struct async_bool *impl = impl_from_IAsyncOperation_boolean( iface ); - HRESULT hr = S_OK; - TRACE( "iface %p, handler %p.\n", iface, handler ); - - EnterCriticalSection( &impl->cs ); - if (impl->status == Closed) hr = E_ILLEGAL_METHOD_CALL; - else if (impl->handler != HANDLER_NOT_SET) hr = E_ILLEGAL_DELEGATE_ASSIGNMENT; - else if ((impl->handler = handler)) - { - IWineAsyncOperationCompletedHandler_AddRef( impl->handler ); - - if (impl->status > Started) - { - IAsyncOperation_boolean *operation = &impl->IAsyncOperation_boolean_iface; - AsyncStatus status = impl->status; - impl->handler = NULL; /* Prevent concurrent invoke. */ - LeaveCriticalSection( &impl->cs ); - - IWineAsyncOperationCompletedHandler_Invoke( handler, (IInspectable *)operation, status ); - IWineAsyncOperationCompletedHandler_Release( handler ); - - return S_OK; - } - } - LeaveCriticalSection( &impl->cs ); - - return hr; + return IWineAsyncInfoImpl_put_Completed( impl->IWineAsyncInfoImpl_inner, (IWineAsyncOperationCompletedHandler *)handler ); }
static HRESULT WINAPI async_bool_get_Completed( IAsyncOperation_boolean *iface, IAsyncOperationCompletedHandler_boolean **bool_handler ) { IWineAsyncOperationCompletedHandler **handler = (IWineAsyncOperationCompletedHandler **)bool_handler; struct async_bool *impl = impl_from_IAsyncOperation_boolean( iface ); - HRESULT hr = S_OK; - - FIXME( "iface %p, handler %p semi stub!\n", iface, handler ); - - EnterCriticalSection( &impl->cs ); - if (impl->status == Closed) hr = E_ILLEGAL_METHOD_CALL; - *handler = (impl->handler != HANDLER_NOT_SET) ? impl->handler : NULL; - LeaveCriticalSection( &impl->cs ); - - return hr; + TRACE( "iface %p, handler %p.\n", iface, handler ); + return IWineAsyncInfoImpl_get_Completed( impl->IWineAsyncInfoImpl_inner, (IWineAsyncOperationCompletedHandler **)handler ); }
static HRESULT WINAPI async_bool_GetResults( IAsyncOperation_boolean *iface, BOOLEAN *results ) @@ -281,16 +450,7 @@ static HRESULT WINAPI async_bool_GetResults( IAsyncOperation_boolean *iface, BOO
TRACE( "iface %p, results %p.\n", iface, results );
- EnterCriticalSection( &impl->cs ); - if (impl->status != Completed && impl->status != Error) hr = E_ILLEGAL_METHOD_CALL; - else if (impl->result.vt != result.vt) hr = E_UNEXPECTED; - else - { - PropVariantCopy( &result, &impl->result ); - if (impl->result.vt == VT_UNKNOWN) PropVariantClear( &impl->result ); - hr = impl->hr; - } - LeaveCriticalSection( &impl->cs ); + hr = IWineAsyncInfoImpl_get_Result( impl->IWineAsyncInfoImpl_inner, &result );
*results = result.boolVal; PropVariantClear( &result ); @@ -313,67 +473,25 @@ static const struct IAsyncOperation_booleanVtbl async_bool_vtbl = async_bool_GetResults, };
-static void CALLBACK async_run_cb( TP_CALLBACK_INSTANCE *instance, void *data, TP_WORK *work ) -{ - IAsyncOperation_boolean *operation = data; - struct async_bool *impl = impl_from_IAsyncOperation_boolean( operation ); - PROPVARIANT result; - HRESULT hr; - - PropVariantInit( &result ); - hr = impl->callback( impl->invoker, &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) - { - IWineAsyncOperationCompletedHandler *handler = impl->handler; - AsyncStatus status = impl->status; - impl->handler = NULL; /* Prevent concurrent invoke. */ - LeaveCriticalSection( &impl->cs ); - - IWineAsyncOperationCompletedHandler_Invoke( handler, (IInspectable *)operation, status ); - IWineAsyncOperationCompletedHandler_Release( handler ); - } - else LeaveCriticalSection( &impl->cs ); - - IAsyncOperation_boolean_Release( operation ); - PropVariantClear( &result ); -} - HRESULT async_operation_boolean_create( IInspectable *invoker, async_operation_callback callback, IAsyncOperation_boolean **out ) { struct async_bool *impl; + HRESULT hr;
*out = NULL; if (!(impl = calloc( 1, sizeof(*impl) ))) return E_OUTOFMEMORY; impl->IAsyncOperation_boolean_iface.lpVtbl = &async_bool_vtbl; - impl->IAsyncInfo_iface.lpVtbl = &async_info_vtbl; impl->ref = 1;
- impl->handler = HANDLER_NOT_SET; - impl->callback = callback; - impl->status = Started; - impl->result.vt = VT_BOOL; - - if (!(impl->async_run_work = CreateThreadpoolWork( async_run_cb, &impl->IAsyncOperation_boolean_iface, NULL ))) + if (FAILED(hr = async_info_create( invoker, callback, (IInspectable *)&impl->IAsyncOperation_boolean_iface, &impl->IWineAsyncInfoImpl_inner )) || + FAILED(hr = IWineAsyncInfoImpl_Start( impl->IWineAsyncInfoImpl_inner ))) { + if (impl->IWineAsyncInfoImpl_inner) IWineAsyncInfoImpl_Release( impl->IWineAsyncInfoImpl_inner ); free( impl ); - return HRESULT_FROM_WIN32( GetLastError() ); + return hr; }
- IInspectable_AddRef( (impl->invoker = invoker) ); - InitializeCriticalSection( &impl->cs ); - impl->cs.DebugInfo->Spare[0] = (DWORD_PTR)( __FILE__ ": async_operation.cs" ); - - /* keep the async alive in the callback */ - IAsyncOperation_boolean_AddRef( &impl->IAsyncOperation_boolean_iface ); - SubmitThreadpoolWork( impl->async_run_work ); - *out = &impl->IAsyncOperation_boolean_iface; TRACE( "created IAsyncOperation_boolean %p\n", *out ); return S_OK; diff --git a/dlls/windows.gaming.input/provider.idl b/dlls/windows.gaming.input/provider.idl index 5f718cb167b..af5fbff05df 100644 --- a/dlls/windows.gaming.input/provider.idl +++ b/dlls/windows.gaming.input/provider.idl @@ -22,6 +22,7 @@ #pragma winrt ns_prefix #endif
+import "propidl.idl"; import "inspectable.idl"; import "asyncinfo.idl"; import "eventtoken.idl"; @@ -93,6 +94,17 @@ namespace Windows.Gaming.Input.Custom { [propget] HRESULT ForceFeedbackMotor([out, retval] Windows.Gaming.Input.ForceFeedback.ForceFeedbackMotor **motor); }
+ [ + uuid(83f377ee-c799-11ec-9d64-0242ac120002) + ] + interface IWineAsyncInfoImpl : IUnknown + { + [propput] HRESULT Completed([in] WineAsyncOperationCompletedHandler *handler); + [propget] HRESULT Completed([out, retval] WineAsyncOperationCompletedHandler **handler); + [propget] HRESULT Result([out, retval] PROPVARIANT *result); + HRESULT Start(); + } + [ marshaling_behavior(agile), threading(both)
From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/windows.gaming.input/async.c | 18 +++++++++++------- dlls/windows.gaming.input/force_feedback.c | 18 +++++++++--------- dlls/windows.gaming.input/private.h | 4 ++-- 3 files changed, 22 insertions(+), 18 deletions(-)
diff --git a/dlls/windows.gaming.input/async.c b/dlls/windows.gaming.input/async.c index f21e749cee6..1426b3d8481 100644 --- a/dlls/windows.gaming.input/async.c +++ b/dlls/windows.gaming.input/async.c @@ -37,7 +37,8 @@ struct async_info
async_operation_callback callback; TP_WORK *async_run_work; - IInspectable *invoker; + IUnknown *invoker; + IUnknown *param;
CRITICAL_SECTION cs; IWineAsyncOperationCompletedHandler *handler; @@ -95,7 +96,8 @@ static ULONG WINAPI async_impl_Release( IWineAsyncInfoImpl *iface ) { if (impl->handler && impl->handler != HANDLER_NOT_SET) IWineAsyncOperationCompletedHandler_Release( impl->handler ); IAsyncInfo_Close( &impl->IAsyncInfo_iface ); - IInspectable_Release( impl->invoker ); + if (impl->param) IUnknown_Release( impl->param ); + if (impl->invoker) IUnknown_Release( impl->invoker ); DeleteCriticalSection( &impl->cs ); free( impl ); } @@ -302,7 +304,7 @@ static void CALLBACK async_info_callback( TP_CALLBACK_INSTANCE *instance, void * PROPVARIANT result; HRESULT hr;
- hr = impl->callback( impl->invoker, &result ); + hr = impl->callback( impl->invoker, impl->param, &result );
EnterCriticalSection( &impl->cs ); if (impl->status != Closed) impl->status = FAILED(hr) ? Error : Completed; @@ -327,7 +329,7 @@ static void CALLBACK async_info_callback( TP_CALLBACK_INSTANCE *instance, void * PropVariantClear( &result ); }
-static HRESULT async_info_create( IInspectable *invoker, async_operation_callback callback, +static HRESULT async_info_create( IUnknown *invoker, IUnknown *param, async_operation_callback callback, IInspectable *outer, IWineAsyncInfoImpl **out ) { struct async_info *impl; @@ -344,7 +346,9 @@ static HRESULT async_info_create( IInspectable *invoker, async_operation_callbac if (!(impl->async_run_work = CreateThreadpoolWork( async_info_callback, &impl->IWineAsyncInfoImpl_iface, NULL ))) return HRESULT_FROM_WIN32( GetLastError() );
- IInspectable_AddRef( (impl->invoker = invoker) ); + if ((impl->invoker = invoker)) IUnknown_AddRef( impl->invoker ); + if ((impl->param = param)) IUnknown_AddRef( impl->param ); + InitializeCriticalSection( &impl->cs ); impl->cs.DebugInfo->Spare[0] = (DWORD_PTR)( __FILE__ ": async_info.cs" );
@@ -473,7 +477,7 @@ static const struct IAsyncOperation_booleanVtbl async_bool_vtbl = async_bool_GetResults, };
-HRESULT async_operation_boolean_create( IInspectable *invoker, async_operation_callback callback, +HRESULT async_operation_boolean_create( IUnknown *invoker, IUnknown *param, async_operation_callback callback, IAsyncOperation_boolean **out ) { struct async_bool *impl; @@ -484,7 +488,7 @@ HRESULT async_operation_boolean_create( IInspectable *invoker, async_operation_c impl->IAsyncOperation_boolean_iface.lpVtbl = &async_bool_vtbl; impl->ref = 1;
- if (FAILED(hr = async_info_create( invoker, callback, (IInspectable *)&impl->IAsyncOperation_boolean_iface, &impl->IWineAsyncInfoImpl_inner )) || + if (FAILED(hr = async_info_create( invoker, param, callback, (IInspectable *)&impl->IAsyncOperation_boolean_iface, &impl->IWineAsyncInfoImpl_inner )) || FAILED(hr = IWineAsyncInfoImpl_Start( impl->IWineAsyncInfoImpl_inner ))) { if (impl->IWineAsyncInfoImpl_inner) IWineAsyncInfoImpl_Release( impl->IWineAsyncInfoImpl_inner ); diff --git a/dlls/windows.gaming.input/force_feedback.c b/dlls/windows.gaming.input/force_feedback.c index 667c6d8d81b..3fdcc636bbd 100644 --- a/dlls/windows.gaming.input/force_feedback.c +++ b/dlls/windows.gaming.input/force_feedback.c @@ -212,9 +212,9 @@ static HRESULT WINAPI motor_StopAllEffects( IForceFeedbackMotor *iface ) return IDirectInputDevice8_SendForceFeedbackCommand( impl->device, DISFFC_STOPALL ); }
-static HRESULT WINAPI motor_try_disable_async( IInspectable *iface, PROPVARIANT *result ) +static HRESULT WINAPI motor_try_disable_async( IUnknown *invoker, IUnknown *param, PROPVARIANT *result ) { - struct motor *impl = impl_from_IForceFeedbackMotor( (IForceFeedbackMotor *)iface ); + struct motor *impl = impl_from_IForceFeedbackMotor( (IForceFeedbackMotor *)invoker ); HRESULT hr;
hr = IDirectInputDevice8_SendForceFeedbackCommand( impl->device, DISFFC_SETACTUATORSOFF ); @@ -227,12 +227,12 @@ static HRESULT WINAPI motor_try_disable_async( IInspectable *iface, PROPVARIANT static HRESULT WINAPI motor_TryDisableAsync( IForceFeedbackMotor *iface, IAsyncOperation_boolean **async_op ) { TRACE( "iface %p, async_op %p.\n", iface, async_op ); - return async_operation_boolean_create( (IInspectable *)iface, motor_try_disable_async, async_op ); + return async_operation_boolean_create( (IUnknown *)iface, NULL, motor_try_disable_async, async_op ); }
-static HRESULT WINAPI motor_try_enable_async( IInspectable *iface, PROPVARIANT *result ) +static HRESULT WINAPI motor_try_enable_async( IUnknown *invoker, IUnknown *param, PROPVARIANT *result ) { - struct motor *impl = impl_from_IForceFeedbackMotor( (IForceFeedbackMotor *)iface ); + struct motor *impl = impl_from_IForceFeedbackMotor( (IForceFeedbackMotor *)invoker ); HRESULT hr;
hr = IDirectInputDevice8_SendForceFeedbackCommand( impl->device, DISFFC_SETACTUATORSON ); @@ -245,12 +245,12 @@ static HRESULT WINAPI motor_try_enable_async( IInspectable *iface, PROPVARIANT * static HRESULT WINAPI motor_TryEnableAsync( IForceFeedbackMotor *iface, IAsyncOperation_boolean **async_op ) { TRACE( "iface %p, async_op %p.\n", iface, async_op ); - return async_operation_boolean_create( (IInspectable *)iface, motor_try_enable_async, async_op ); + return async_operation_boolean_create( (IUnknown *)iface, NULL, motor_try_enable_async, async_op ); }
-static HRESULT WINAPI motor_try_reset_async( IInspectable *iface, PROPVARIANT *result ) +static HRESULT WINAPI motor_try_reset_async( IUnknown *invoker, IUnknown *param, PROPVARIANT *result ) { - struct motor *impl = impl_from_IForceFeedbackMotor( (IForceFeedbackMotor *)iface ); + struct motor *impl = impl_from_IForceFeedbackMotor( (IForceFeedbackMotor *)invoker ); HRESULT hr;
hr = IDirectInputDevice8_SendForceFeedbackCommand( impl->device, DISFFC_RESET ); @@ -263,7 +263,7 @@ static HRESULT WINAPI motor_try_reset_async( IInspectable *iface, PROPVARIANT *r static HRESULT WINAPI motor_TryResetAsync( IForceFeedbackMotor *iface, IAsyncOperation_boolean **async_op ) { TRACE( "iface %p, async_op %p.\n", iface, async_op ); - return async_operation_boolean_create( (IInspectable *)iface, motor_try_reset_async, async_op ); + return async_operation_boolean_create( (IUnknown *)iface, NULL, motor_try_reset_async, async_op ); }
static HRESULT WINAPI motor_TryUnloadEffectAsync( IForceFeedbackMotor *iface, IForceFeedbackEffect *effect, diff --git a/dlls/windows.gaming.input/private.h b/dlls/windows.gaming.input/private.h index 63c9c262f7a..68f6bdcf5b6 100644 --- a/dlls/windows.gaming.input/private.h +++ b/dlls/windows.gaming.input/private.h @@ -67,8 +67,8 @@ extern void event_handlers_notify( struct list *list, IInspectable *element );
extern HRESULT force_feedback_motor_create( IDirectInputDevice8W *device, IForceFeedbackMotor **out );
-typedef HRESULT (WINAPI *async_operation_callback)( IInspectable *invoker, PROPVARIANT *result ); -extern HRESULT async_operation_boolean_create( IInspectable *invoker, async_operation_callback callback, +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, IAsyncOperation_boolean **out );
#define DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from, iface_mem, expr ) \