From: Vibhav Pant vibhavp@gmail.com
--- dlls/windows.devices.enumeration/main.c | 209 ++++++++++++++---- .../tests/devices.c | 36 ++- 2 files changed, 183 insertions(+), 62 deletions(-)
diff --git a/dlls/windows.devices.enumeration/main.c b/dlls/windows.devices.enumeration/main.c index c965ca363e0..a130ffd523d 100644 --- a/dlls/windows.devices.enumeration/main.c +++ b/dlls/windows.devices.enumeration/main.c @@ -35,7 +35,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(enumeration); struct devquery_params { IUnknown IUnknown_iface; + DEV_OBJECT_TYPE type; struct aqs_expr *expr; + DEVPROPCOMPKEY *prop_keys; + ULONG prop_keys_len; LONG ref; };
@@ -78,6 +81,7 @@ static ULONG WINAPI devquery_params_Release( IUnknown *iface ) if (!ref) { free_aqs_expr( impl->expr ); + free( impl->prop_keys ); free( impl ); } return ref; @@ -91,7 +95,7 @@ static const IUnknownVtbl devquery_params_vtbl = devquery_params_Release, };
-static HRESULT devquery_params_create( struct aqs_expr *expr, IUnknown **out ) +static HRESULT devquery_params_create( DEV_OBJECT_TYPE type, struct aqs_expr *expr, DEVPROPCOMPKEY *prop_keys, ULONG prop_keys_len, IUnknown **out ) { struct devquery_params *impl;
@@ -100,7 +104,10 @@ static HRESULT devquery_params_create( struct aqs_expr *expr, IUnknown **out )
impl->IUnknown_iface.lpVtbl = &devquery_params_vtbl; impl->ref = 1; + impl->type = type; impl->expr = expr; + impl->prop_keys = prop_keys; + impl->prop_keys_len = prop_keys_len; *out = &impl->IUnknown_iface; return S_OK; } @@ -399,8 +406,8 @@ static HRESULT WINAPI device_watcher_Start( IDeviceWatcher *iface ) }
IWeakReferenceSource_GetWeakReference( &impl->weak_reference_source.IWeakReferenceSource_iface, &weak ); - hr = DevCreateObjectQuery( DevObjectTypeDeviceInterfaceDisplay, DevQueryFlagAsyncClose, ARRAY_SIZE( device_iface_default_props ), - device_iface_default_props, filters_len, filters, device_object_query_callback, weak, &impl->query ); + hr = DevCreateObjectQuery( query_params->type, DevQueryFlagAsyncClose, query_params->prop_keys_len, query_params->prop_keys, filters_len, filters, + device_object_query_callback, weak, &impl->query ); if (FAILED(hr)) { ERR( "Failed to create device query: %#lx\n", hr ); @@ -468,10 +475,100 @@ static const struct IDeviceWatcherVtbl device_watcher_vtbl = device_watcher_Stop, };
-static HRESULT device_watcher_create( HSTRING filter, IDeviceWatcher **out ) +struct devpropcompkey_buf { + DEVPROPCOMPKEY *keys; + ULONG len; + ULONG cap; +}; + +static BOOL devpropcompkey_buf_find_devpropkey( const struct devpropcompkey_buf *buf, DEVPROPKEY key ) +{ + ULONG i; + + for (i = 0; i < buf->len; i++) + if (IsEqualDevPropKey(buf->keys[i].Key, key)) return TRUE; + return FALSE; +} + +static HRESULT devpropcompkey_buf_init( struct devpropcompkey_buf *buf, const DEVPROPCOMPKEY *keys, ULONG len ) +{ + if (!(buf->keys = calloc( len, sizeof( *keys )))) return E_OUTOFMEMORY; + buf->len = buf->cap = len; + memcpy( buf->keys, keys, len * sizeof( *keys ) ); + return S_OK; +} + +static HRESULT devpropcompkey_buf_append_devpropkey( struct devpropcompkey_buf *buf, DEVPROPKEY key ) +{ + DEVPROPCOMPKEY *tmp; + + if (devpropcompkey_buf_find_devpropkey( buf, key )) return S_OK; + + if (buf->len == buf->cap) + { + ULONG cap = buf->cap > 1 ? (buf->cap * 1.5) : 2; + + if (!(tmp = realloc ( buf->keys, sizeof( *buf->keys ) * cap ))) return E_OUTOFMEMORY; + buf->keys = tmp; + buf->cap = cap; + } + + tmp = &buf->keys[buf->len]; + buf->len++; + tmp->Key = key; + tmp->Store = DEVPROP_STORE_SYSTEM; + tmp->LocaleName = NULL; + + return S_OK; +} + +static HRESULT WINAPI append_devpropcompkeys_from_names( IIterable_HSTRING *names_iterable, struct devpropcompkey_buf *keys ) +{ + IIterator_HSTRING *names; + boolean valid; + HRESULT hr; + + if (FAILED(hr = IIterable_HSTRING_First( names_iterable, &names ))) return hr; + hr = IIterator_HSTRING_get_HasCurrent( names, &valid ); + while (SUCCEEDED(hr) && valid) + { + const WCHAR *buf; + DEVPROPKEY key; + HSTRING name; + + if (FAILED(hr = IIterator_HSTRING_get_Current( names, &name ))) break; + buf = WindowsGetStringRawBuffer( name, NULL ); + if (buf[0] == '{') + hr = PSPropertyKeyFromString( buf, (PROPERTYKEY *)&key ); + else + hr = PSGetPropertyKeyFromName( buf, (PROPERTYKEY *)&key ); + WindowsDeleteString( name ); + if (FAILED(hr) || FAILED(hr = devpropcompkey_buf_append_devpropkey( keys, key ))) break; + hr = IIterator_HSTRING_MoveNext( names, &valid ); + } + + IIterator_HSTRING_Release( names ); + return hr; +} + +static HRESULT device_watcher_create( HSTRING filter, IIterable_HSTRING *additional_props, DeviceInformationKind kind, IDeviceWatcher **out ) +{ + static const DEV_OBJECT_TYPE kind_type[] = { + DevObjectTypeUnknown, + DevObjectTypeDeviceInterfaceDisplay, + DevObjectTypeDeviceContainerDisplay, + DevObjectTypeDevice, + DevObjectTypeDeviceInterfaceClass, + DevObjectTypeAEP, + DevObjectTypeAEPContainer, + DevObjectTypeAEPService, + DevObjectTypeDevicePanel, + }; + DEV_OBJECT_TYPE type = DevObjectTypeUnknown; + struct devpropcompkey_buf prop_keys = {0}; + struct aqs_expr *expr = NULL; struct device_watcher *impl; - struct aqs_expr *expr; HRESULT hr;
if (!(impl = calloc( 1, sizeof(*impl) ))) return E_OUTOFMEMORY; @@ -483,19 +580,19 @@ static HRESULT device_watcher_create( HSTRING filter, IDeviceWatcher **out ) return hr; } /* If the filter string is all whitespaces, we return E_INVALIDARG in IDeviceWatcher_Start, not here. */ - if (FAILED(hr = aqs_parse_query( WindowsGetStringRawBuffer( filter, NULL ), &expr, &impl->aqs_all_whitespace )) && !impl->aqs_all_whitespace) - { - weak_reference_strong_release( &impl->weak_reference_source ); - free( impl ); - return hr; - } - if (FAILED(hr = devquery_params_create( expr, &impl->query_params ))) + if (FAILED(hr = aqs_parse_query( WindowsGetStringRawBuffer( filter, NULL ), &expr, &impl->aqs_all_whitespace )) && !impl->aqs_all_whitespace) goto failed; + + if (kind < ARRAY_SIZE( kind_type )) { - free_aqs_expr( expr ); - weak_reference_strong_release( &impl->weak_reference_source ); - free( impl ); - return hr; + type = kind_type[kind]; + if (kind == DeviceInformationKind_DeviceInterface && + FAILED(hr = devpropcompkey_buf_init( &prop_keys, device_iface_default_props, ARRAY_SIZE( device_iface_default_props ) ))) + goto failed; } + else FIXME( "Unknown DeviceInformationKind value: %u\n", kind ); + + if (additional_props && FAILED(hr = append_devpropcompkeys_from_names( additional_props, &prop_keys ))) goto failed; + if (FAILED(hr = devquery_params_create( type, expr, prop_keys.keys, prop_keys.len, &impl->query_params ))) goto failed;
list_init( &impl->added_handlers ); list_init( &impl->enumerated_handlers ); @@ -508,6 +605,13 @@ static HRESULT device_watcher_create( HSTRING filter, IDeviceWatcher **out ) *out = &impl->IDeviceWatcher_iface; TRACE( "created DeviceWatcher %p\n", *out ); return S_OK; + +failed: + free( prop_keys.keys ); + free_aqs_expr( expr ); + weak_reference_strong_release( &impl->weak_reference_source ); + free( impl ); + return hr; }
struct device_information_statics @@ -650,8 +754,7 @@ static HRESULT find_all_async( IUnknown *invoker, IUnknown *param, PROPVARIANT * filters_len = params->expr->len; } if (FAILED(hr = vector_create( &iids, (void *)&vector ))) return hr; - hr = DevGetObjects( DevObjectTypeDeviceInterfaceDisplay, DevQueryFlagNone, ARRAY_SIZE( device_iface_default_props ), device_iface_default_props, filters_len, filters, - &len, &objects ); + hr = DevGetObjects( params->type, DevQueryFlagNone, params->prop_keys_len, params->prop_keys, filters_len, filters, &len, &objects ); if (FAILED(hr)) { IVector_IInspectable_Release( vector ); @@ -680,7 +783,7 @@ static HRESULT WINAPI device_statics_FindAllAsync( IDeviceInformationStatics *if IAsyncOperation_DeviceInformationCollection **op ) { TRACE( "iface %p, op %p\n", iface, op ); - return IDeviceInformationStatics_FindAllAsyncAqsFilter( iface, NULL, op ); + return IDeviceInformationStatics_FindAllAsyncAqsFilterAndAdditionalProperties( iface, NULL, NULL, op ); }
static HRESULT WINAPI device_statics_FindAllAsyncDeviceClass( IDeviceInformationStatics *iface, DeviceClass class, @@ -693,34 +796,41 @@ static HRESULT WINAPI device_statics_FindAllAsyncDeviceClass( IDeviceInformation static HRESULT WINAPI device_statics_FindAllAsyncAqsFilter( IDeviceInformationStatics *iface, HSTRING filter, IAsyncOperation_DeviceInformationCollection **op ) { - struct aqs_expr *expr; - IUnknown *params; - HRESULT hr; - TRACE( "iface %p, aqs %p, op %p\n", iface, debugstr_hstring(filter), op ); - - if (FAILED(hr = aqs_parse_query(WindowsGetStringRawBuffer( filter, NULL ), &expr, NULL ))) return hr; - if (FAILED(hr = devquery_params_create( expr, ¶ms ))) - { - free_aqs_expr( expr ); - return hr; - } - return async_operation_inspectable_create( &IID_IAsyncOperation_DeviceInformationCollection, (IUnknown *)iface, (IUnknown *)params, - find_all_async, (IAsyncOperation_IInspectable **)op ); + return IDeviceInformationStatics_FindAllAsyncAqsFilterAndAdditionalProperties( iface, filter, NULL, op ); }
static HRESULT WINAPI device_statics_FindAllAsyncAqsFilterAndAdditionalProperties( IDeviceInformationStatics *iface, HSTRING filter, IIterable_HSTRING *additional_properties, IAsyncOperation_DeviceInformationCollection **op ) { - FIXME( "iface %p, aqs %p, additional_properties %p, op %p stub!\n", iface, debugstr_hstring(filter), additional_properties, op ); - return E_NOTIMPL; + struct devpropcompkey_buf prop_keys = {0}; + struct aqs_expr *expr = NULL; + IUnknown *params; + HRESULT hr; + + TRACE( "iface %p, aqs %s, additional_properties %p, op %p\n", iface, debugstr_hstring(filter), additional_properties, op ); + + if (FAILED(hr = devpropcompkey_buf_init( &prop_keys, device_iface_default_props, ARRAY_SIZE( device_iface_default_props ) ))) return hr; + if (additional_properties && FAILED(hr = append_devpropcompkeys_from_names( additional_properties, &prop_keys ))) goto failed; + if (FAILED(hr = aqs_parse_query(WindowsGetStringRawBuffer( filter, NULL ), &expr, NULL ))) goto failed; + if (FAILED(hr = devquery_params_create( DevObjectTypeDeviceInterfaceDisplay, expr, prop_keys.keys, prop_keys.len, ¶ms ))) goto failed; + + hr = async_operation_inspectable_create( &IID_IAsyncOperation_DeviceInformationCollection, (IUnknown *)iface, params, find_all_async, + (IAsyncOperation_IInspectable **)op ); + IUnknown_Release( params ); + if (SUCCEEDED(hr)) return hr; + +failed: + free( prop_keys.keys ); + free_aqs_expr( expr ); + return hr; }
static HRESULT WINAPI device_statics_CreateWatcher( IDeviceInformationStatics *iface, IDeviceWatcher **watcher ) { TRACE( "iface %p, watcher %p\n", iface, watcher ); - return device_watcher_create( NULL, watcher ); + return IDeviceInformationStatics_CreateWatcherAqsFilterAndAdditionalProperties( iface, NULL, NULL, watcher ); }
static HRESULT WINAPI device_statics_CreateWatcherDeviceClass( IDeviceInformationStatics *iface, DeviceClass class, IDeviceWatcher **watcher ) @@ -732,14 +842,14 @@ static HRESULT WINAPI device_statics_CreateWatcherDeviceClass( IDeviceInformatio 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 ); + return IDeviceInformationStatics_CreateWatcherAqsFilterAndAdditionalProperties( iface, filter, NULL, watcher ); }
static HRESULT WINAPI device_statics_CreateWatcherAqsFilterAndAdditionalProperties( IDeviceInformationStatics *iface, HSTRING filter, IIterable_HSTRING *additional_properties, IDeviceWatcher **watcher ) { - FIXME( "iface %p, aqs %p, additional_properties %p, watcher %p stub!\n", iface, debugstr_hstring(filter), additional_properties, watcher ); - return E_NOTIMPL; + TRACE( "iface %p, aqs %s, additional_properties %p, watcher %p\n", iface, debugstr_hstring(filter), additional_properties, watcher ); + return device_watcher_create( filter, additional_properties, DeviceInformationKind_DeviceInterface, watcher ); }
static const struct IDeviceInformationStaticsVtbl device_statics_vtbl = @@ -791,13 +901,30 @@ static HRESULT WINAPI device_statics2_FindAllAsync( IDeviceInformationStatics2 * return E_NOTIMPL; }
+static const char *debugstr_DeviceInformationKind( DeviceInformationKind kind ) +{ + static const char *str[] = { + "Unknown", + "DeviceInterface", + "DeviceContainer", + "Device", + "DeviceInterfaceClass", + "AssociationEndpoint", + "AssociationEndpointContainer", + "AssociationEndpointService", + "DevicePanel", + }; + if (kind < ARRAY_SIZE( str )) return wine_dbg_sprintf( "DeviceInformationKind_%s", str[kind] ); + return wine_dbg_sprintf( "(unknown %u)\n", kind ); +} + static HRESULT WINAPI device_statics2_CreateWatcher( IDeviceInformationStatics2 *iface, HSTRING filter, IIterable_HSTRING *additional_properties, DeviceInformationKind kind, IDeviceWatcher **watcher ) { - FIXME( "iface %p, filter %s, additional_properties %p, kind %u, watcher %p semi-stub!\n", - iface, debugstr_hstring( filter ), additional_properties, kind, watcher ); - return device_watcher_create( filter, watcher ); + TRACE( "iface %p, filter %s, additional_properties %p, kind %s, watcher %p\n", + iface, debugstr_hstring( filter ), additional_properties, debugstr_DeviceInformationKind( kind ), watcher ); + return device_watcher_create( filter, additional_properties, kind, 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 a4294075e38..d91546e3610 100644 --- a/dlls/windows.devices.enumeration/tests/devices.c +++ b/dlls/windows.devices.enumeration/tests/devices.c @@ -1003,36 +1003,30 @@ static void test_DeviceInformation( void ) IVectorView_DeviceInformation_Release( info_collection );
hr = IDeviceInformationStatics_FindAllAsyncAqsFilterAndAdditionalProperties( device_info_statics, NULL, NULL, &info_collection_async ); - todo_wine ok( hr == S_OK, "got hr %#lx\n", hr ); + ok( hr == S_OK, "got hr %#lx\n", hr );
- if (SUCCEEDED( hr )) - { - await_device_information_collection( info_collection_async ); - check_device_information_collection_async_no_id( info_collection_async, Completed, S_OK, &info_collection ); - IAsyncOperation_DeviceInformationCollection_Release( info_collection_async ); - test_DeviceInformationCollection( __LINE__, info_collection, device_iface_exp_props, ARRAY_SIZE( device_iface_exp_props ) - 1 ); - IVectorView_DeviceInformation_Release( info_collection ); - } + await_device_information_collection( info_collection_async ); + check_device_information_collection_async_no_id( info_collection_async, Completed, S_OK, &info_collection ); + IAsyncOperation_DeviceInformationCollection_Release( info_collection_async ); + test_DeviceInformationCollection( __LINE__, info_collection, device_iface_exp_props, ARRAY_SIZE( device_iface_exp_props ) - 1 ); + IVectorView_DeviceInformation_Release( info_collection );
additional_props = iterable_hstring_create( device_iface_additional_props, ARRAY_SIZE( device_iface_additional_props ) ); hr = IDeviceInformationStatics_FindAllAsyncAqsFilterAndAdditionalProperties( device_info_statics, NULL, additional_props, &info_collection_async ); - todo_wine ok( hr == S_OK, "got hr %#lx\n", hr ); + ok( hr == S_OK, "got hr %#lx\n", hr ); IIterable_HSTRING_Release( additional_props ); - if (SUCCEEDED( hr )) - { - await_device_information_collection( info_collection_async ); - check_device_information_collection_async_no_id( info_collection_async, Completed, S_OK, &info_collection ); - IAsyncOperation_DeviceInformationCollection_Release( info_collection_async ); - test_DeviceInformationCollection( __LINE__, info_collection, device_iface_exp_props, ARRAY_SIZE( device_iface_exp_props ) ); - IVectorView_DeviceInformation_Release( info_collection ); - } + await_device_information_collection( info_collection_async ); + check_device_information_collection_async_no_id( info_collection_async, Completed, S_OK, &info_collection ); + IAsyncOperation_DeviceInformationCollection_Release( info_collection_async ); + test_DeviceInformationCollection( __LINE__, info_collection, device_iface_exp_props, ARRAY_SIZE( device_iface_exp_props ) ); + IVectorView_DeviceInformation_Release( info_collection );
for (i = 0; i < ARRAY_SIZE( device_nonexistent_props ); i++ ) { winetest_push_context( "device_nonexistent_props[%d]", i ); additional_props = iterable_hstring_create( &device_nonexistent_props[i], 1 ); hr = IDeviceInformationStatics_FindAllAsyncAqsFilterAndAdditionalProperties( device_info_statics, NULL, additional_props, &info_collection_async ); - todo_wine ok( hr == TYPE_E_ELEMENTNOTFOUND, "got hr %#lx\n", hr ); + ok( hr == TYPE_E_ELEMENTNOTFOUND, "got hr %#lx\n", hr ); IIterable_HSTRING_Release( additional_props ); winetest_pop_context(); } @@ -1042,7 +1036,7 @@ static void test_DeviceInformation( void ) winetest_push_context( "device_invalid_props[%d]", i ); additional_props = iterable_hstring_create( &device_invalid_props[i], 1 ); hr = IDeviceInformationStatics_FindAllAsyncAqsFilterAndAdditionalProperties( device_info_statics, NULL, additional_props, &info_collection_async ); - todo_wine ok( hr == E_INVALIDARG, "got hr %#lx\n", hr ); + ok( hr == E_INVALIDARG, "got hr %#lx\n", hr ); IIterable_HSTRING_Release( additional_props ); winetest_pop_context(); } @@ -1369,7 +1363,7 @@ static void test_aqs_filters( void ) hr = WindowsCreateString( filter_iface_display, wcslen( filter_iface_display ), &str ); ok( hr == S_OK, "got hr %#lx\n", hr ); hr = IDeviceInformationStatics_FindAllAsyncAqsFilterAndAdditionalProperties( statics, str, props_iterable, &info_collection_async ); - todo_wine ok( hr == S_OK, "got hr %#lx\n", hr ); + ok( hr == S_OK, "got hr %#lx\n", hr ); WindowsDeleteString( str ); IIterable_HSTRING_Release( props_iterable ); if (SUCCEEDED( hr ))