[PATCH 4/5] windows.gaming.input: Split IAsyncInfo interface to a separate struct.
Rémi Bernon
wine at gitlab.winehq.org
Wed May 4 04:34:03 CDT 2022
From: Rémi Bernon <rbernon at codeweavers.com>
Signed-off-by: Rémi Bernon <rbernon at 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)
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/33
More information about the wine-devel
mailing list