From: Vibhav Pant vibhavp@gmail.com
--- dlls/windows.devices.enumeration/main.c | 218 ++++++++++++++---- .../tests/devices.c | 4 +- 2 files changed, 179 insertions(+), 43 deletions(-)
diff --git a/dlls/windows.devices.enumeration/main.c b/dlls/windows.devices.enumeration/main.c index 78d77effb35..aee89d9442d 100644 --- a/dlls/windows.devices.enumeration/main.c +++ b/dlls/windows.devices.enumeration/main.c @@ -26,17 +26,54 @@
WINE_DEFAULT_DEBUG_CHANNEL(enumeration);
+struct device_watcher_weak; struct device_watcher { IDeviceWatcher IDeviceWatcher_iface; - LONG ref; + struct device_watcher_weak *weakref;
struct list added_handlers; struct list enumerated_handlers; struct list stopped_handlers; HSTRING filter; + + CRITICAL_SECTION cs; + DeviceWatcherStatus status; };
+struct device_watcher_weak +{ + LONG weak_count; + LONG strong_count; + struct device_watcher *watcher; +}; + +static struct device_watcher *device_watcher_weak_resolve( struct device_watcher_weak *weak ) +{ + LONG count = weak->strong_count; + + while (count) + { + if (InterlockedCompareExchange( &weak->strong_count, count + 1, count) == count) + return weak->watcher; + + count = weak->strong_count; + } + return NULL; +} + +static void device_watcher_weak_decref( struct device_watcher_weak *weak ) +{ + if (!InterlockedDecrement( &weak->weak_count )) + free( weak ); +} + +static struct device_watcher_weak *device_watcher_make_weak( struct device_watcher *watcher ) +{ + InterlockedIncrement( &watcher->weakref->weak_count ); + return watcher->weakref; +} + static inline struct device_watcher *impl_from_IDeviceWatcher( IDeviceWatcher *iface ) { return CONTAINING_RECORD( iface, struct device_watcher, IDeviceWatcher_iface ); @@ -65,7 +102,7 @@ static HRESULT WINAPI device_watcher_QueryInterface( IDeviceWatcher *iface, REFI static ULONG WINAPI device_watcher_AddRef( IDeviceWatcher *iface ) { struct device_watcher *impl = impl_from_IDeviceWatcher( iface ); - ULONG ref = InterlockedIncrement( &impl->ref ); + ULONG ref = InterlockedIncrement( &impl->weakref->strong_count ); TRACE( "iface %p, ref %lu.\n", iface, ref ); return ref; } @@ -73,7 +110,7 @@ static ULONG WINAPI device_watcher_AddRef( IDeviceWatcher *iface ) static ULONG WINAPI device_watcher_Release( IDeviceWatcher *iface ) { struct device_watcher *impl = impl_from_IDeviceWatcher( iface ); - ULONG ref = InterlockedDecrement( &impl->ref ); + ULONG ref = InterlockedDecrement( &impl->weakref->strong_count ); TRACE( "iface %p, ref %lu.\n", iface, ref );
if (!ref) @@ -82,6 +119,9 @@ 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 ); + device_watcher_weak_decref( impl->weakref ); + impl->cs.DebugInfo->Spare[0] = 0; + DeleteCriticalSection( &impl->cs ); free( impl ); }
@@ -188,9 +228,107 @@ static HRESULT WINAPI device_watcher_Status( IDeviceWatcher *iface, DeviceWatche return E_NOTIMPL; }
+static HRESULT WINAPI find_all_async( IUnknown *invoker, IUnknown *param, PROPVARIANT *result ); + +static void CALLBACK device_watcher_enumerate_proc( TP_CALLBACK_INSTANCE *instance, void *watcher_weak ) +{ + IVectorView_DeviceInformation *collection = NULL; + struct device_watcher *impl; + IDeviceInformation *info; + IDeviceWatcher *watcher; + PROPVARIANT result; + UINT32 i, size; + HRESULT hr; + + if (!(impl = device_watcher_weak_resolve( watcher_weak ))) + { + device_watcher_weak_decref( watcher_weak ); + return; + } + watcher = &impl->IDeviceWatcher_iface; + + PropVariantInit( &result ); + if (FAILED( hr = find_all_async( NULL, NULL, &result ) )) + goto done; + + collection = (IVectorView_DeviceInformation *)result.punkVal; + if (!WindowsIsStringEmpty( impl->filter )) + { + FIXME( "Unsupported filter: %s\n", debugstr_hstring( impl->filter ) ); + 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 ); + if (impl->status == DeviceWatcherStatus_Started) + { + impl->status = DeviceWatcherStatus_EnumerationCompleted; + LeaveCriticalSection( &impl->cs ); + typed_event_handlers_notify( &impl->enumerated_handlers, (IInspectable *)watcher, NULL ); + } + else + LeaveCriticalSection( &impl->cs ); + + if (collection) + IVectorView_DeviceInformation_Release( collection ); + IDeviceWatcher_Release( watcher ); + device_watcher_weak_decref( watcher_weak ); +} + static HRESULT WINAPI device_watcher_Start( IDeviceWatcher *iface ) { - FIXME( "iface %p stub!\n", iface ); + struct device_watcher *impl = impl_from_IDeviceWatcher( iface ); + + FIXME( "iface %p: semi-stub!\n", iface ); + + EnterCriticalSection( &impl->cs ); + switch (impl->status) + { + case DeviceWatcherStatus_Created: + case DeviceWatcherStatus_Stopped: + case DeviceWatcherStatus_Aborted: + { + struct device_watcher_weak *weak; + + if (!(weak = device_watcher_make_weak( impl ))) + { + LeaveCriticalSection( &impl->cs ); + return E_OUTOFMEMORY; + } + impl->status = DeviceWatcherStatus_Started; + if (!TrySubmitThreadpoolCallback( device_watcher_enumerate_proc, weak, NULL )) + { + DWORD err = GetLastError(); + LeaveCriticalSection( &impl->cs ); + ERR( "TrySubmitThreadpoolCallback failed: %lu\n", err ); + device_watcher_weak_decref( weak ); + return HRESULT_FROM_WIN32( err ); + } + break; + } + default: + LeaveCriticalSection( &impl->cs ); + return E_ILLEGAL_METHOD_CALL; + } + LeaveCriticalSection( &impl->cs ); return S_OK; }
@@ -201,6 +339,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 +590,31 @@ 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; + if (!((this->weakref = calloc ( 1, sizeof( *this->weakref ) )))) + { + free( this ); + return E_OUTOFMEMORY; + } + + this->weakref->weak_count = this->weakref->strong_count = 1; + this->weakref->watcher = this;
this->IDeviceWatcher_iface.lpVtbl = &device_watcher_vtbl; - this->ref = 1; if (FAILED(hr = WindowsDuplicateString( filter, &this->filter ))) { + free( this->weakref ); 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 +623,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 +701,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 075ae50ed73..bee609629de 100644 --- a/dlls/windows.devices.enumeration/tests/devices.c +++ b/dlls/windows.devices.enumeration/tests/devices.c @@ -479,13 +479,13 @@ static void test_DeviceInformation( void ) ok( ref == 2, "got ref %lu\n", ref ); 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" ); + ok( !WaitForSingleObject( enumerated_handler.event, 5000 ), "wait for enumerated_handler.event failed\n" ); 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 ); IDeviceWatcher_Release( device_watcher );