From: Vibhav Pant vibhavp@gmail.com
--- dlls/windows.devices.enumeration/main.c | 288 +++++++++++++++--- .../tests/devices.c | 6 +- 2 files changed, 252 insertions(+), 42 deletions(-)
diff --git a/dlls/windows.devices.enumeration/main.c b/dlls/windows.devices.enumeration/main.c index 78d77effb35..c71cadb7d3e 100644 --- a/dlls/windows.devices.enumeration/main.c +++ b/dlls/windows.devices.enumeration/main.c @@ -21,6 +21,7 @@ #include "initguid.h" #include "private.h" #include "setupapi.h" +#include "roapi.h"
#include "wine/debug.h"
@@ -35,6 +36,10 @@ struct device_watcher struct list enumerated_handlers; struct list stopped_handlers; HSTRING filter; + + CRITICAL_SECTION cs; + DeviceWatcherStatus status; + IAsyncOperation_DeviceInformationCollection *async_op; };
static inline struct device_watcher *impl_from_IDeviceWatcher( IDeviceWatcher *iface ) @@ -42,6 +47,89 @@ static inline struct device_watcher *impl_from_IDeviceWatcher( IDeviceWatcher *i return CONTAINING_RECORD( iface, struct device_watcher, IDeviceWatcher_iface ); }
+typedef HRESULT (*async_invoke_func)( IAsyncOperationCompletedHandler_IInspectable *, IAsyncOperation_IInspectable *, + AsyncStatus, void * ); + +struct async_handler +{ + IAsyncOperationCompletedHandler_IInspectable IAsyncOperationCompletedHandler_IInspectable_iface; + LONG ref; + const GUID *iid; + + async_invoke_func invoke_cb; + void *data; +}; + +static inline struct async_handler *impl_from_IAsyncOperationCompletedHandler_IInspectable( IAsyncOperationCompletedHandler_IInspectable *iface ) +{ + return CONTAINING_RECORD( iface, struct async_handler, IAsyncOperationCompletedHandler_IInspectable_iface ); +} + +static HRESULT WINAPI async_handler_QueryInterface( IAsyncOperationCompletedHandler_IInspectable *iface, REFIID iid, void **out ) +{ + struct async_handler *impl = impl_from_IAsyncOperationCompletedHandler_IInspectable( iface ); + + TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out ); + + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, impl->iid )) + { + IUnknown_AddRef( (IUnknown *)(*out = &impl->IAsyncOperationCompletedHandler_IInspectable_iface )); + return S_OK; + } + + FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI async_handler_AddRef( IAsyncOperationCompletedHandler_IInspectable *iface ) +{ + struct async_handler *impl = impl_from_IAsyncOperationCompletedHandler_IInspectable( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + TRACE( "iface %p increasing refcount to %lu.\n", iface, ref ); + return ref; +} + +static ULONG WINAPI async_handler_Release( IAsyncOperationCompletedHandler_IInspectable *iface ) +{ + struct async_handler *impl = impl_from_IAsyncOperationCompletedHandler_IInspectable( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + TRACE( "iface %p decreasing refcount to %lu.\n", iface, ref ); + if (!ref) free( impl ); + return ref; +} + +static HRESULT WINAPI async_handler_Invoke( IAsyncOperationCompletedHandler_IInspectable *iface, IAsyncOperation_IInspectable *info, AsyncStatus status ) +{ + struct async_handler *impl = impl_from_IAsyncOperationCompletedHandler_IInspectable( iface ); + TRACE( "iface %p, info %p, status %d.\n", iface, info, status ); + return impl->invoke_cb( iface, info, status, impl->data ); +} + +static const struct IAsyncOperationCompletedHandler_IInspectableVtbl async_handler_vtbl = +{ + async_handler_QueryInterface, + async_handler_AddRef, + async_handler_Release, + async_handler_Invoke +}; + +static HRESULT async_handler_create( async_invoke_func on_invoke, void *data, const GUID *iid, void **out ) +{ + struct async_handler *this; + + if (!(this = calloc( 1, sizeof( *this ) ))) return E_OUTOFMEMORY; + + this->IAsyncOperationCompletedHandler_IInspectable_iface.lpVtbl = &async_handler_vtbl; + this->ref = 1; + this->iid = iid; + this->invoke_cb = on_invoke; + this->data = data; + *out = this; + return S_OK; +} + static HRESULT WINAPI device_watcher_QueryInterface( IDeviceWatcher *iface, REFIID iid, void **out ) { struct device_watcher *impl = impl_from_IDeviceWatcher( iface ); @@ -82,6 +170,10 @@ static ULONG WINAPI device_watcher_Release( IDeviceWatcher *iface ) typed_event_handlers_clear( &impl->enumerated_handlers ); typed_event_handlers_clear( &impl->stopped_handlers ); WindowsDeleteString( impl->filter ); + impl->cs.DebugInfo->Spare[0] = 0; + DeleteCriticalSection( &impl->cs ); + if (impl->async_op) + IAsyncOperation_DeviceInformationCollection_Release( impl->async_op ); free( impl ); }
@@ -188,10 +280,138 @@ static HRESULT WINAPI device_watcher_Status( IDeviceWatcher *iface, DeviceWatche return E_NOTIMPL; }
+static HRESULT device_watcher_findall_invoke( IAsyncOperationCompletedHandler_IInspectable *iface, IAsyncOperation_IInspectable *async_info, AsyncStatus status, + void *watcher ) +{ + IVectorView_DeviceInformation *collection = NULL; + struct device_watcher *impl; + IDeviceInformation *info; + UINT32 i, size; + HRESULT hr; + + impl = impl_from_IDeviceWatcher( watcher ); + if (status == Completed) + { + void *out; + if (FAILED( hr = IAsyncOperation_IInspectable_GetResults( async_info, (void *)&out ) )) goto done; + if (FAILED( hr = IInspectable_QueryInterface( out, &IID_IVectorView_DeviceInformation, (void *)&collection ))) goto done; + } + else + { + hr = E_FAIL; + goto done; + } + + if (!WindowsIsStringEmpty( impl->filter )) + { + FIXME( "Unsupported filter: %s\n", debugstr_hstring( impl->filter ) ); + hr = E_NOTIMPL; + goto done; + } + if (FAILED( hr = IVectorView_DeviceInformation_get_Size( collection, &size ))) + goto done; + for (i = 0; i < size && SUCCEEDED( hr = IVectorView_DeviceInformation_GetAt( collection, i, &info ) ); i++) + { + DeviceWatcherStatus status; + + EnterCriticalSection( &impl->cs ); + status = impl->status; + LeaveCriticalSection( &impl->cs ); + if (status != DeviceWatcherStatus_Started) + { + IDeviceInformation_Release( info ); + goto done; + } + + typed_event_handlers_notify( &impl->added_handlers, (IInspectable *)watcher, (IInspectable *)info ); + IDeviceInformation_Release( info ); + } + +done: + EnterCriticalSection( &impl->cs ); + IAsyncOperation_DeviceInformationCollection_Release( impl->async_op ); + impl->async_op = NULL; + if (SUCCEEDED( hr ) && impl->status == DeviceWatcherStatus_Started) + { + impl->status = DeviceWatcherStatus_EnumerationCompleted; + LeaveCriticalSection( &impl->cs ); + typed_event_handlers_notify( &impl->enumerated_handlers, (IInspectable *)watcher, NULL ); + } + else + { + if (FAILED( hr )) + impl->status = DeviceWatcherStatus_Aborted; + LeaveCriticalSection( &impl->cs ); + } + + IDeviceWatcher_Release( watcher ); + return hr; +} + static HRESULT WINAPI device_watcher_Start( IDeviceWatcher *iface ) { - FIXME( "iface %p stub!\n", iface ); - return S_OK; + struct device_watcher *impl = impl_from_IDeviceWatcher( iface ); + IDeviceInformationStatics *statics; + const WCHAR *name = RuntimeClass_Windows_Devices_Enumeration_DeviceInformation; + HSTRING class_name; + HRESULT hr; + + FIXME( "iface %p: semi-stub!\n", iface ); + + if (!WindowsIsStringEmpty( impl->filter )) + { + FIXME("Unsupported filter: %s\n", debugstr_hstring( impl->filter )); + return E_NOTIMPL; + } + hr = WindowsCreateString( name, wcslen( name ), &class_name ); + if (FAILED( hr )) return hr; + hr = RoGetActivationFactory( class_name, &IID_IDeviceInformationStatics, (void *)&statics ); + WindowsDeleteString( class_name ); + if (FAILED( hr )) return hr; + + EnterCriticalSection( &impl->cs ); + switch (impl->status) + { + case DeviceWatcherStatus_Created: + case DeviceWatcherStatus_Stopped: + case DeviceWatcherStatus_Aborted: + { + IAsyncOperationCompletedHandler_IInspectable *handler; + HRESULT hr; + + if (FAILED( hr = async_handler_create( device_watcher_findall_invoke, iface, &IID_IAsyncOperationCompletedHandler_DeviceInformationCollection, + (void *)&handler ) )) + { + impl->status = DeviceWatcherStatus_Aborted; + break; + } + if (FAILED( hr = IDeviceInformationStatics_FindAllAsync( statics, &impl->async_op ))) + { + IAsyncOperationCompletedHandler_IInspectable_Release( handler ); + impl->status = DeviceWatcherStatus_Aborted; + break; + } + + IDeviceWatcher_AddRef( iface ); + if (FAILED( hr = IAsyncOperation_DeviceInformationCollection_put_Completed( impl->async_op, + (IAsyncOperationCompletedHandler_DeviceInformationCollection *) handler))) + { + IAsyncOperationCompletedHandler_IInspectable_Release( handler ); + IAsyncOperation_DeviceInformationCollection_Release( impl->async_op ); + impl->async_op = NULL; + IDeviceWatcher_Release( iface ); + break; + } + + impl->status = DeviceWatcherStatus_Started; + break; + } + default: + hr = E_ILLEGAL_METHOD_CALL; + } + LeaveCriticalSection( &impl->cs ); + IDeviceInformationStatics_Release( statics ); + return hr; }
static HRESULT WINAPI device_watcher_Stop( IDeviceWatcher *iface ) @@ -201,6 +421,10 @@ static HRESULT WINAPI device_watcher_Stop( IDeviceWatcher *iface )
FIXME( "iface %p semi-stub!\n", iface );
+ EnterCriticalSection( &impl->cs ); + impl->status = DeviceWatcherStatus_Stopped; + LeaveCriticalSection( &impl->cs ); + IDeviceWatcher_AddRef( &impl->IDeviceWatcher_iface ); hr = typed_event_handlers_notify( &impl->stopped_handlers, (IInspectable *)iface, NULL ); IDeviceWatcher_Release( &impl->IDeviceWatcher_iface ); @@ -448,35 +672,23 @@ static HRESULT WINAPI device_statics_FindAllAsyncAqsFilterAndAdditionalPropertie return E_NOTIMPL; }
-static HRESULT WINAPI device_statics_CreateWatcher( IDeviceInformationStatics *iface, IDeviceWatcher **watcher ) -{ - TRACE( "iface %p, watcher %p\n", iface, watcher ); - return IDeviceInformationStatics_CreateWatcherAqsFilter( iface, NULL, watcher ); -} - -static HRESULT WINAPI device_statics_CreateWatcherDeviceClass( IDeviceInformationStatics *iface, DeviceClass class, IDeviceWatcher **watcher ) -{ - FIXME( "iface %p, class %d, watcher %p stub!\n", iface, class, watcher ); - return E_NOTIMPL; -} - -static HRESULT WINAPI device_statics_CreateWatcherAqsFilter( IDeviceInformationStatics *iface, HSTRING filter, IDeviceWatcher **watcher ) +static HRESULT device_watcher_create( HSTRING filter, IDeviceWatcher **watcher ) { struct device_watcher *this; HRESULT hr;
- TRACE( "iface %p, filter %s, watcher %p\n", iface, debugstr_hstring(filter), watcher ); - if (!(this = calloc( 1, sizeof(*this) ))) return E_OUTOFMEMORY;
- this->IDeviceWatcher_iface.lpVtbl = &device_watcher_vtbl; this->ref = 1; + this->IDeviceWatcher_iface.lpVtbl = &device_watcher_vtbl; if (FAILED(hr = WindowsDuplicateString( filter, &this->filter ))) { free( this ); return hr; }
+ InitializeCriticalSectionEx( &this->cs, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO ); + this->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": device_watcher.cs"); list_init( &this->added_handlers ); list_init( &this->enumerated_handlers ); list_init( &this->stopped_handlers ); @@ -485,6 +697,24 @@ static HRESULT WINAPI device_statics_CreateWatcherAqsFilter( IDeviceInformationS return S_OK; }
+static HRESULT WINAPI device_statics_CreateWatcher( IDeviceInformationStatics *iface, IDeviceWatcher **watcher ) +{ + TRACE( "iface %p, watcher %p\n", iface, watcher ); + return device_watcher_create( NULL, watcher ); +} + +static HRESULT WINAPI device_statics_CreateWatcherDeviceClass( IDeviceInformationStatics *iface, DeviceClass class, IDeviceWatcher **watcher ) +{ + FIXME( "iface %p, class %d, watcher %p stub!\n", iface, class, watcher ); + return E_NOTIMPL; +} + +static HRESULT WINAPI device_statics_CreateWatcherAqsFilter( IDeviceInformationStatics *iface, HSTRING filter, IDeviceWatcher **watcher ) +{ + TRACE( "iface %p, filter %s, watcher %p\n", iface, debugstr_hstring(filter), watcher ); + return device_watcher_create( filter, watcher ); +} + static HRESULT WINAPI device_statics_CreateWatcherAqsFilterAndAdditionalProperties( IDeviceInformationStatics *iface, HSTRING filter, IIterable_HSTRING *additional_properties, IDeviceWatcher **watcher ) { @@ -545,29 +775,9 @@ static HRESULT WINAPI device_statics2_CreateWatcher( IDeviceInformationStatics2 IIterable_HSTRING *additional_properties, DeviceInformationKind kind, IDeviceWatcher **watcher ) { - struct device_watcher *this; - HRESULT hr; - FIXME( "iface %p, filter %s, additional_properties %p, kind %u, watcher %p semi-stub!\n", iface, debugstr_hstring( filter ), additional_properties, kind, watcher ); - - if (!(this = calloc( 1, sizeof(*this) ))) - return E_OUTOFMEMORY; - - this->IDeviceWatcher_iface.lpVtbl = &device_watcher_vtbl; - this->ref = 1; - if (FAILED(hr = WindowsDuplicateString( filter, &this->filter ))) - { - free( this ); - return hr; - } - - list_init( &this->added_handlers ); - list_init( &this->enumerated_handlers ); - list_init( &this->stopped_handlers ); - - *watcher = &this->IDeviceWatcher_iface; - return S_OK; + return device_watcher_create( filter, watcher ); }
static const struct IDeviceInformationStatics2Vtbl device_statics2_vtbl = diff --git a/dlls/windows.devices.enumeration/tests/devices.c b/dlls/windows.devices.enumeration/tests/devices.c index 57e62904da5..d690d9b4745 100644 --- a/dlls/windows.devices.enumeration/tests/devices.c +++ b/dlls/windows.devices.enumeration/tests/devices.c @@ -479,14 +479,14 @@ static void test_DeviceInformation( void )
hr = IDeviceWatcher_Start( device_watcher ); ok( hr == S_OK, "got hr %#lx\n", hr ); - todo_wine ok( !WaitForSingleObject( enumerated_handler.event, 5000 ), "wait for enumerated_handler.event failed\n" ); - todo_wine ok( added_handler.devices_added > 0, "devices_added should be greater than 0" ); + ok( !WaitForSingleObject( enumerated_handler.event, 5000 ), "wait for enumerated_handler.event failed\n" ); + ok( added_handler.devices_added > 0, "devices_added should be greater than 0" ); hr = IDeviceWatcher_get_Status( device_watcher, &status ); todo_wine ok( hr == S_OK, "got hr %#lx\n", hr ); todo_wine 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 ); }