[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