From: Rémi Bernon rbernon@codeweavers.com
--- dlls/windows.devices.enumeration/async.c | 143 ++++++++++++++++++ dlls/windows.devices.enumeration/main.c | 87 ++++++++++- dlls/windows.devices.enumeration/private.h | 2 + .../tests/devices.c | 16 +- 4 files changed, 234 insertions(+), 14 deletions(-)
diff --git a/dlls/windows.devices.enumeration/async.c b/dlls/windows.devices.enumeration/async.c index 3235c65a0a4..0c4f6d647d2 100644 --- a/dlls/windows.devices.enumeration/async.c +++ b/dlls/windows.devices.enumeration/async.c @@ -514,3 +514,146 @@ HRESULT async_operation_inspectable_create( const GUID *iid, IUnknown *invoker, TRACE( "created IAsyncOperation_IInspectable %p\n", *out ); return S_OK; } + +struct async_action +{ + IAsyncAction IAsyncAction_iface; + IAsyncInfoImpl *IAsyncInfoImpl_inner; + LONG ref; +}; + +static inline struct async_action *impl_from_IAsyncAction( IAsyncAction *iface ) +{ + return CONTAINING_RECORD( iface, struct async_action, IAsyncAction_iface ); +} + +static HRESULT WINAPI async_action_QueryInterface( IAsyncAction *iface, REFIID iid, void **out ) +{ + struct async_action *impl = impl_from_IAsyncAction( 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_IAsyncAction )) + { + IInspectable_AddRef( (*out = &impl->IAsyncAction_iface) ); + return S_OK; + } + + return IAsyncInfoImpl_QueryInterface( impl->IAsyncInfoImpl_inner, iid, out ); +} + +static ULONG WINAPI async_action_AddRef( IAsyncAction *iface ) +{ + struct async_action *impl = impl_from_IAsyncAction( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + TRACE( "iface %p, ref %lu.\n", iface, ref ); + return ref; +} + +static ULONG WINAPI async_action_Release( IAsyncAction *iface ) +{ + struct async_action *impl = impl_from_IAsyncAction( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + TRACE( "iface %p, ref %lu.\n", iface, ref ); + + if (!ref) + { + /* guard against re-entry if inner releases an outer iface */ + InterlockedIncrement( &impl->ref ); + IAsyncInfoImpl_Release( impl->IAsyncInfoImpl_inner ); + free( impl ); + } + + return ref; +} + +static HRESULT WINAPI async_action_GetIids( IAsyncAction *iface, ULONG *iid_count, IID **iids ) +{ + FIXME( "iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids ); + return E_NOTIMPL; +} + +static HRESULT WINAPI async_action_GetRuntimeClassName( IAsyncAction *iface, HSTRING *class_name ) +{ + return WindowsCreateString( L"Windows.Foundation.IAsyncOperation`1<Boolean>", + ARRAY_SIZE(L"Windows.Foundation.IAsyncOperation`1<Boolean>"), + class_name ); +} + +static HRESULT WINAPI async_action_GetTrustLevel( IAsyncAction *iface, TrustLevel *trust_level ) +{ + FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level ); + return E_NOTIMPL; +} + +static HRESULT WINAPI async_action_put_Completed( IAsyncAction *iface, IAsyncActionCompletedHandler *bool_handler ) +{ + IAsyncOperationCompletedHandlerImpl *handler = (IAsyncOperationCompletedHandlerImpl *)bool_handler; + struct async_action *impl = impl_from_IAsyncAction( iface ); + TRACE( "iface %p, handler %p.\n", iface, handler ); + return IAsyncInfoImpl_put_Completed( impl->IAsyncInfoImpl_inner, handler ); +} + +static HRESULT WINAPI async_action_get_Completed( IAsyncAction *iface, IAsyncActionCompletedHandler **bool_handler ) +{ + IAsyncOperationCompletedHandlerImpl **handler = (IAsyncOperationCompletedHandlerImpl **)bool_handler; + struct async_action *impl = impl_from_IAsyncAction( iface ); + TRACE( "iface %p, handler %p.\n", iface, handler ); + return IAsyncInfoImpl_get_Completed( impl->IAsyncInfoImpl_inner, handler ); +} + +static HRESULT WINAPI async_action_GetResults( IAsyncAction *iface ) +{ + struct async_action *impl = impl_from_IAsyncAction( iface ); + PROPVARIANT result; + HRESULT hr; + + TRACE( "iface %p.\n", iface ); + + PropVariantInit( &result ); + hr = IAsyncInfoImpl_get_Result( impl->IAsyncInfoImpl_inner, &result ); + PropVariantClear( &result ); + return hr; +} + +static const struct IAsyncActionVtbl async_action_vtbl = +{ + /* IUnknown methods */ + async_action_QueryInterface, + async_action_AddRef, + async_action_Release, + /* IInspectable methods */ + async_action_GetIids, + async_action_GetRuntimeClassName, + async_action_GetTrustLevel, + /* IAsyncOperation<boolean> */ + async_action_put_Completed, + async_action_get_Completed, + async_action_GetResults, +}; + +HRESULT async_action_create( IUnknown *invoker, async_operation_callback callback, IAsyncAction **out ) +{ + struct async_action *impl; + HRESULT hr; + + *out = NULL; + if (!(impl = calloc( 1, sizeof(*impl) ))) return E_OUTOFMEMORY; + impl->IAsyncAction_iface.lpVtbl = &async_action_vtbl; + impl->ref = 1; + + if (FAILED(hr = async_info_create( invoker, NULL, callback, (IInspectable *)&impl->IAsyncAction_iface, &impl->IAsyncInfoImpl_inner )) || + FAILED(hr = IAsyncInfoImpl_Start( impl->IAsyncInfoImpl_inner ))) + { + if (impl->IAsyncInfoImpl_inner) IAsyncInfoImpl_Release( impl->IAsyncInfoImpl_inner ); + free( impl ); + return hr; + } + + *out = &impl->IAsyncAction_iface; + TRACE( "created IAsyncAction %p\n", *out ); + return S_OK; +} diff --git a/dlls/windows.devices.enumeration/main.c b/dlls/windows.devices.enumeration/main.c index a67369b6e07..0efe0966b5f 100644 --- a/dlls/windows.devices.enumeration/main.c +++ b/dlls/windows.devices.enumeration/main.c @@ -188,22 +188,97 @@ static HRESULT WINAPI device_watcher_get_Status( IDeviceWatcher *iface, DeviceWa return S_OK; }
+static HRESULT device_watcher_start_async( IUnknown *invoker, IUnknown *param, PROPVARIANT *result ) +{ + struct device_watcher *impl = impl_from_IDeviceWatcher( (IDeviceWatcher *)invoker ); + DeviceWatcherStatus status; + + EnterCriticalSection( &impl->cs ); + if (impl->status == DeviceWatcherStatus_Stopping) status = DeviceWatcherStatus_Stopped; + else status = DeviceWatcherStatus_EnumerationCompleted; + impl->status = status; + LeaveCriticalSection( &impl->cs ); + + if (status == DeviceWatcherStatus_Stopped) typed_event_handlers_notify( &impl->stopped_handlers, (IInspectable *)invoker, NULL ); + return S_OK; +} + static HRESULT WINAPI device_watcher_Start( IDeviceWatcher *iface ) { - FIXME( "iface %p stub!\n", iface ); + struct device_watcher *impl = impl_from_IDeviceWatcher( iface ); + IAsyncAction *async; + HRESULT hr = S_OK; + + FIXME( "iface %p: semi-stub!\n", iface ); + + if (!WindowsIsStringEmpty( impl->filter )) + { + FIXME( "Unsupported filter: %s\n", debugstr_hstring( impl->filter ) ); + return E_NOTIMPL; + } + + EnterCriticalSection( &impl->cs ); + switch (impl->status) + { + case DeviceWatcherStatus_EnumerationCompleted: hr = E_ILLEGAL_METHOD_CALL; break; + case DeviceWatcherStatus_Started: hr = E_ILLEGAL_METHOD_CALL; break; + case DeviceWatcherStatus_Stopping: hr = E_ILLEGAL_METHOD_CALL; break; + default: hr = E_ILLEGAL_METHOD_CALL; + + case DeviceWatcherStatus_Aborted: + case DeviceWatcherStatus_Created: + case DeviceWatcherStatus_Stopped: + impl->status = DeviceWatcherStatus_Started; + hr = async_action_create( (IUnknown *)iface, device_watcher_start_async, &async ); + IAsyncAction_Release( async ); + break; + } + LeaveCriticalSection( &impl->cs ); + + return hr; +} + +static HRESULT device_watcher_stop_async( IUnknown *invoker, IUnknown *param, PROPVARIANT *result ) +{ + struct device_watcher *impl = impl_from_IDeviceWatcher( (IDeviceWatcher *)invoker ); + + EnterCriticalSection( &impl->cs ); + impl->status = DeviceWatcherStatus_Stopped; + LeaveCriticalSection( &impl->cs ); + + typed_event_handlers_notify( &impl->stopped_handlers, (IInspectable *)invoker, NULL ); return S_OK; }
static HRESULT WINAPI device_watcher_Stop( IDeviceWatcher *iface ) { struct device_watcher *impl = impl_from_IDeviceWatcher( iface ); - HRESULT hr; + IAsyncAction *async; + HRESULT hr = S_OK; + + TRACE( "iface %p\n", iface );
- FIXME( "iface %p semi-stub!\n", iface ); + EnterCriticalSection( &impl->cs ); + switch (impl->status) + { + case DeviceWatcherStatus_Aborted: break; + case DeviceWatcherStatus_Created: hr = E_ILLEGAL_METHOD_CALL; break; + case DeviceWatcherStatus_Stopped: hr = E_ILLEGAL_METHOD_CALL; break; + case DeviceWatcherStatus_Stopping: hr = E_ILLEGAL_METHOD_CALL; break; + default: hr = E_ILLEGAL_METHOD_CALL; + + case DeviceWatcherStatus_EnumerationCompleted: + impl->status = DeviceWatcherStatus_Stopping; + hr = async_action_create( (IUnknown *)iface, device_watcher_stop_async, &async ); + IAsyncAction_Release( async ); + break; + case DeviceWatcherStatus_Started: + impl->status = DeviceWatcherStatus_Stopping; + /* an async start is in progress, let it handle stopped state change */ + break; + } + LeaveCriticalSection( &impl->cs );
- IDeviceWatcher_AddRef( &impl->IDeviceWatcher_iface ); - hr = typed_event_handlers_notify( &impl->stopped_handlers, (IInspectable *)iface, NULL ); - IDeviceWatcher_Release( &impl->IDeviceWatcher_iface ); return hr; }
diff --git a/dlls/windows.devices.enumeration/private.h b/dlls/windows.devices.enumeration/private.h index cc5be350379..e0a8e46f8b5 100644 --- a/dlls/windows.devices.enumeration/private.h +++ b/dlls/windows.devices.enumeration/private.h @@ -58,6 +58,8 @@ HRESULT typed_event_handlers_clear( struct list *list );
extern HRESULT async_operation_inspectable_create( const GUID *iid, IUnknown *invoker, IUnknown *param, async_operation_callback callback, IAsyncOperation_IInspectable **out ); +extern HRESULT async_action_create( IUnknown *invoker, async_operation_callback callback, IAsyncAction **out ); + extern HRESULT vector_create( const struct vector_iids *iids, void **out ); extern HRESULT device_information_create( const WCHAR *path, IDeviceInformation **info );
diff --git a/dlls/windows.devices.enumeration/tests/devices.c b/dlls/windows.devices.enumeration/tests/devices.c index 2dc5b1433dc..2f6c0b8191f 100644 --- a/dlls/windows.devices.enumeration/tests/devices.c +++ b/dlls/windows.devices.enumeration/tests/devices.c @@ -398,17 +398,17 @@ static void test_DeviceInformation( void ) ok( hr == S_OK, "got hr %#lx\n", hr ); hr = IDeviceWatcher_get_Status( device_watcher, &status ); ok( hr == S_OK, "got hr %#lx\n", hr ); - todo_wine ok( status == DeviceWatcherStatus_Started, "got status %u\n", status ); + ok( status == DeviceWatcherStatus_Started, "got status %u\n", status );
ref = IDeviceWatcher_AddRef( device_watcher ); - ok( ref == 2, "got ref %lu\n", ref ); + todo_wine ok( ref == 2, "got ref %lu\n", ref ); hr = IDeviceWatcher_Stop( device_watcher ); ok( hr == S_OK, "got hr %#lx\n", hr ); ok( !WaitForSingleObject( stopped_handler.event, 1000 ), "wait for stopped_handler.event failed\n" );
hr = IDeviceWatcher_get_Status( device_watcher, &status ); ok( hr == S_OK, "got hr %#lx\n", hr ); - todo_wine ok( status == DeviceWatcherStatus_Stopped, "got status %u\n", status ); + ok( status == DeviceWatcherStatus_Stopped, "got status %u\n", status ); ok( stopped_handler.invoked, "stopped_handler not invoked\n" ); ok( stopped_handler.args == NULL, "stopped_handler not invoked\n" );
@@ -445,17 +445,17 @@ static void test_DeviceInformation( void ) ok( hr == S_OK, "got hr %#lx\n", hr ); hr = IDeviceWatcher_get_Status( device_watcher, &status ); ok( hr == S_OK, "got hr %#lx\n", hr ); - todo_wine ok( status == DeviceWatcherStatus_Started, "got status %u\n", status ); + ok( status == DeviceWatcherStatus_Started, "got status %u\n", status );
ref = IDeviceWatcher_AddRef( device_watcher ); - ok( ref == 2, "got ref %lu\n", ref ); + todo_wine ok( ref == 2, "got ref %lu\n", ref ); hr = IDeviceWatcher_Stop( device_watcher ); ok( hr == S_OK, "got hr %#lx\n", hr ); ok( !WaitForSingleObject( stopped_handler.event, 1000 ), "wait for stopped_handler.event failed\n" );
hr = IDeviceWatcher_get_Status( device_watcher, &status ); ok( hr == S_OK, "got hr %#lx\n", hr ); - todo_wine ok( status == DeviceWatcherStatus_Stopped, "got status %u\n", status ); + ok( status == DeviceWatcherStatus_Stopped, "got status %u\n", status ); ok( stopped_handler.invoked, "stopped_handler not invoked\n" ); ok( stopped_handler.args == NULL, "stopped_handler not invoked\n" );
@@ -478,10 +478,10 @@ static void test_DeviceInformation( void ) todo_wine ok( added_handler.devices_added > 0, "devices_added should be greater than 0\n" ); hr = IDeviceWatcher_get_Status( device_watcher, &status ); ok( hr == S_OK, "got hr %#lx\n", hr ); - todo_wine ok( status == DeviceWatcherStatus_EnumerationCompleted, "got status %u\n", status ); + ok( status == DeviceWatcherStatus_EnumerationCompleted, "got status %u\n", status );
hr = IDeviceWatcher_Start( device_watcher ); - todo_wine ok( hr == E_ILLEGAL_METHOD_CALL, "Start returned %#lx\n", hr ); + ok( hr == E_ILLEGAL_METHOD_CALL, "Start returned %#lx\n", hr );
IDeviceWatcher_Release( device_watcher ); }