From: Rémi Bernon rbernon@codeweavers.com
--- dlls/cryptowinrt/Makefile.in | 3 +- dlls/cryptowinrt/async.c | 340 +------------------ dlls/cryptowinrt/credentials.c | 2 +- dlls/cryptowinrt/private.h | 5 +- dlls/cryptowinrt/provider.idl | 47 --- dlls/windows.gaming.input/async.c | 342 +------------------ dlls/windows.gaming.input/force_feedback.c | 10 +- dlls/windows.gaming.input/private.h | 5 +- dlls/windows.gaming.input/provider.idl | 14 - include/wine/winrt.idl | 27 ++ libs/winewinrt/Makefile.in | 1 + libs/winewinrt/async_info.c | 361 +++++++++++++++++++++ 12 files changed, 402 insertions(+), 755 deletions(-) delete mode 100644 dlls/cryptowinrt/provider.idl create mode 100644 libs/winewinrt/async_info.c
diff --git a/dlls/cryptowinrt/Makefile.in b/dlls/cryptowinrt/Makefile.in index e58476eb6d6..0f99c556acb 100644 --- a/dlls/cryptowinrt/Makefile.in +++ b/dlls/cryptowinrt/Makefile.in @@ -7,5 +7,4 @@ C_SRCS = \ main.c
IDL_SRCS = \ - classes.idl \ - provider.idl + classes.idl diff --git a/dlls/cryptowinrt/async.c b/dlls/cryptowinrt/async.c index dbf111cc880..8fb94e88312 100644 --- a/dlls/cryptowinrt/async.c +++ b/dlls/cryptowinrt/async.c @@ -24,344 +24,6 @@
WINE_DEFAULT_DEBUG_CHANNEL(crypto);
-#define Closed 4 -#define HANDLER_NOT_SET ((void *)~(ULONG_PTR)0) - -struct async_info -{ - IWineAsyncInfoImpl IWineAsyncInfoImpl_iface; - IAsyncInfo IAsyncInfo_iface; - IInspectable *IInspectable_outer; - LONG ref; - - async_operation_callback callback; - TP_WORK *async_run_work; - IUnknown *invoker; - IUnknown *param; - - CRITICAL_SECTION cs; - IWineAsyncOperationCompletedHandler *handler; - PROPVARIANT result; - AsyncStatus status; - HRESULT hr; -}; - -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; - } - - FIXME( "%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 ); - if (impl->param) IUnknown_Release( impl->param ); - if (impl->invoker) IUnknown_Release( impl->invoker ); - impl->cs.DebugInfo->Spare[0] = 0; - 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; - if (impl->handler == NULL || impl->handler == HANDLER_NOT_SET) *handler = NULL; - else IWineAsyncOperationCompletedHandler_AddRef( (*handler = impl->handler) ); - 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_info *impl = impl_from_IAsyncInfo( iface ); - HRESULT hr = S_OK; - - TRACE( "iface %p, id %p.\n", iface, id ); - - EnterCriticalSection( &impl->cs ); - if (impl->status == Closed) hr = E_ILLEGAL_METHOD_CALL; - *id = 1; - LeaveCriticalSection( &impl->cs ); - - return hr; -} - -static HRESULT WINAPI async_info_get_Status( IAsyncInfo *iface, AsyncStatus *status ) -{ - struct async_info *impl = impl_from_IAsyncInfo( iface ); - HRESULT hr = S_OK; - - TRACE( "iface %p, status %p.\n", iface, status ); - - EnterCriticalSection( &impl->cs ); - if (impl->status == Closed) hr = E_ILLEGAL_METHOD_CALL; - *status = impl->status; - LeaveCriticalSection( &impl->cs ); - - return hr; -} - -static HRESULT WINAPI async_info_get_ErrorCode( IAsyncInfo *iface, HRESULT *error_code ) -{ - struct async_info *impl = impl_from_IAsyncInfo( iface ); - HRESULT hr = S_OK; - - TRACE( "iface %p, error_code %p.\n", iface, error_code ); - - EnterCriticalSection( &impl->cs ); - if (impl->status == Closed) *error_code = hr = E_ILLEGAL_METHOD_CALL; - else *error_code = impl->hr; - LeaveCriticalSection( &impl->cs ); - - return hr; -} - -static HRESULT WINAPI async_info_Cancel( IAsyncInfo *iface ) -{ - struct async_info *impl = impl_from_IAsyncInfo( iface ); - HRESULT hr = S_OK; - - TRACE( "iface %p.\n", iface ); - - EnterCriticalSection( &impl->cs ); - if (impl->status == Closed) hr = E_ILLEGAL_METHOD_CALL; - else if (impl->status == Started) impl->status = Canceled; - LeaveCriticalSection( &impl->cs ); - - return hr; -} - -static HRESULT WINAPI async_info_Close( IAsyncInfo *iface ) -{ - struct async_info *impl = impl_from_IAsyncInfo( iface ); - HRESULT hr = S_OK; - - TRACE( "iface %p.\n", iface ); - - EnterCriticalSection( &impl->cs ); - if (impl->status == Started) - hr = E_ILLEGAL_STATE_CHANGE; - else if (impl->status != Closed) - { - CloseThreadpoolWork( impl->async_run_work ); - impl->async_run_work = NULL; - impl->status = Closed; - } - LeaveCriticalSection( &impl->cs ); - - return hr; -} - -static const struct IAsyncInfoVtbl async_info_vtbl = -{ - /* IUnknown methods */ - async_info_QueryInterface, - async_info_AddRef, - async_info_Release, - /* IInspectable methods */ - async_info_GetIids, - async_info_GetRuntimeClassName, - async_info_GetTrustLevel, - /* IAsyncInfo */ - async_info_get_Id, - async_info_get_Status, - async_info_get_ErrorCode, - async_info_Cancel, - 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, 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) - { - 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( IUnknown *invoker, IUnknown *param, async_operation_callback callback, - IInspectable *outer, IWineAsyncInfoImpl **out ) -{ - struct async_info *impl; - HRESULT hr; - - 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 ))) - { - hr = HRESULT_FROM_WIN32( GetLastError() ); - free( impl ); - return hr; - } - - 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" ); - - *out = &impl->IWineAsyncInfoImpl_iface; - return S_OK; -} - struct async_bool { IAsyncOperation_boolean IAsyncOperation_boolean_iface; @@ -483,7 +145,7 @@ static const struct IAsyncOperation_booleanVtbl async_bool_vtbl = async_bool_GetResults, };
-HRESULT async_operation_boolean_create( IUnknown *invoker, IUnknown *param, async_operation_callback callback, +HRESULT async_operation_boolean_create( IUnknown *invoker, IUnknown *param, async_callback callback, IAsyncOperation_boolean **out ) { struct async_bool *impl; diff --git a/dlls/cryptowinrt/credentials.c b/dlls/cryptowinrt/credentials.c index e23c5d94696..960c5fabf8f 100644 --- a/dlls/cryptowinrt/credentials.c +++ b/dlls/cryptowinrt/credentials.c @@ -118,7 +118,7 @@ static const struct IActivationFactoryVtbl factory_vtbl =
DEFINE_IINSPECTABLE( credentials_statics, IKeyCredentialManagerStatics, struct credentials_statics, IActivationFactory_iface );
-static HRESULT WINAPI is_supported_async( IUnknown *invoker, IUnknown *param, PROPVARIANT *result ) +static HRESULT is_supported_async( IUnknown *invoker, IUnknown *param, PROPVARIANT *result ) { result->vt = VT_BOOL; result->boolVal = FALSE; diff --git a/dlls/cryptowinrt/private.h b/dlls/cryptowinrt/private.h index 0cc2ba507b0..e83aa41671a 100644 --- a/dlls/cryptowinrt/private.h +++ b/dlls/cryptowinrt/private.h @@ -39,12 +39,9 @@
#include "wine/winrt.h"
-#include "provider.h" - extern IActivationFactory *credentials_activation_factory;
-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, +extern HRESULT async_operation_boolean_create( IUnknown *invoker, IUnknown *param, async_callback callback, IAsyncOperation_boolean **out );
#endif diff --git a/dlls/cryptowinrt/provider.idl b/dlls/cryptowinrt/provider.idl deleted file mode 100644 index 7196119dba0..00000000000 --- a/dlls/cryptowinrt/provider.idl +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2022 Mohamad Al-Jaf - * Copyright 2022 Rémi Bernon for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#pragma makedep header - -#ifdef __WIDL__ -#pragma winrt ns_prefix -#endif - -import "propidl.idl"; -import "inspectable.idl"; -import "asyncinfo.idl"; -import "eventtoken.idl"; -import "windowscontracts.idl"; -import "windows.foundation.idl"; - -namespace Windows.Security.Credentials { - /* type-pruning version of AsyncOperationCompletedHandler<T> */ - delegate HRESULT WineAsyncOperationCompletedHandler([in] IInspectable *async, [in] AsyncStatus status); - - [ - 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(); - } -} diff --git a/dlls/windows.gaming.input/async.c b/dlls/windows.gaming.input/async.c index c41abe96cd1..0e3814d5ac4 100644 --- a/dlls/windows.gaming.input/async.c +++ b/dlls/windows.gaming.input/async.c @@ -25,344 +25,6 @@
WINE_DEFAULT_DEBUG_CHANNEL(input);
-#define Closed 4 -#define HANDLER_NOT_SET ((void *)~(ULONG_PTR)0) - -struct async_info -{ - IWineAsyncInfoImpl IWineAsyncInfoImpl_iface; - IAsyncInfo IAsyncInfo_iface; - IInspectable *IInspectable_outer; - LONG ref; - - async_operation_callback callback; - TP_WORK *async_run_work; - IUnknown *invoker; - IUnknown *param; - - CRITICAL_SECTION cs; - IWineAsyncOperationCompletedHandler *handler; - PROPVARIANT result; - AsyncStatus status; - HRESULT hr; -}; - -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; - } - - FIXME( "%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 ); - if (impl->param) IUnknown_Release( impl->param ); - if (impl->invoker) IUnknown_Release( impl->invoker ); - impl->cs.DebugInfo->Spare[0] = 0; - 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; - if (impl->handler == NULL || impl->handler == HANDLER_NOT_SET) *handler = NULL; - else IWineAsyncOperationCompletedHandler_AddRef( (*handler = impl->handler) ); - 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_info *impl = impl_from_IAsyncInfo( iface ); - HRESULT hr = S_OK; - - TRACE( "iface %p, id %p.\n", iface, id ); - - EnterCriticalSection( &impl->cs ); - if (impl->status == Closed) hr = E_ILLEGAL_METHOD_CALL; - *id = 1; - LeaveCriticalSection( &impl->cs ); - - return hr; -} - -static HRESULT WINAPI async_info_get_Status( IAsyncInfo *iface, AsyncStatus *status ) -{ - struct async_info *impl = impl_from_IAsyncInfo( iface ); - HRESULT hr = S_OK; - - TRACE( "iface %p, status %p.\n", iface, status ); - - EnterCriticalSection( &impl->cs ); - if (impl->status == Closed) hr = E_ILLEGAL_METHOD_CALL; - *status = impl->status; - LeaveCriticalSection( &impl->cs ); - - return hr; -} - -static HRESULT WINAPI async_info_get_ErrorCode( IAsyncInfo *iface, HRESULT *error_code ) -{ - struct async_info *impl = impl_from_IAsyncInfo( iface ); - HRESULT hr = S_OK; - - TRACE( "iface %p, error_code %p.\n", iface, error_code ); - - EnterCriticalSection( &impl->cs ); - if (impl->status == Closed) *error_code = hr = E_ILLEGAL_METHOD_CALL; - else *error_code = impl->hr; - LeaveCriticalSection( &impl->cs ); - - return hr; -} - -static HRESULT WINAPI async_info_Cancel( IAsyncInfo *iface ) -{ - struct async_info *impl = impl_from_IAsyncInfo( iface ); - HRESULT hr = S_OK; - - TRACE( "iface %p.\n", iface ); - - EnterCriticalSection( &impl->cs ); - if (impl->status == Closed) hr = E_ILLEGAL_METHOD_CALL; - else if (impl->status == Started) impl->status = Canceled; - LeaveCriticalSection( &impl->cs ); - - return hr; -} - -static HRESULT WINAPI async_info_Close( IAsyncInfo *iface ) -{ - struct async_info *impl = impl_from_IAsyncInfo( iface ); - HRESULT hr = S_OK; - - TRACE( "iface %p.\n", iface ); - - EnterCriticalSection( &impl->cs ); - if (impl->status == Started) - hr = E_ILLEGAL_STATE_CHANGE; - else if (impl->status != Closed) - { - CloseThreadpoolWork( impl->async_run_work ); - impl->async_run_work = NULL; - impl->status = Closed; - } - LeaveCriticalSection( &impl->cs ); - - return hr; -} - -static const struct IAsyncInfoVtbl async_info_vtbl = -{ - /* IUnknown methods */ - async_info_QueryInterface, - async_info_AddRef, - async_info_Release, - /* IInspectable methods */ - async_info_GetIids, - async_info_GetRuntimeClassName, - async_info_GetTrustLevel, - /* IAsyncInfo */ - async_info_get_Id, - async_info_get_Status, - async_info_get_ErrorCode, - async_info_Cancel, - 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, 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) - { - 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( IUnknown *invoker, IUnknown *param, async_operation_callback callback, - IInspectable *outer, IWineAsyncInfoImpl **out ) -{ - struct async_info *impl; - HRESULT hr; - - 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 ))) - { - hr = HRESULT_FROM_WIN32( GetLastError() ); - free( impl ); - return hr; - } - - 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" ); - - *out = &impl->IWineAsyncInfoImpl_iface; - return S_OK; -} - struct async_bool { IAsyncOperation_boolean IAsyncOperation_boolean_iface; @@ -484,7 +146,7 @@ static const struct IAsyncOperation_booleanVtbl async_bool_vtbl = async_bool_GetResults, };
-HRESULT async_operation_boolean_create( IUnknown *invoker, IUnknown *param, async_operation_callback callback, +HRESULT async_operation_boolean_create( IUnknown *invoker, IUnknown *param, async_callback callback, IAsyncOperation_boolean **out ) { struct async_bool *impl; @@ -627,7 +289,7 @@ static const struct IAsyncOperation_ForceFeedbackLoadEffectResultVtbl async_resu async_result_GetResults, };
-HRESULT async_operation_effect_result_create( IUnknown *invoker, IUnknown *param, async_operation_callback callback, +HRESULT async_operation_effect_result_create( IUnknown *invoker, IUnknown *param, async_callback callback, IAsyncOperation_ForceFeedbackLoadEffectResult **out ) { struct async_result *impl; diff --git a/dlls/windows.gaming.input/force_feedback.c b/dlls/windows.gaming.input/force_feedback.c index cff3c184bf9..dd2b56375cf 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 WINAPI motor_load_effect_async( IUnknown *invoker, IUnknown *param, PROPVARIANT *result ) +static HRESULT motor_load_effect_async( IUnknown *invoker, IUnknown *param, PROPVARIANT *result ) { struct effect *effect = impl_from_IForceFeedbackEffect( (IForceFeedbackEffect *)param ); IForceFeedbackMotor *motor = (IForceFeedbackMotor *)invoker; @@ -693,7 +693,7 @@ static HRESULT WINAPI motor_StopAllEffects( IForceFeedbackMotor *iface ) return IDirectInputDevice8_SendForceFeedbackCommand( impl->device, DISFFC_STOPALL ); }
-static HRESULT WINAPI motor_try_disable_async( IUnknown *invoker, IUnknown *param, PROPVARIANT *result ) +static HRESULT motor_try_disable_async( IUnknown *invoker, IUnknown *param, PROPVARIANT *result ) { struct motor *impl = impl_from_IForceFeedbackMotor( (IForceFeedbackMotor *)invoker ); HRESULT hr; @@ -711,7 +711,7 @@ static HRESULT WINAPI motor_TryDisableAsync( IForceFeedbackMotor *iface, IAsyncO return async_operation_boolean_create( (IUnknown *)iface, NULL, motor_try_disable_async, async_op ); }
-static HRESULT WINAPI motor_try_enable_async( IUnknown *invoker, IUnknown *param, PROPVARIANT *result ) +static HRESULT motor_try_enable_async( IUnknown *invoker, IUnknown *param, PROPVARIANT *result ) { struct motor *impl = impl_from_IForceFeedbackMotor( (IForceFeedbackMotor *)invoker ); HRESULT hr; @@ -729,7 +729,7 @@ static HRESULT WINAPI motor_TryEnableAsync( IForceFeedbackMotor *iface, IAsyncOp return async_operation_boolean_create( (IUnknown *)iface, NULL, motor_try_enable_async, async_op ); }
-static HRESULT WINAPI motor_try_reset_async( IUnknown *invoker, IUnknown *param, PROPVARIANT *result ) +static HRESULT motor_try_reset_async( IUnknown *invoker, IUnknown *param, PROPVARIANT *result ) { struct motor *impl = impl_from_IForceFeedbackMotor( (IForceFeedbackMotor *)invoker ); HRESULT hr; @@ -747,7 +747,7 @@ static HRESULT WINAPI motor_TryResetAsync( IForceFeedbackMotor *iface, IAsyncOpe return async_operation_boolean_create( (IUnknown *)iface, NULL, motor_try_reset_async, async_op ); }
-static HRESULT WINAPI motor_unload_effect_async( IUnknown *iface, IUnknown *param, PROPVARIANT *result ) +static HRESULT motor_unload_effect_async( IUnknown *iface, IUnknown *param, PROPVARIANT *result ) { struct effect *effect = impl_from_IForceFeedbackEffect( (IForceFeedbackEffect *)param ); IDirectInputEffect *dinput_effect; diff --git a/dlls/windows.gaming.input/private.h b/dlls/windows.gaming.input/private.h index fd1335c689a..0b0abd3f1f6 100644 --- a/dlls/windows.gaming.input/private.h +++ b/dlls/windows.gaming.input/private.h @@ -68,10 +68,9 @@ 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( enum WineForceFeedbackEffectType type, 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, +extern HRESULT async_operation_boolean_create( IUnknown *invoker, IUnknown *param, async_callback callback, IAsyncOperation_boolean **out ); -extern HRESULT async_operation_effect_result_create( IUnknown *invoker, IUnknown *param, async_operation_callback callback, +extern HRESULT async_operation_effect_result_create( IUnknown *invoker, IUnknown *param, async_callback callback, IAsyncOperation_ForceFeedbackLoadEffectResult **out );
static inline const char *debugstr_vector3( const Vector3 *vector ) diff --git a/dlls/windows.gaming.input/provider.idl b/dlls/windows.gaming.input/provider.idl index e7b6e96b8aa..ebf6cef6e4a 100644 --- a/dlls/windows.gaming.input/provider.idl +++ b/dlls/windows.gaming.input/provider.idl @@ -46,9 +46,6 @@ 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, @@ -195,17 +192,6 @@ namespace Windows.Gaming.Input.Custom { [in, optional] WineForceFeedbackEffectEnvelope *envelope); }
- [ - 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) diff --git a/include/wine/winrt.idl b/include/wine/winrt.idl index 95322875656..59a6da28ee2 100644 --- a/include/wine/winrt.idl +++ b/include/wine/winrt.idl @@ -25,6 +25,11 @@ #pragma winrt ns_prefix #endif
+import "propidl.idl"; +import "inspectable.idl"; +import "asyncinfo.idl"; +import "eventtoken.idl"; +import "windowscontracts.idl"; import "windows.foundation.idl";
struct vector_iids @@ -40,6 +45,28 @@ extern HRESULT vector_hstring_copy( Windows.Foundation.Collections.IIterable<HST Windows.Foundation.Collections.IVector<HSTRING> **out ); extern HRESULT vector_inspectable_create( const struct vector_iids *iids, void **out );
+namespace Windows.Foundation { + + /* type-pruning version of AsyncOperationCompletedHandler<T> */ + delegate HRESULT WineAsyncOperationCompletedHandler([in] IInspectable *async, [in] AsyncStatus status); + + [ + 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(); + } + +} + +typedef HRESULT (*async_callback)( IUnknown *invoker, IUnknown *param, PROPVARIANT *result ); +extern HRESULT async_info_create( IUnknown *invoker, IUnknown *param, async_callback callback, + IInspectable *outer, Windows.Foundation.IWineAsyncInfoImpl **out ); + extern const char *debugstr_hstring( HSTRING hstr );
cpp_quote("#define DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from, iface_mem, expr ) \") diff --git a/libs/winewinrt/Makefile.in b/libs/winewinrt/Makefile.in index 937df798735..fce5844ee51 100644 --- a/libs/winewinrt/Makefile.in +++ b/libs/winewinrt/Makefile.in @@ -1,6 +1,7 @@ STATICLIB = libwinewinrt.a
C_SRCS = \ + async_info.c \ debug.c \ vector_hstring.c \ vector_inspectable.c diff --git a/libs/winewinrt/async_info.c b/libs/winewinrt/async_info.c new file mode 100644 index 00000000000..0e1db19e1fb --- /dev/null +++ b/libs/winewinrt/async_info.c @@ -0,0 +1,361 @@ +/* WinRT IAsyncInfo implementation + * + * Copyright 2022 Bernhard Kölbl for CodeWeavers + * Copyright 2022 Rémi Bernon for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(winrt); + +#define Closed 4 +#define HANDLER_NOT_SET ((void *)~(ULONG_PTR)0) + +struct async_info +{ + IWineAsyncInfoImpl IWineAsyncInfoImpl_iface; + IAsyncInfo IAsyncInfo_iface; + IInspectable *IInspectable_outer; + LONG ref; + + async_callback callback; + TP_WORK *async_run_work; + IUnknown *invoker; + IUnknown *param; + + CRITICAL_SECTION cs; + IWineAsyncOperationCompletedHandler *handler; + PROPVARIANT result; + AsyncStatus status; + HRESULT hr; +}; + +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; + } + + FIXME( "%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 ); + if (impl->param) IUnknown_Release( impl->param ); + if (impl->invoker) IUnknown_Release( impl->invoker ); + impl->cs.DebugInfo->Spare[0] = 0; + 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; + if (impl->handler == NULL || impl->handler == HANDLER_NOT_SET) *handler = NULL; + else IWineAsyncOperationCompletedHandler_AddRef( (*handler = impl->handler) ); + 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_info *impl = impl_from_IAsyncInfo( iface ); + HRESULT hr = S_OK; + + TRACE( "iface %p, id %p.\n", iface, id ); + + EnterCriticalSection( &impl->cs ); + if (impl->status == Closed) hr = E_ILLEGAL_METHOD_CALL; + *id = 1; + LeaveCriticalSection( &impl->cs ); + + return hr; +} + +static HRESULT WINAPI async_info_get_Status( IAsyncInfo *iface, AsyncStatus *status ) +{ + struct async_info *impl = impl_from_IAsyncInfo( iface ); + HRESULT hr = S_OK; + + TRACE( "iface %p, status %p.\n", iface, status ); + + EnterCriticalSection( &impl->cs ); + if (impl->status == Closed) hr = E_ILLEGAL_METHOD_CALL; + *status = impl->status; + LeaveCriticalSection( &impl->cs ); + + return hr; +} + +static HRESULT WINAPI async_info_get_ErrorCode( IAsyncInfo *iface, HRESULT *error_code ) +{ + struct async_info *impl = impl_from_IAsyncInfo( iface ); + HRESULT hr = S_OK; + + TRACE( "iface %p, error_code %p.\n", iface, error_code ); + + EnterCriticalSection( &impl->cs ); + if (impl->status == Closed) *error_code = hr = E_ILLEGAL_METHOD_CALL; + else *error_code = impl->hr; + LeaveCriticalSection( &impl->cs ); + + return hr; +} + +static HRESULT WINAPI async_info_Cancel( IAsyncInfo *iface ) +{ + struct async_info *impl = impl_from_IAsyncInfo( iface ); + HRESULT hr = S_OK; + + TRACE( "iface %p.\n", iface ); + + EnterCriticalSection( &impl->cs ); + if (impl->status == Closed) hr = E_ILLEGAL_METHOD_CALL; + else if (impl->status == Started) impl->status = Canceled; + LeaveCriticalSection( &impl->cs ); + + return hr; +} + +static HRESULT WINAPI async_info_Close( IAsyncInfo *iface ) +{ + struct async_info *impl = impl_from_IAsyncInfo( iface ); + HRESULT hr = S_OK; + + TRACE( "iface %p.\n", iface ); + + EnterCriticalSection( &impl->cs ); + if (impl->status == Started) + hr = E_ILLEGAL_STATE_CHANGE; + else if (impl->status != Closed) + { + CloseThreadpoolWork( impl->async_run_work ); + impl->async_run_work = NULL; + impl->status = Closed; + } + LeaveCriticalSection( &impl->cs ); + + return hr; +} + +static const struct IAsyncInfoVtbl async_info_vtbl = +{ + /* IUnknown methods */ + async_info_QueryInterface, + async_info_AddRef, + async_info_Release, + /* IInspectable methods */ + async_info_GetIids, + async_info_GetRuntimeClassName, + async_info_GetTrustLevel, + /* IAsyncInfo */ + async_info_get_Id, + async_info_get_Status, + async_info_get_ErrorCode, + async_info_Cancel, + 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, 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) + { + 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 ); +} + +HRESULT async_info_create( IUnknown *invoker, IUnknown *param, async_callback callback, + IInspectable *outer, IWineAsyncInfoImpl **out ) +{ + struct async_info *impl; + HRESULT hr; + + 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 ))) + { + hr = HRESULT_FROM_WIN32( GetLastError() ); + free( impl ); + return hr; + } + + 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" ); + + *out = &impl->IWineAsyncInfoImpl_iface; + return S_OK; +}