Implement `DeviceWatcher` on top of a `HDEVQUERY` object, obtained from `DevCreateObjectQuery`. All events from the query object's associated callback are directly forwarded to the `DeviceWatcher`'s corresponding event handlers.
As closing/freeing the `HDEVQUERY` is performed asynchronously, I have also added `IWeakReference` support for the device watcher.
-- v4: windows.devices.enumeration: Implement DeviceInformationStatics::DeviceWatcher using DevCreateObjectQuery.
From: Vibhav Pant vibhavp@gmail.com
--- dlls/windows.devices.enumeration/Makefile.in | 2 +- dlls/windows.devices.enumeration/main.c | 27 ++++++++++++++------ 2 files changed, 20 insertions(+), 9 deletions(-)
diff --git a/dlls/windows.devices.enumeration/Makefile.in b/dlls/windows.devices.enumeration/Makefile.in index 5e3f6fbb6fa..853c1303efa 100644 --- a/dlls/windows.devices.enumeration/Makefile.in +++ b/dlls/windows.devices.enumeration/Makefile.in @@ -1,5 +1,5 @@ MODULE = windows.devices.enumeration.dll -IMPORTS = advapi32 combase setupapi uuid +IMPORTS = advapi32 cfgmgr32 combase setupapi uuid
SOURCES = \ access.c \ diff --git a/dlls/windows.devices.enumeration/main.c b/dlls/windows.devices.enumeration/main.c index c927ccff18d..2cd727a4149 100644 --- a/dlls/windows.devices.enumeration/main.c +++ b/dlls/windows.devices.enumeration/main.c @@ -21,6 +21,8 @@ #include "initguid.h" #include "private.h" #include "setupapi.h" +#include "devfiltertypes.h" +#include "devquery.h"
#include "wine/debug.h"
@@ -519,12 +521,6 @@ static HRESULT WINAPI device_statics_CreateFromIdAsyncAdditionalProperties( IDev return E_NOTIMPL; }
-static HRESULT append_device_information( IDeviceInformation *info, void *context ) -{ - IVector_IInspectable *vector = context; - return IVector_IInspectable_Append( vector, (IInspectable *)info ); -} - static HRESULT find_all_async( IUnknown *invoker, IUnknown *param, PROPVARIANT *result ) { static const struct vector_iids iids = @@ -536,13 +532,28 @@ static HRESULT find_all_async( IUnknown *invoker, IUnknown *param, PROPVARIANT * }; IVectorView_DeviceInformation *view; IVector_IInspectable *vector; + const DEV_OBJECT *objects; + ULONG len, i; HRESULT hr;
TRACE( "invoker %p, param %p, result %p\n", invoker, param, result );
if (FAILED(hr = vector_create( &iids, (void *)&vector ))) return hr; - hr = enum_device_information( append_device_information, vector ); - + if (FAILED(hr = DevGetObjects( DevObjectTypeDeviceInterfaceDisplay, DevQueryFlagNone, 0, NULL, 0, NULL, &len, &objects ))) + { + IVector_IInspectable_Release( vector ); + return hr; + } + for (i = 0; i < len && SUCCEEDED(hr); i++) + { + IDeviceInformation *info; + if (SUCCEEDED(hr = device_information_create( objects[i].pszObjectId, &info ))) + { + hr = IVector_IInspectable_Append( vector, (IInspectable *)info ); + IDeviceInformation_Release( info ); + } + } + DevFreeObjects( len, objects ); if (SUCCEEDED(hr)) hr = IVector_IInspectable_GetView( vector, (void *)&view ); IVector_IInspectable_Release( vector ); if (FAILED(hr)) return hr;
From: Vibhav Pant vibhavp@gmail.com
--- .../tests/devices.c | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-)
diff --git a/dlls/windows.devices.enumeration/tests/devices.c b/dlls/windows.devices.enumeration/tests/devices.c index d9247bb6ced..a0b8cfd043b 100644 --- a/dlls/windows.devices.enumeration/tests/devices.c +++ b/dlls/windows.devices.enumeration/tests/devices.c @@ -27,6 +27,7 @@
#include "initguid.h" #include "roapi.h" +#include "weakreference.h"
#define WIDL_using_Windows_Foundation #define WIDL_using_Windows_Foundation_Collections @@ -339,6 +340,7 @@ static void test_DeviceInformation( void ) IAsyncOperation_DeviceInformationCollection *info_collection_async = NULL; IVectorView_DeviceInformation *info_collection = NULL; IDeviceInformation *info; + IWeakReferenceSource *weak_src; UINT32 i, size; HSTRING str; HRESULT hr; @@ -385,6 +387,24 @@ static void test_DeviceInformation( void ) check_interface( device_watcher, &IID_IAgileObject, TRUE ); check_interface( device_watcher, &IID_IDeviceWatcher, TRUE );
+ hr = IDeviceWatcher_QueryInterface( device_watcher, &IID_IWeakReferenceSource, (void **)&weak_src ); + todo_wine ok( hr == S_OK, "got hr %#lx\n", hr ); + if (SUCCEEDED( hr )) + { + IWeakReference *weak_ref; + IDeviceWatcher *watcher; + + check_interface( weak_src, &IID_IAgileObject, TRUE ); + hr = IWeakReferenceSource_GetWeakReference( weak_src, &weak_ref ); + IWeakReferenceSource_Release( weak_src ); + ok( hr == S_OK, "got hr %#lx\n", hr ); + hr = IWeakReference_Resolve( weak_ref, &IID_IDeviceWatcher, (IInspectable **)&watcher ); + IWeakReference_Release( weak_ref ); + ok( hr == S_OK, "got hr %#lx\n", hr ); + ref = IDeviceWatcher_Release( watcher ); + ok( ref == 1, "got ref %lu\n", ref ); + } + hr = IDeviceWatcher_add_Added( device_watcher, (void *)&added_handler.ITypedEventHandler_DeviceWatcher_IInspectable_iface, &added_token ); ok( hr == S_OK, "got hr %#lx\n", hr ); hr = IDeviceWatcher_add_Stopped( device_watcher, &stopped_handler.ITypedEventHandler_DeviceWatcher_IInspectable_iface, &stopped_token ); @@ -475,7 +495,7 @@ static void test_DeviceInformation( void ) hr = IDeviceWatcher_Start( device_watcher ); ok( hr == S_OK, "got hr %#lx\n", hr ); 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" ); + 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 ); ok( status == DeviceWatcherStatus_EnumerationCompleted, "got status %u\n", status );
From: Vibhav Pant vibhavp@gmail.com
--- dlls/windows.devices.enumeration/Makefile.in | 3 +- dlls/windows.devices.enumeration/main.c | 20 +- dlls/windows.devices.enumeration/private.h | 1 + .../tests/devices.c | 28 ++- dlls/windows.devices.enumeration/weakref.c | 175 ++++++++++++++++++ dlls/windows.devices.enumeration/weakref.h | 38 ++++ 6 files changed, 244 insertions(+), 21 deletions(-) create mode 100644 dlls/windows.devices.enumeration/weakref.c create mode 100644 dlls/windows.devices.enumeration/weakref.h
diff --git a/dlls/windows.devices.enumeration/Makefile.in b/dlls/windows.devices.enumeration/Makefile.in index 853c1303efa..c81a88d2ec7 100644 --- a/dlls/windows.devices.enumeration/Makefile.in +++ b/dlls/windows.devices.enumeration/Makefile.in @@ -9,4 +9,5 @@ SOURCES = \ event_handlers.c \ information.c \ main.c \ - vector.c + vector.c \ + weakref.c diff --git a/dlls/windows.devices.enumeration/main.c b/dlls/windows.devices.enumeration/main.c index 2cd727a4149..693e8f5103c 100644 --- a/dlls/windows.devices.enumeration/main.c +++ b/dlls/windows.devices.enumeration/main.c @@ -83,7 +83,7 @@ static HRESULT enum_device_information( enum_device_information_cb callback, voi struct device_watcher { IDeviceWatcher IDeviceWatcher_iface; - LONG ref; + struct weak_reference_source weak_reference_source;
struct list added_handlers; struct list enumerated_handlers; @@ -114,6 +114,13 @@ static HRESULT WINAPI device_watcher_QueryInterface( IDeviceWatcher *iface, REFI return S_OK; }
+ if (IsEqualGUID( iid, &IID_IWeakReferenceSource )) + { + *out = &impl->weak_reference_source.IWeakReferenceSource_iface; + IWeakReferenceSource_AddRef(*out); + return S_OK; + } + FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); *out = NULL; return E_NOINTERFACE; @@ -122,7 +129,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 = weak_reference_strong_add_ref( &impl->weak_reference_source ); TRACE( "iface %p, ref %lu.\n", iface, ref ); return ref; } @@ -130,7 +137,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 = weak_reference_strong_release( &impl->weak_reference_source ); TRACE( "iface %p, ref %lu.\n", iface, ref );
if (!ref) @@ -386,10 +393,15 @@ static HRESULT device_watcher_create( HSTRING filter, IDeviceWatcher **out )
if (!(impl = calloc( 1, sizeof(*impl) ))) return E_OUTOFMEMORY;
- impl->ref = 1; impl->IDeviceWatcher_iface.lpVtbl = &device_watcher_vtbl; + if (FAILED(hr = weak_reference_source_init( &impl->weak_reference_source, (IUnknown *)&impl->IDeviceWatcher_iface ))) + { + free( impl ); + return hr; + } if (FAILED(hr = WindowsDuplicateString( filter, &impl->filter ))) { + weak_reference_strong_release( &impl->weak_reference_source ); free( impl ); return hr; } diff --git a/dlls/windows.devices.enumeration/private.h b/dlls/windows.devices.enumeration/private.h index e0a8e46f8b5..ad15b7916ca 100644 --- a/dlls/windows.devices.enumeration/private.h +++ b/dlls/windows.devices.enumeration/private.h @@ -40,6 +40,7 @@ #include "wine/list.h"
#include "async_private.h" +#include "weakref.h"
struct vector_iids { diff --git a/dlls/windows.devices.enumeration/tests/devices.c b/dlls/windows.devices.enumeration/tests/devices.c index a0b8cfd043b..529215df0f2 100644 --- a/dlls/windows.devices.enumeration/tests/devices.c +++ b/dlls/windows.devices.enumeration/tests/devices.c @@ -341,6 +341,8 @@ static void test_DeviceInformation( void ) IVectorView_DeviceInformation *info_collection = NULL; IDeviceInformation *info; IWeakReferenceSource *weak_src; + IWeakReference *weak_ref; + IDeviceWatcher *watcher; UINT32 i, size; HSTRING str; HRESULT hr; @@ -388,22 +390,16 @@ static void test_DeviceInformation( void ) check_interface( device_watcher, &IID_IDeviceWatcher, TRUE );
hr = IDeviceWatcher_QueryInterface( device_watcher, &IID_IWeakReferenceSource, (void **)&weak_src ); - todo_wine ok( hr == S_OK, "got hr %#lx\n", hr ); - if (SUCCEEDED( hr )) - { - IWeakReference *weak_ref; - IDeviceWatcher *watcher; - - check_interface( weak_src, &IID_IAgileObject, TRUE ); - hr = IWeakReferenceSource_GetWeakReference( weak_src, &weak_ref ); - IWeakReferenceSource_Release( weak_src ); - ok( hr == S_OK, "got hr %#lx\n", hr ); - hr = IWeakReference_Resolve( weak_ref, &IID_IDeviceWatcher, (IInspectable **)&watcher ); - IWeakReference_Release( weak_ref ); - ok( hr == S_OK, "got hr %#lx\n", hr ); - ref = IDeviceWatcher_Release( watcher ); - ok( ref == 1, "got ref %lu\n", ref ); - } + ok( hr == S_OK, "got hr %#lx\n", hr ); + check_interface( weak_src, &IID_IAgileObject, TRUE ); + hr = IWeakReferenceSource_GetWeakReference( weak_src, &weak_ref ); + IWeakReferenceSource_Release( weak_src ); + ok( hr == S_OK, "got hr %#lx\n", hr ); + hr = IWeakReference_Resolve( weak_ref, &IID_IDeviceWatcher, (IInspectable **)&watcher ); + IWeakReference_Release( weak_ref ); + ok( hr == S_OK, "got hr %#lx\n", hr ); + ref = IDeviceWatcher_Release( watcher ); + ok( ref == 1, "got ref %lu\n", ref );
hr = IDeviceWatcher_add_Added( device_watcher, (void *)&added_handler.ITypedEventHandler_DeviceWatcher_IInspectable_iface, &added_token ); ok( hr == S_OK, "got hr %#lx\n", hr ); diff --git a/dlls/windows.devices.enumeration/weakref.c b/dlls/windows.devices.enumeration/weakref.c new file mode 100644 index 00000000000..6a10390dd4c --- /dev/null +++ b/dlls/windows.devices.enumeration/weakref.c @@ -0,0 +1,175 @@ +/* WinRT weak reference helpers + * + * Copyright 2025 Zhiyi Zhang 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 + */ + +#define COBJMACROS +#include "weakref.h" + +/* The control block is contained in struct weak_reference so that we don't have to allocate a + * separate struct for it */ +struct weak_reference +{ + IWeakReference IWeakReference_iface; + IUnknown *object; + /* control block */ + LONG ref_strong; + LONG ref_weak; +}; + +static inline struct weak_reference *impl_from_IWeakReference( IWeakReference *iface ) +{ + return CONTAINING_RECORD(iface, struct weak_reference, IWeakReference_iface); +} + +static HRESULT WINAPI weak_reference_QueryInterface( IWeakReference *iface, REFIID iid, void **out ) +{ + struct weak_reference *impl = impl_from_IWeakReference( iface ); + + if (IsEqualGUID( iid, &IID_IUnknown ) || IsEqualGUID( iid, &IID_IWeakReference )) + { + *out = &impl->IWeakReference_iface; + IWeakReference_AddRef( *out ); + return S_OK; + } + + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI weak_reference_AddRef( IWeakReference *iface ) +{ + struct weak_reference *impl = impl_from_IWeakReference( iface ); + return InterlockedIncrement( &impl->ref_weak ); +} + +static ULONG WINAPI weak_reference_Release( IWeakReference *iface ) +{ + struct weak_reference *impl = impl_from_IWeakReference( iface ); + ULONG ref = InterlockedDecrement( &impl->ref_weak ); + + if (!ref) + free( impl ); + return ref; +} + +static HRESULT WINAPI weak_reference_Resolve( IWeakReference *iface, REFIID iid, IInspectable **out ) +{ + struct weak_reference *impl = impl_from_IWeakReference( iface ); + HRESULT hr; + LONG ref; + + *out = NULL; + do + { + if (!(ref = ReadNoFence( &impl->ref_strong ))) + return S_OK; + } while (ref != InterlockedCompareExchange( &impl->ref_strong, ref + 1, ref )); + + hr = IUnknown_QueryInterface( impl->object, iid, (void **)out ); + IUnknown_Release( impl->object ); + return hr; +} + +static const struct IWeakReferenceVtbl weak_reference_vtbl = +{ + weak_reference_QueryInterface, + weak_reference_AddRef, + weak_reference_Release, + weak_reference_Resolve, +}; + +static inline struct weak_reference_source *impl_from_IWeakReferenceSource( IWeakReferenceSource *iface ) +{ + return CONTAINING_RECORD(iface, struct weak_reference_source, IWeakReferenceSource_iface); +} + +static HRESULT WINAPI weak_reference_source_QueryInterface( IWeakReferenceSource *iface, REFIID iid, void **out ) +{ + struct weak_reference_source *weak_reference_source = impl_from_IWeakReferenceSource( iface ); + struct weak_reference *weak_reference = impl_from_IWeakReference( weak_reference_source->weak_reference ); + return IUnknown_QueryInterface( weak_reference->object, iid, out ); +} + +static ULONG WINAPI weak_reference_source_AddRef( IWeakReferenceSource *iface ) +{ + struct weak_reference_source *weak_reference_source = impl_from_IWeakReferenceSource( iface ); + struct weak_reference *weak_reference = impl_from_IWeakReference( weak_reference_source->weak_reference ); + return IUnknown_AddRef( weak_reference->object ); +} + +static ULONG WINAPI weak_reference_source_Release( IWeakReferenceSource *iface ) +{ + struct weak_reference_source *weak_reference_source = impl_from_IWeakReferenceSource( iface ); + struct weak_reference *weak_reference = impl_from_IWeakReference( weak_reference_source->weak_reference ); + return IUnknown_Release( weak_reference->object ); +} + +static HRESULT WINAPI weak_reference_source_GetWeakReference( IWeakReferenceSource *iface, + IWeakReference **weak_reference ) +{ + struct weak_reference_source *impl = impl_from_IWeakReferenceSource( iface ); + + *weak_reference = impl->weak_reference; + IWeakReference_AddRef( *weak_reference ); + return S_OK; +} + +static const struct IWeakReferenceSourceVtbl weak_reference_source_vtbl = +{ + weak_reference_source_QueryInterface, + weak_reference_source_AddRef, + weak_reference_source_Release, + weak_reference_source_GetWeakReference, +}; + +static HRESULT weak_reference_create( IUnknown *object, IWeakReference **out ) +{ + struct weak_reference *weak_reference; + + if (!(weak_reference = calloc( 1, sizeof(*weak_reference) ))) + return E_OUTOFMEMORY; + + weak_reference->IWeakReference_iface.lpVtbl = &weak_reference_vtbl; + weak_reference->ref_strong = 1; + weak_reference->ref_weak = 1; + weak_reference->object = object; + *out = &weak_reference->IWeakReference_iface; + return S_OK; +} + +HRESULT weak_reference_source_init( struct weak_reference_source *source, IUnknown *object ) +{ + source->IWeakReferenceSource_iface.lpVtbl = &weak_reference_source_vtbl; + return weak_reference_create( object, &source->weak_reference ); +} + +ULONG weak_reference_strong_add_ref( struct weak_reference_source *source ) +{ + struct weak_reference *impl = impl_from_IWeakReference( source->weak_reference ); + return InterlockedIncrement( &impl->ref_strong ); +} + +ULONG weak_reference_strong_release( struct weak_reference_source *source ) +{ + struct weak_reference *impl = impl_from_IWeakReference( source->weak_reference ); + ULONG ref = InterlockedDecrement( &impl->ref_strong ); + + if (!ref) + IWeakReference_Release( source->weak_reference ); + return ref; +} diff --git a/dlls/windows.devices.enumeration/weakref.h b/dlls/windows.devices.enumeration/weakref.h new file mode 100644 index 00000000000..7d4bc22b087 --- /dev/null +++ b/dlls/windows.devices.enumeration/weakref.h @@ -0,0 +1,38 @@ +/* WinRT weak reference helpers + * + * Copyright 2025 Zhiyi Zhang 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 + */ + +#ifndef __WINE_WEAKREF_H +#define __WINE_WEAKREF_H + +#include "weakreference.h" + +struct weak_reference_source +{ + IWeakReferenceSource IWeakReferenceSource_iface; + IWeakReference *weak_reference; +}; + +/* Initialize a IWeakReferenceSource with the object to manage */ +HRESULT weak_reference_source_init( struct weak_reference_source *source, IUnknown *object ); +/* Add a strong reference to the managed object */ +ULONG weak_reference_strong_add_ref( struct weak_reference_source *source ); +/* Release a strong reference to the managed object */ +ULONG weak_reference_strong_release( struct weak_reference_source *source ); + +#endif /* __WINE_WEAKREF_H */
From: Vibhav Pant vibhavp@gmail.com
--- dlls/windows.devices.enumeration/Makefile.in | 2 +- dlls/windows.devices.enumeration/main.c | 186 +++++++++--------- .../tests/devices.c | 4 +- 3 files changed, 94 insertions(+), 98 deletions(-)
diff --git a/dlls/windows.devices.enumeration/Makefile.in b/dlls/windows.devices.enumeration/Makefile.in index c81a88d2ec7..0a204835ae1 100644 --- a/dlls/windows.devices.enumeration/Makefile.in +++ b/dlls/windows.devices.enumeration/Makefile.in @@ -1,5 +1,5 @@ MODULE = windows.devices.enumeration.dll -IMPORTS = advapi32 cfgmgr32 combase setupapi uuid +IMPORTS = cfgmgr32 combase uuid
SOURCES = \ access.c \ diff --git a/dlls/windows.devices.enumeration/main.c b/dlls/windows.devices.enumeration/main.c index 693e8f5103c..f8462c8faed 100644 --- a/dlls/windows.devices.enumeration/main.c +++ b/dlls/windows.devices.enumeration/main.c @@ -2,6 +2,7 @@ * * Copyright 2021 Gijs Vermeulen * Copyright 2022 Julian Klemann for CodeWeavers + * Copyright 2025 Vibhav Pant * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -18,9 +19,11 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
+#include <assert.h> + #include "initguid.h" #include "private.h" -#include "setupapi.h" +#include "devpropdef.h" #include "devfiltertypes.h" #include "devquery.h"
@@ -28,58 +31,6 @@
WINE_DEFAULT_DEBUG_CHANNEL(enumeration);
-typedef HRESULT (*enum_device_information_cb)( IDeviceInformation *info, void *context ); - -static HRESULT enum_device_information( enum_device_information_cb callback, void *context ) -{ - HKEY iface_key; - HRESULT hr; - DWORD i; - - if (!(iface_key = SetupDiOpenClassRegKeyExW( NULL, KEY_ENUMERATE_SUB_KEYS, DIOCR_INTERFACE, NULL, NULL ))) - return HRESULT_FROM_WIN32( GetLastError() ); - - for (i = 0, hr = S_OK; SUCCEEDED(hr); i++) - { - char buffer[sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) + MAX_PATH * sizeof(WCHAR)]; - SP_DEVICE_INTERFACE_DETAIL_DATA_W *detail = (void *)buffer; - SP_DEVICE_INTERFACE_DATA iface = {.cbSize = sizeof(iface)}; - HDEVINFO set = INVALID_HANDLE_VALUE; - GUID iface_class; - WCHAR name[40]; - DWORD j, len; - LSTATUS ret; - - len = ARRAY_SIZE(name); - ret = RegEnumKeyExW( iface_key, i, name, &len, NULL, NULL, NULL, NULL ); - if (ret == ERROR_NO_MORE_ITEMS) break; - if (ret) hr = HRESULT_FROM_WIN32( ret ); - - if (SUCCEEDED(hr) && SUCCEEDED(hr = CLSIDFromString( name, &iface_class ))) - { - set = SetupDiGetClassDevsW( &iface_class, NULL, NULL, DIGCF_DEVICEINTERFACE ); - if (set == INVALID_HANDLE_VALUE) hr = HRESULT_FROM_WIN32( GetLastError() ); - } - - for (j = 0; SUCCEEDED(hr) && SetupDiEnumDeviceInterfaces( set, NULL, &iface_class, j, &iface ); j++) - { - IDeviceInformation *info; - - detail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W); - if (!SetupDiGetDeviceInterfaceDetailW( set, &iface, detail, sizeof(buffer), NULL, NULL )) continue; - - if (SUCCEEDED(hr = device_information_create( detail->DevicePath, &info ))) - { - hr = callback( info, context ); - IDeviceInformation_Release( info ); - } - } - } - - RegCloseKey( iface_key ); - return hr; -} - struct device_watcher { IDeviceWatcher IDeviceWatcher_iface; @@ -92,6 +43,7 @@ struct device_watcher
CRITICAL_SECTION cs; DeviceWatcherStatus status; + HDEVQUERY query; };
static inline struct device_watcher *impl_from_IDeviceWatcher( IDeviceWatcher *iface ) @@ -148,6 +100,7 @@ static ULONG WINAPI device_watcher_Release( IDeviceWatcher *iface ) WindowsDeleteString( impl->filter ); impl->cs.DebugInfo->Spare[0] = 0; DeleteCriticalSection( &impl->cs ); + if (impl->query) DevCloseObjectQuery( impl->query ); free( impl ); }
@@ -255,37 +208,86 @@ static HRESULT WINAPI device_watcher_get_Status( IDeviceWatcher *iface, DeviceWa return S_OK; }
-static HRESULT add_device_information( IDeviceInformation *info, void *invoker ) +static const char *debugstr_DEV_QUERY_RESULT_ACTION_DATA( const DEV_QUERY_RESULT_ACTION_DATA *data ) { - struct device_watcher *impl = impl_from_IDeviceWatcher( (IDeviceWatcher *)invoker ); - typed_event_handlers_notify( &impl->added_handlers, (IInspectable *)invoker, (IInspectable *)info ); - return S_OK; + const DEV_OBJECT *obj = &data->Data.DeviceObject; + if (!data) return wine_dbg_sprintf( "(null)" ); + if (data->Action == DevQueryResultStateChange) + return wine_dbg_sprintf( "{%d {%d}}", data->Action, data->Data.State ); + return wine_dbg_sprintf( "{%d {{%d %s %lu %p}}}", data->Action, obj->ObjectType, debugstr_w( obj->pszObjectId ), obj->cPropertyCount, obj->pProperties ); }
-static HRESULT device_watcher_start_async( IUnknown *invoker, IUnknown *param, PROPVARIANT *result ) +static void WINAPI device_object_query_callback( HDEVQUERY query, void *data, + const DEV_QUERY_RESULT_ACTION_DATA *action_data ) { - struct device_watcher *impl = impl_from_IDeviceWatcher( (IDeviceWatcher *)invoker ); - DeviceWatcherStatus status; + struct device_watcher *watcher; + IWeakReference *weak = data; + IDeviceWatcher *iface; HRESULT hr;
- hr = enum_device_information( add_device_information, invoker ); + TRACE( "query %p, data %p, action_data %s.\n", query, data, debugstr_DEV_QUERY_RESULT_ACTION_DATA( action_data ) );
- EnterCriticalSection( &impl->cs ); - if (FAILED(hr)) status = DeviceWatcherStatus_Aborted; - else if (impl->status == DeviceWatcherStatus_Stopping) status = DeviceWatcherStatus_Stopped; - else status = DeviceWatcherStatus_EnumerationCompleted; - impl->status = status; - LeaveCriticalSection( &impl->cs ); + if (FAILED(hr = IWeakReference_Resolve( weak, &IID_IDeviceWatcher, (IInspectable **)&iface )) || !iface) + { + if (action_data->Action == DevQueryResultStateChange && + (action_data->Data.State == DevQueryStateClosed || action_data->Data.State == DevQueryStateAborted)) + IWeakReference_Release( weak ); /* No more callbacks are expected, so we can release the weak ref. */ + return; + } + watcher = impl_from_IDeviceWatcher( iface );
- if (status == DeviceWatcherStatus_Stopped) typed_event_handlers_notify( &impl->stopped_handlers, (IInspectable *)invoker, NULL ); - if (status == DeviceWatcherStatus_EnumerationCompleted) typed_event_handlers_notify( &impl->enumerated_handlers, (IInspectable *)invoker, NULL ); - return S_OK; + switch (action_data->Action) + { + case DevQueryResultStateChange: + switch (action_data->Data.State) + { + case DevQueryStateClosed: + EnterCriticalSection( &watcher->cs ); + watcher->status = DeviceWatcherStatus_Stopped; + LeaveCriticalSection( &watcher->cs ); + typed_event_handlers_notify( &watcher->stopped_handlers, (IInspectable *)iface, NULL ); + IWeakReference_Release( weak ); + break; + case DevQueryStateAborted: + EnterCriticalSection( &watcher->cs ); + watcher->status = DeviceWatcherStatus_Aborted; + DevCloseObjectQuery( watcher->query ); + watcher->query = NULL; + LeaveCriticalSection( &watcher->cs ); + IWeakReference_Release( weak ); + break; + case DevQueryStateEnumCompleted: + EnterCriticalSection( &watcher->cs ); + watcher->status = DeviceWatcherStatus_EnumerationCompleted; + LeaveCriticalSection( &watcher->cs ); + + typed_event_handlers_notify( &watcher->enumerated_handlers, (IInspectable *)iface, NULL ); + break; + default: + FIXME( "Unhandled DEV_QUERY_STATE value: %d\n", action_data->Data.State ); + break; + } + break; + case DevQueryResultAdd: + { + IDeviceInformation *info; + if (FAILED(hr = device_information_create( action_data->Data.DeviceObject.pszObjectId, &info ))) + break; + typed_event_handlers_notify( &watcher->added_handlers, (IInspectable *)iface, (IInspectable *)info ); + IDeviceInformation_Release( info ); + break; + } + default: + FIXME( "Unhandled DEV_QUERY_RESULT_ACTION value: %d\n", action_data->Action ); + break; + } + + IDeviceWatcher_Release( iface ); }
static HRESULT WINAPI device_watcher_Start( IDeviceWatcher *iface ) { struct device_watcher *impl = impl_from_IDeviceWatcher( iface ); - IAsyncAction *async; HRESULT hr = S_OK;
FIXME( "iface %p: semi-stub!\n", iface ); @@ -302,37 +304,35 @@ static HRESULT WINAPI device_watcher_Start( IDeviceWatcher *iface ) 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; - + default: assert( FALSE ); break; case DeviceWatcherStatus_Aborted: case DeviceWatcherStatus_Created: case DeviceWatcherStatus_Stopped: + { + IWeakReference *weak; + HRESULT hr; + + IWeakReferenceSource_GetWeakReference( &impl->weak_reference_source.IWeakReferenceSource_iface, &weak ); + hr = DevCreateObjectQuery( DevObjectTypeDeviceInterfaceDisplay, DevQueryFlagAsyncClose, 0, NULL, 0, NULL, device_object_query_callback, weak, + &impl->query ); + if (FAILED(hr)) + { + ERR( "Failed to create device query: %#lx\n", hr ); + IWeakReference_Release( weak ); + break; + } impl->status = DeviceWatcherStatus_Started; - hr = async_action_create( (IUnknown *)iface, device_watcher_start_async, &async ); - if (SUCCEEDED(hr)) 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 ); - IAsyncAction *async; HRESULT hr = S_OK;
TRACE( "iface %p\n", iface ); @@ -344,16 +344,12 @@ static HRESULT WINAPI device_watcher_Stop( IDeviceWatcher *iface ) 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; - + default: assert( FALSE ); break; case DeviceWatcherStatus_EnumerationCompleted: - impl->status = DeviceWatcherStatus_Stopping; - hr = async_action_create( (IUnknown *)iface, device_watcher_stop_async, &async ); - if (SUCCEEDED(hr)) IAsyncAction_Release( async ); - break; case DeviceWatcherStatus_Started: impl->status = DeviceWatcherStatus_Stopping; - /* an async start is in progress, let it handle stopped state change */ + DevCloseObjectQuery( impl->query ); + impl->query = NULL; break; } LeaveCriticalSection( &impl->cs ); diff --git a/dlls/windows.devices.enumeration/tests/devices.c b/dlls/windows.devices.enumeration/tests/devices.c index 529215df0f2..e4bb1349f6d 100644 --- a/dlls/windows.devices.enumeration/tests/devices.c +++ b/dlls/windows.devices.enumeration/tests/devices.c @@ -417,7 +417,7 @@ static void test_DeviceInformation( void ) ok( status == DeviceWatcherStatus_Started, "got status %u\n", status );
ref = IDeviceWatcher_AddRef( device_watcher ); - todo_wine ok( ref == 2, "got ref %lu\n", ref ); + 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" ); @@ -464,7 +464,7 @@ static void test_DeviceInformation( void ) ok( status == DeviceWatcherStatus_Started, "got status %u\n", status );
ref = IDeviceWatcher_AddRef( device_watcher ); - todo_wine ok( ref == 2, "got ref %lu\n", ref ); + 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" );
v4:
* <span dir="">Use </span>`` assert( FALSE ) ``<span dir=""> instead of `</span>`` DEFAULT_UNREACHABLE` ``
This merge request was approved by Rémi Bernon.