-- v5: windows.devices.enumeration: Implement IDeviceInformationStatics::{FindAllAsyncAqsFilterAndAdditionalProperties, CreateWatcherAqsFilterAndAdditionalProperties}. windows.devices.enumeration: Implement IDeviceInformation::get_Properties. windows.devices.enumeration/tests: Add tests for IDeviceInformationStatics::FindAllAsyncAqsFilterAndAdditionalProperties. windows.devices.enumeration/tests: Add tests for device properties for IDeviceInformation objects.
From: Vibhav Pant vibhavp@gmail.com
--- .../tests/Makefile.in | 2 +- .../tests/devices.c | 217 +++++++++++++++++- 2 files changed, 209 insertions(+), 10 deletions(-)
diff --git a/dlls/windows.devices.enumeration/tests/Makefile.in b/dlls/windows.devices.enumeration/tests/Makefile.in index 0b47593720c..200e6707f58 100644 --- a/dlls/windows.devices.enumeration/tests/Makefile.in +++ b/dlls/windows.devices.enumeration/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = windows.devices.enumeration.dll -IMPORTS = combase uuid +IMPORTS = cfgmgr32 combase propsys uuid
SOURCES = \ devices.c diff --git a/dlls/windows.devices.enumeration/tests/devices.c b/dlls/windows.devices.enumeration/tests/devices.c index 433f9c33f2b..b003193b42a 100644 --- a/dlls/windows.devices.enumeration/tests/devices.c +++ b/dlls/windows.devices.enumeration/tests/devices.c @@ -24,6 +24,10 @@ #include "winbase.h" #include "winerror.h" #include "winstring.h" +#include "devpropdef.h" +#include "devfiltertypes.h" +#include "devquery.h" +#include "propsys.h"
#include "initguid.h" #include "roapi.h" @@ -131,6 +135,12 @@ static ITypedEventHandler_IInspectable_IInspectable *inspectable_event_handler_c return &handler->iface; }
+struct device_property +{ + const WCHAR *name; + PropertyType type; +}; + struct device_watcher_added_handler_data { LONG devices_added; @@ -344,27 +354,215 @@ static void check_device_information_collection_async_( int line, IAsyncOperatio } }
-static void test_DeviceInformation_obj( int line, IDeviceInformation *info ) +/* Find the DEVPROPKEY associated with prop_name, ensure propval matches the value retrieved from DevGetObjectProperties. + * If propval is NULL, then check the retrieved DEVPROPERTY has Type DEVPROP_TYPE_EMPTY. + * This assumes that the DeviceInformationKind is DeviceInterface (DevObjectTypeDeviceInterfaceDisplay). */ +static void test_DeviceInformation_property( HSTRING device_id, const WCHAR *prop_name, IPropertyValue *propval ) { + PropertyType type = 0xdeadbeef; + DEVPROPCOMPKEY comp_key = {0}; + const DEVPROPERTY *prop; + DEVPROPKEY key = {0}; HRESULT hr; - HSTRING str; + ULONG len; + + hr = PSGetPropertyKeyFromName( prop_name, (PROPERTYKEY *)&key ); + ok( hr == S_OK, "got hr %#lx\n", hr ); + + comp_key.Key = key; + prop = NULL; + len = 0; + hr = DevGetObjectProperties( DevObjectTypeDeviceInterfaceDisplay, WindowsGetStringRawBuffer( device_id, NULL ), 0, 1, &comp_key, &len, &prop ); + ok( hr == S_OK, "got hr %#lx\n", hr ); + ok( !!prop, "got prop %p\n", prop ); + ok( len == 1, "got len %lu != 1\n", len ); + + if (propval) + { + hr = IPropertyValue_get_Type( propval, &type ); + ok( hr == S_OK, "got hr %#lx\n", hr ); + + switch (type) + { + case PropertyType_Boolean: + { + boolean bool_val, exp_val; + + hr = IPropertyValue_GetBoolean( propval, &bool_val ); + ok( hr == S_OK, "got hr %#lx\n", hr ); + ok( prop->Type == DEVPROP_TYPE_BOOLEAN, "got Type %#lx\n", prop->Type ); + exp_val = !!*(DEVPROP_BOOLEAN *)prop->Buffer; + ok( bool_val == exp_val, "got bool_val %d != %d\n", bool_val, exp_val ); + break; + } + case PropertyType_String: + { + HSTRING str; + + hr = IPropertyValue_GetString( propval, &str ); + ok( hr == S_OK, "got hr %#lx\n", hr ); + ok( prop->Type == DEVPROP_TYPE_STRING || prop->Type == DEVPROP_TYPE_STRING_INDIRECT, "got Type %#lx\n", prop->Type ); + /* TODO: + * For DEVPROP_TYPE_STRING_INDIRECT, WinRT extracts the locale-specific string from the referenced INF. + * System.ItemNameDisplay's value is formatted differently by WinRT. */ + if (prop->Type == DEVPROP_TYPE_STRING) + ok( !wcsicmp( WindowsGetStringRawBuffer( str, NULL ), prop->Buffer ) || broken( !wcsicmp( prop_name, L"System.ItemNameDisplay" ) ), + "got str %s != %s\n", debugstr_hstring( str ), debugstr_w( prop->Buffer ) ); + WindowsDeleteString( str ); + break; + } + case PropertyType_Guid: + { + GUID guid; + + hr = IPropertyValue_GetGuid( propval, &guid ); + ok( hr == S_OK, "got hr %#lx\n", hr ); + ok( prop->Type == DEVPROP_TYPE_GUID, "got Type %#lx\n", prop->Type ); + ok( IsEqualGUID( &guid, prop->Buffer ), "got guid %s != %s\n", debugstr_guid( &guid ), debugstr_guid( prop->Buffer ) ); + break; + } + /* Used by System.Devices.PhysicalDeviceLocation */ + case PropertyType_UInt8Array: + { + BYTE *arr = NULL; + UINT32 len = 0; + + hr = IPropertyValue_GetUInt8Array( propval, &len, &arr ); + ok( hr == S_OK, "got hr %#lx\n", hr ); + ok( prop->Type == (DEVPROP_TYPEMOD_ARRAY | DEVPROP_TYPE_BYTE), "got Type %#lx\n", prop->Type ); + ok( prop->BufferSize == sizeof( BYTE ) * len, "got BufferSize %lu\n", prop->BufferSize ); + if (prop->BufferSize == sizeof( BYTE ) * len) + ok( !memcmp( arr, prop->Buffer, len ), "got arr %s != %s \n", debugstr_an( (char *)arr, len ), debugstr_an( (char *)prop->Buffer, len ) ); + CoTaskMemFree( arr ); + break; + } + default: + skip( "Unhandled type %d, skipping.\n", type ); + break; + } + } + else + ok( prop->Type == DEVPROP_TYPE_EMPTY, "got Type %#lx\n", prop->Type ); + + DevFreeObjectProperties( len, prop ); + winetest_pop_context(); +} + + +static void test_DeviceInformation_obj( int line, IDeviceInformation *info ) +{ + HSTRING str = NULL, id = NULL; boolean bool_val; + HRESULT hr;
- hr = IDeviceInformation_get_Id( info, &str ); - ok_(__FILE__, line)( hr == S_OK, "got hr %#lx\n", hr ); - WindowsDeleteString( str ); - str = NULL; + hr = IDeviceInformation_get_Id( info, &id ); + ok_(__FILE__, line)( hr == S_OK, "get_Id failed, got hr %#lx\n", hr ); hr = IDeviceInformation_get_Name( info, &str ); - todo_wine ok_(__FILE__, line)( hr == S_OK, "got hr %#lx\n", hr ); + todo_wine ok_(__FILE__, line)( hr == S_OK, "get_Name failed, got hr %#lx\n", hr ); WindowsDeleteString( str ); hr = IDeviceInformation_get_IsEnabled( info, &bool_val ); - todo_wine ok_(__FILE__, line)( hr == S_OK, "got hr %#lx\n", hr ); + todo_wine ok_(__FILE__, line)( hr == S_OK, "get_IsEnabled failed, got hr %#lx\n", hr ); hr = IDeviceInformation_get_IsDefault( info, &bool_val ); - todo_wine ok_(__FILE__, line)( hr == S_OK, "got hr %#lx\n", hr ); + todo_wine ok_(__FILE__, line)( hr == S_OK, "get_IsDefault failed, got hr %#lx\n", hr ); +} + +static void test_DeviceInformation_properties( IDeviceInformation *info, const struct device_property *exp_props, SIZE_T exp_props_len ) +{ + IIterable_IKeyValuePair_HSTRING_IInspectable *iterable; + IIterator_IKeyValuePair_HSTRING_IInspectable *iterator; + IMapView_HSTRING_IInspectable *properties; + IInspectable *inspectable; + IPropertyValue *propval; + HSTRING str, id = NULL; + boolean valid; + HRESULT hr; + SIZE_T i; + + hr = IDeviceInformation_get_Properties( info, &properties ); + todo_wine ok( hr == S_OK, "got hr %#lx\n", hr ); + if (FAILED(hr)) return; + + hr = IDeviceInformation_get_Id( info, &id ); + ok( hr == S_OK, "got hr %#lx\n", hr ); + for (i = 0; i < exp_props_len; i++) + { + PropertyType type = 0xdeadbeef; + HSTRING_HEADER hdr; + + winetest_push_context( "exp_props[%Iu]", i ); + hr = WindowsCreateStringReference( exp_props[i].name, wcslen( exp_props[i].name ), &hdr, &str ); + ok( hr == S_OK, "got hr %#lx\n", hr ); + hr = IMapView_HSTRING_IInspectable_Lookup( properties, str, &inspectable ); + ok( hr == S_OK, "got hr %#lx\n", hr ); + hr = IInspectable_QueryInterface( inspectable, &IID_IPropertyValue, (void **)&propval ); + ok( hr == S_OK, "got hr %#lx\n", hr ); + IInspectable_Release( inspectable ); + hr = IPropertyValue_get_Type( propval, &type ); + ok( hr == S_OK, "got hr %#lx\n", hr ); + ok(type == exp_props[i].type, "got type %d != %d\n", type, exp_props[i].type ); + IPropertyValue_Release( propval ); + winetest_pop_context(); + } + + hr = IMapView_HSTRING_IInspectable_QueryInterface( properties, &IID_IIterable_IKeyValuePair_HSTRING_IInspectable, (void **)&iterable ); + ok( hr == S_OK, "got hr %#lx\n", hr ); + IMapView_HSTRING_IInspectable_Release( properties ); + hr = IIterable_IKeyValuePair_HSTRING_IInspectable_First( iterable, &iterator ); + ok( hr == S_OK, "got hr %#lx\n", hr ); + IIterable_IKeyValuePair_HSTRING_IInspectable_Release( iterable ); + + i = 0; + valid = FALSE; + hr = IIterator_IKeyValuePair_HSTRING_IInspectable_get_HasCurrent( iterator, &valid ); + ok( hr == S_OK, "got hr %#lx\n", hr ); + while (valid && SUCCEEDED( hr )) + { + IKeyValuePair_HSTRING_IInspectable *pair; + const WCHAR *prop_buf; + + winetest_push_context( "i=%Iu", i++ ); + + hr = IIterator_IKeyValuePair_HSTRING_IInspectable_get_Current( iterator, &pair ); + ok( hr == S_OK, "got hr %#lx\n", hr ); + + str = NULL; + hr = IKeyValuePair_HSTRING_IInspectable_get_Key( pair, &str ); + ok( hr == S_OK, "got hr %#lx\n", hr ); + prop_buf = WindowsGetStringRawBuffer( str, NULL ); + inspectable = NULL; + hr = IKeyValuePair_HSTRING_IInspectable_get_Value( pair, &inspectable ); + ok( hr == S_OK, "got hr %#lx\n", hr ); + IKeyValuePair_HSTRING_IInspectable_Release( pair ); + + propval = NULL; + if (inspectable) + { + hr = IInspectable_QueryInterface( inspectable, &IID_IPropertyValue, (void **)&propval ); + ok( hr == S_OK, "got hr %#lx\n", hr ); + IInspectable_Release( inspectable ); + } + + winetest_push_context("%s: %s", debugstr_hstring( id ), debugstr_w( prop_buf ) ); + test_DeviceInformation_property( id, prop_buf, propval ); + WindowsDeleteString( str ); + winetest_pop_context(); + + hr = IIterator_IKeyValuePair_HSTRING_IInspectable_MoveNext( iterator, &valid ); + ok( hr == S_OK, " got hr %#lx\n", hr ); + + winetest_pop_context(); + } + WindowsDeleteString( id ); + IIterator_IKeyValuePair_HSTRING_IInspectable_Release( iterator ); + }
static void test_DeviceInformation( void ) { + static const struct device_property device_iface_exp_props[] = { + { L"System.Devices.InterfaceEnabled", PropertyType_Boolean }, + { L"System.Devices.DeviceInstanceId", PropertyType_String }, + }; static const WCHAR *device_info_name = L"Windows.Devices.Enumeration.DeviceInformation";
ITypedEventHandler_DeviceWatcher_IInspectable *stopped_handler, *enumerated_handler; @@ -557,6 +755,7 @@ static void test_DeviceInformation( void ) hr = IVectorView_DeviceInformation_GetAt( info_collection, i, &info ); ok( hr == S_OK, "got %#lx\n", hr ); test_DeviceInformation_obj( __LINE__, info ); + test_DeviceInformation_properties( info, device_iface_exp_props, ARRAY_SIZE( device_iface_exp_props ) ); IDeviceInformation_Release( info ); winetest_pop_context(); }
From: Vibhav Pant vibhavp@gmail.com
--- .../tests/devices.c | 376 +++++++++++++++++- 1 file changed, 364 insertions(+), 12 deletions(-)
diff --git a/dlls/windows.devices.enumeration/tests/devices.c b/dlls/windows.devices.enumeration/tests/devices.c index b003193b42a..5917bae9408 100644 --- a/dlls/windows.devices.enumeration/tests/devices.c +++ b/dlls/windows.devices.enumeration/tests/devices.c @@ -32,6 +32,7 @@ #include "initguid.h" #include "roapi.h" #include "weakreference.h" +#include "ntddvdeo.h"
#define WIDL_using_Windows_Foundation #define WIDL_using_Windows_Foundation_Collections @@ -354,6 +355,231 @@ static void check_device_information_collection_async_( int line, IAsyncOperatio } }
+struct iterable_hstring +{ + IIterable_HSTRING IIterable_HSTRING_iface; + LONG ref; + + ULONG count; + HSTRING values[]; +}; + +C_ASSERT( sizeof( struct iterable_hstring ) == offsetof( struct iterable_hstring, values[0] ) ); + +static inline struct iterable_hstring *impl_from_IIterable_HSTRING( IIterable_HSTRING *iface ) +{ + return CONTAINING_RECORD( iface, struct iterable_hstring, IIterable_HSTRING_iface ); +} + +struct iterator_hstring +{ + IIterator_HSTRING IIterator_HSTRING_iface; + LONG ref; + + UINT32 index; + struct iterable_hstring *view; +}; + +static inline struct iterator_hstring *impl_from_IIterator_HSTRING( IIterator_HSTRING *iface ) +{ + return CONTAINING_RECORD( iface, struct iterator_hstring, IIterator_HSTRING_iface ); +} + +static HRESULT WINAPI iterator_hstring_QueryInterface( IIterator_HSTRING *iface, REFIID iid, void **out ) +{ + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IInspectable ) || + IsEqualGUID( iid, &IID_IAgileObject ) || + IsEqualGUID( iid, &IID_IIterator_HSTRING )) + { + IIterator_HSTRING_AddRef(( *out = iface )); + return S_OK; + } + + if (winetest_debug > 1) trace( "%s not implemented, returning E_NO_INTERFACE.\n", debugstr_guid( iid ) ); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI iterator_hstring_AddRef( IIterator_HSTRING *iface ) +{ + struct iterator_hstring *impl = impl_from_IIterator_HSTRING( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + return ref; +} + +static ULONG WINAPI iterator_hstring_Release(IIterator_HSTRING *iface) +{ + struct iterator_hstring *impl = impl_from_IIterator_HSTRING( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + + if (!ref) + { + IIterable_HSTRING_Release( &impl->view->IIterable_HSTRING_iface ); + free( impl ); + } + + return ref; +} + +static HRESULT WINAPI iterator_hstring_GetIids( IIterator_HSTRING *iface, ULONG *iid_count, IID **iids ) { return E_NOTIMPL; } + +static HRESULT WINAPI iterator_hstring_GetRuntimeClassName( IIterator_HSTRING *iface, HSTRING *class_name ) { return E_NOTIMPL; } + +static HRESULT WINAPI iterator_hstring_GetTrustLevel( IIterator_HSTRING *iface, TrustLevel *trust_level ) { return E_NOTIMPL; } + +static HRESULT WINAPI iterator_hstring_get_Current( IIterator_HSTRING *iface, HSTRING *value ) +{ + struct iterator_hstring *impl = impl_from_IIterator_HSTRING( iface ); + + *value = NULL; + if (impl->index >= impl->view->count) return E_BOUNDS; + return WindowsDuplicateString( impl->view->values[impl->index], value ); +} + +static HRESULT WINAPI iterator_hstring_get_HasCurrent( IIterator_HSTRING *iface, boolean *value ) +{ + struct iterator_hstring *impl = impl_from_IIterator_HSTRING( iface ); + + *value = impl->index < impl->view->count; + return S_OK; +} + +static HRESULT WINAPI iterator_hstring_MoveNext( IIterator_HSTRING *iface, boolean *value ) +{ + struct iterator_hstring *impl = impl_from_IIterator_HSTRING( iface ); + + if (impl->index < impl->view->count) impl->index++; + return IIterator_HSTRING_get_HasCurrent( iface, value ); +} + +static HRESULT WINAPI iterator_hstring_GetMany( IIterator_HSTRING *iface, UINT32 items_size, HSTRING *items, UINT *count ) +{ + struct iterator_hstring *impl = impl_from_IIterator_HSTRING( iface ); + ULONG i, start = impl->index; + HRESULT hr = S_OK; + + for (i = start; i < impl->view->count && i < start + items_size; i++) + if (FAILED(hr = WindowsDuplicateString( impl->view->values[i], items + i - start ))) break; + + if (FAILED( hr )) while (i-- > start) WindowsDeleteString( items[i - start] ); + *count = i - start; + return hr; +} + +static const IIterator_HSTRINGVtbl iterator_hstring_vtbl = +{ + /* IUnknown methods */ + iterator_hstring_QueryInterface, + iterator_hstring_AddRef, + iterator_hstring_Release, + /* IInspectable methods */ + iterator_hstring_GetIids, + iterator_hstring_GetRuntimeClassName, + iterator_hstring_GetTrustLevel, + /* IIterator<HSTRING> methods */ + iterator_hstring_get_Current, + iterator_hstring_get_HasCurrent, + iterator_hstring_MoveNext, + iterator_hstring_GetMany, +}; + +static HRESULT STDMETHODCALLTYPE iterable_hstring_QueryInterface( IIterable_HSTRING *iface, REFIID iid, void **out ) +{ + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IInspectable ) || + IsEqualGUID( iid, &IID_IAgileObject ) || + IsEqualGUID( iid, &IID_IIterable_HSTRING )) + { + IIterable_HSTRING_AddRef(( *out = iface )); + return S_OK; + } + + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG STDMETHODCALLTYPE iterable_hstring_AddRef( IIterable_HSTRING *iface ) +{ + struct iterable_hstring *impl = impl_from_IIterable_HSTRING( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + return ref; +} + +static ULONG STDMETHODCALLTYPE iterable_hstring_Release( IIterable_HSTRING *iface ) +{ + struct iterable_hstring *impl = impl_from_IIterable_HSTRING( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + + if (!ref) + { + while (impl->count--) WindowsDeleteString( impl->values[impl->count] ); + free( impl ); + } + return ref; +} + +static HRESULT WINAPI iterable_hstring_GetIids( IIterable_HSTRING *iface, ULONG *iid_count, IID **iids ) { return E_NOTIMPL; } + +static HRESULT WINAPI iterable_hstring_GetRuntimeClassName( IIterable_HSTRING *iface, HSTRING *class_name ) { return E_NOTIMPL; } + +static HRESULT WINAPI iterable_hstring_GetTrustLevel( IIterable_HSTRING *iface, TrustLevel *trust_level ) { return E_NOTIMPL; } + +static HRESULT WINAPI iterable_hstring_First( IIterable_HSTRING *iface, IIterator_HSTRING **value ) +{ + struct iterable_hstring *impl = impl_from_IIterable_HSTRING( iface ); + struct iterator_hstring *iter; + + if (!(iter = calloc( 1, sizeof( *iter ) ))) return E_OUTOFMEMORY; + iter->IIterator_HSTRING_iface.lpVtbl = &iterator_hstring_vtbl; + iter->ref = 1; + + IIterable_HSTRING_AddRef( iface ); + iter->view = impl; + + *value = &iter->IIterator_HSTRING_iface; + return S_OK; +} + +static const struct IIterable_HSTRINGVtbl iterable_hstring_vtbl = +{ + /* IUnknown methods */ + iterable_hstring_QueryInterface, + iterable_hstring_AddRef, + iterable_hstring_Release, + /* IInspectable methods */ + iterable_hstring_GetIids, + iterable_hstring_GetRuntimeClassName, + iterable_hstring_GetTrustLevel, + /* IIterable<HSTRING> methods */ + iterable_hstring_First, +}; + +static IIterable_HSTRING *iterable_hstring_create( const WCHAR **values, SIZE_T count ) +{ + struct iterable_hstring *impl; + HRESULT hr; + SIZE_T i; + + if (!(impl = malloc( offsetof( struct iterable_hstring, values[count] ) ))) return NULL; + impl->ref = 1; + + impl->IIterable_HSTRING_iface.lpVtbl = &iterable_hstring_vtbl; + impl->count = count; + for (i = 0; i < count; i++) + { + if (FAILED(hr = WindowsCreateString( values[i], wcslen(values[i]), &impl->values[i] ))) + { + while(i) WindowsDeleteString( impl->values[--i] ); + free( impl ); + return NULL; + } + } + + return &impl->IIterable_HSTRING_iface; +} + + /* Find the DEVPROPKEY associated with prop_name, ensure propval matches the value retrieved from DevGetObjectProperties. * If propval is NULL, then check the retrieved DEVPROPERTY has Type DEVPROP_TYPE_EMPTY. * This assumes that the DeviceInformationKind is DeviceInterface (DevObjectTypeDeviceInterfaceDisplay). */ @@ -557,11 +783,40 @@ static void test_DeviceInformation_properties( IDeviceInformation *info, const s
}
+static void test_DeviceInformationCollection( int line, IVectorView_DeviceInformation *info_collection, const struct device_property *exp_props, + SIZE_T exp_props_len ) +{ + UINT32 size, i; + HRESULT hr; + + hr = IVectorView_DeviceInformation_get_Size( info_collection, &size ); + ok_(__FILE__, line)( hr == S_OK, "got %#lx\n", hr ); + for (i = 0; i < size; i++) + { + IDeviceInformation *info; + + winetest_push_context( "info_collection %u", i ); + hr = IVectorView_DeviceInformation_GetAt( info_collection, i, &info ); + ok_(__FILE__, line)( hr == S_OK, "got %#lx\n", hr ); + test_DeviceInformation_obj( line, info ); + winetest_push_context("%d", line ); + test_DeviceInformation_properties( info, exp_props, exp_props_len ); + IDeviceInformation_Release( info ); + winetest_pop_context(); + winetest_pop_context(); + } +} + static void test_DeviceInformation( void ) { + static const WCHAR *device_iface_additional_props[] = { L"System.Devices.InterfaceClassGuid", L"{026e516e-b814-414b-83cd-856d6fef4822} 3" }; + static const WCHAR *device_invalid_props[] = { L"{026e516e-b814-414b-83cd-856d6fef4822}", L"{0-b814-414b-83cd-856d6fef4822} 3", L"{}" }; + static const WCHAR *device_nonexistent_props[] = { L"foo", L"", L" " }; static const struct device_property device_iface_exp_props[] = { { L"System.Devices.InterfaceEnabled", PropertyType_Boolean }, { L"System.Devices.DeviceInstanceId", PropertyType_String }, + /* Additional properties */ + { L"System.Devices.InterfaceClassGuid", PropertyType_Guid } }; static const WCHAR *device_info_name = L"Windows.Devices.Enumeration.DeviceInformation";
@@ -574,18 +829,18 @@ static void test_DeviceInformation( void ) IActivationFactory *factory; IDeviceInformationStatics2 *device_info_statics2; IDeviceInformationStatics *device_info_statics; + IIterable_HSTRING *additional_props; IDeviceWatcher *device_watcher; DeviceWatcherStatus status = 0xdeadbeef; IAsyncOperation_DeviceInformationCollection *info_collection_async = NULL; IVectorView_DeviceInformation *info_collection = NULL; - IDeviceInformation *info; IWeakReferenceSource *weak_src; IWeakReference *weak_ref; IDeviceWatcher *watcher; - UINT32 i, size; HSTRING str; HRESULT hr; ULONG ref; + int i;
enumerated_data.event = CreateEventW( NULL, FALSE, FALSE, NULL ); ok( !!enumerated_data.event, "failed to create event, got error %lu\n", GetLastError() ); @@ -746,20 +1001,53 @@ static void test_DeviceInformation( void ) await_device_information_collection( info_collection_async ); check_device_information_collection_async( info_collection_async, 1, 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 );
- hr = IVectorView_DeviceInformation_get_Size( info_collection, &size ); - ok( hr == S_OK, "got %#lx\n", hr ); - for (i = 0; i < size; i++) + hr = IDeviceInformationStatics_FindAllAsyncAqsFilterAndAdditionalProperties( device_info_statics, NULL, NULL, &info_collection_async ); + todo_wine ok( hr == S_OK, "got hr %#lx\n", hr ); + + if (SUCCEEDED( hr )) { - winetest_push_context( "info_collection %u", i ); - hr = IVectorView_DeviceInformation_GetAt( info_collection, i, &info ); - ok( hr == S_OK, "got %#lx\n", hr ); - test_DeviceInformation_obj( __LINE__, info ); - test_DeviceInformation_properties( info, device_iface_exp_props, ARRAY_SIZE( device_iface_exp_props ) ); - IDeviceInformation_Release( info ); + 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 ); + 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 ); + } + + 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 ); + IIterable_HSTRING_Release( additional_props ); + winetest_pop_context(); + } + + for (i = 0; i < ARRAY_SIZE( device_invalid_props ); i++ ) + { + 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 ); + IIterable_HSTRING_Release( additional_props ); winetest_pop_context(); } - IVectorView_DeviceInformation_Release( info_collection );
IDeviceInformationStatics_Release( device_info_statics );
@@ -996,10 +1284,45 @@ static const struct test_case_filter filters_invalid_operand[] = { { L" System.StructuredQueryType.Boolean#True := System.StructuredQueryType.Boolean#True", E_INVALIDARG }, };
+static void test_DeviceInformation_prop_guid( IDeviceInformation *info, const WCHAR *prop, const GUID *guid_val ) +{ + IMapView_HSTRING_IInspectable *props; + IInspectable *inspectable; + IReference_GUID *val; + GUID guid = {0}; + HSTRING str; + HRESULT hr; + + hr = IDeviceInformation_get_Properties( info, &props ); + ok( hr == S_OK, "got hr %#lx\n", hr ); + + hr = WindowsCreateString( prop, wcslen( prop ), &str ); + ok( hr == S_OK, "got hr %#lx\n", hr ); + hr = IMapView_HSTRING_IInspectable_Lookup( props, str, &inspectable ); + ok( hr == S_OK, "got hr %#lx\n", hr ); + WindowsDeleteString( str ); + IMapView_HSTRING_IInspectable_Release( props ); + + hr = IInspectable_QueryInterface( inspectable, &IID_IReference_GUID, (void **)&val ); + ok( hr == S_OK, "got hr %#lx\n", hr ); + IInspectable_Release( inspectable ); + hr = IReference_GUID_get_Value( val, &guid ); + ok( hr == S_OK, "got hr %#lx\n", hr ); + IReference_GUID_Release( val ); + + ok( IsEqualGUID( &guid, guid_val ), "got guid %s != %s\n", debugstr_guid( &guid ), debugstr_guid( guid_val ) ); +} + static void test_aqs_filters( void ) { + static const WCHAR *filter_iface_display = L"System.Devices.InterfaceClassGuid := {e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}"; static const WCHAR *class_name = RuntimeClass_Windows_Devices_Enumeration_DeviceInformation; + static const WCHAR *prop_name_iface_guid = L"System.Devices.InterfaceClassGuid"; + IAsyncOperation_DeviceInformationCollection *info_collection_async; + IVectorView_DeviceInformation *info_collection; IDeviceInformationStatics *statics; + IIterable_HSTRING *props_iterable; + UINT32 i, size; HSTRING str; HRESULT hr;
@@ -1044,6 +1367,35 @@ static void test_aqs_filters( void ) test_FindAllAsyncAqsFilter( statics, filters_invalid_operand, FALSE, FALSE ); test_CreateWatcherAqsFilter( statics, filters_invalid_operand, FALSE, FALSE, FALSE, FALSE );
+ props_iterable = iterable_hstring_create( &prop_name_iface_guid, 1 ); + 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 ); + WindowsDeleteString( str ); + IIterable_HSTRING_Release( props_iterable ); + 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 ); + + hr = IVectorView_DeviceInformation_get_Size( info_collection, &size ); + ok( hr == S_OK, "got hr %#lx\n", hr ); + for (i = 0; i < size; i++) + { + IDeviceInformation *info; + + winetest_push_context( "i=%u", i ); + hr = IVectorView_DeviceInformation_GetAt( info_collection, i, &info ); + ok( hr == S_OK, "got hr %#lx\n", hr ); + test_DeviceInformation_prop_guid( info, prop_name_iface_guid, &GUID_DEVINTERFACE_MONITOR ); + IDeviceInformation_Release( info ); + winetest_pop_context(); + } + IVectorView_DeviceInformation_Release( info_collection ); + } + IDeviceInformationStatics_Release( statics ); }
From: Vibhav Pant vibhavp@gmail.com
--- .../windows.devices.enumeration/information.c | 185 ++++++++++++++++-- dlls/windows.devices.enumeration/main.c | 22 ++- dlls/windows.devices.enumeration/private.h | 5 +- .../tests/devices.c | 4 +- 4 files changed, 192 insertions(+), 24 deletions(-)
diff --git a/dlls/windows.devices.enumeration/information.c b/dlls/windows.devices.enumeration/information.c index c09a9ea37ef..8dda2b63a98 100644 --- a/dlls/windows.devices.enumeration/information.c +++ b/dlls/windows.devices.enumeration/information.c @@ -19,6 +19,7 @@
#include "private.h"
+#include "roapi.h" #include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(enumeration); @@ -28,10 +29,11 @@ struct device_information IDeviceInformation IDeviceInformation_iface; LONG ref;
- HSTRING path; + IMap_HSTRING_IInspectable *properties; + HSTRING id; };
-static inline struct device_information *impl_DeviceInterface_from_IDeviceInformation( IDeviceInformation *iface ) +static inline struct device_information *impl_from_IDeviceInformation( IDeviceInformation *iface ) { return CONTAINING_RECORD( iface, struct device_information, IDeviceInformation_iface ); } @@ -57,7 +59,7 @@ static HRESULT WINAPI device_information_QueryInterface( IDeviceInformation *ifa
static ULONG WINAPI device_information_AddRef( IDeviceInformation *iface ) { - struct device_information *impl = impl_DeviceInterface_from_IDeviceInformation( iface ); + struct device_information *impl = impl_from_IDeviceInformation( iface ); ULONG ref = InterlockedIncrement( &impl->ref ); TRACE( "iface %p, ref %lu.\n", iface, ref ); return ref; @@ -65,14 +67,15 @@ static ULONG WINAPI device_information_AddRef( IDeviceInformation *iface )
static ULONG WINAPI device_information_Release( IDeviceInformation *iface ) { - struct device_information *impl = impl_DeviceInterface_from_IDeviceInformation( iface ); + struct device_information *impl = impl_from_IDeviceInformation( iface ); ULONG ref = InterlockedDecrement( &impl->ref );
TRACE( "iface %p, ref %lu.\n", iface, ref );
if (!ref) { - WindowsDeleteString( impl->path ); + if (impl->properties) IMap_HSTRING_IInspectable_Release( impl->properties ); + WindowsDeleteString( impl->id ); free( impl ); }
@@ -100,9 +103,9 @@ static HRESULT WINAPI device_information_GetTrustLevel( IDeviceInformation *ifac
static HRESULT WINAPI device_information_get_Id( IDeviceInformation *iface, HSTRING *id ) { - struct device_information *impl = impl_DeviceInterface_from_IDeviceInformation( iface ); + struct device_information *impl = impl_from_IDeviceInformation( iface ); TRACE( "iface %p, id %p\n", iface, id ); - return WindowsDuplicateString( impl->path, id ); + return WindowsDuplicateString( impl->id, id ); }
static HRESULT WINAPI device_information_get_Name( IDeviceInformation *iface, HSTRING *name ) @@ -131,8 +134,9 @@ static HRESULT WINAPI device_information_get_EnclosureLocation( IDeviceInformati
static HRESULT WINAPI device_information_get_Properties( IDeviceInformation *iface, IMapView_HSTRING_IInspectable **properties ) { - FIXME( "iface %p, properties %p stub!\n", iface, properties ); - return E_NOTIMPL; + struct device_information *impl = impl_from_IDeviceInformation( iface ); + TRACE( "iface %p, properties %p.\n", iface, properties ); + return IMap_HSTRING_IInspectable_GetView( impl->properties, properties ); }
static HRESULT WINAPI device_information_Update( IDeviceInformation *iface, IDeviceInformationUpdate *update ) @@ -176,19 +180,176 @@ static const struct IDeviceInformationVtbl device_information_vtbl = device_information_GetGlyphThumbnailAsync, };
-HRESULT device_information_create( const WCHAR *path, IDeviceInformation **info ) +static const char *debugstr_DEVPROPKEY( const DEVPROPKEY *key ) +{ + if (!key) return "(null)"; + return wine_dbg_sprintf( "{%s, %04lx}", debugstr_guid( &key->fmtid ), key->pid ); +} + +static HRESULT create_device_properties( const DEVPROPERTY *props, ULONG len, IMap_HSTRING_IInspectable **map ) +{ + static const WCHAR *propertyset_name = RuntimeClass_Windows_Foundation_Collections_PropertySet; + static const WCHAR *propertyvalue_name = RuntimeClass_Windows_Foundation_PropertyValue; + + IPropertyValueStatics *propval_statics = NULL; + IPropertySet *propset; + HSTRING_HEADER hdr; + HSTRING str; + HRESULT hr; + ULONG i; + + TRACE( "props %p, len %lu, map %p.\n", props, len, map ); + + if (FAILED(hr = WindowsCreateStringReference( propertyset_name, wcslen( propertyset_name ), &hdr, &str ))) return hr; + if (FAILED(hr = RoActivateInstance( str, (IInspectable **)&propset ))) return hr; + hr = IPropertySet_QueryInterface( propset, &IID_IMap_HSTRING_IInspectable, (void **)map ); + IPropertySet_Release( propset ); + if (FAILED(hr)) goto done; + + if (FAILED(hr = WindowsCreateStringReference( propertyvalue_name, wcslen( propertyvalue_name ), &hdr, &str ))) goto done; + hr = RoGetActivationFactory( str, &IID_IPropertyValueStatics, (void **)&propval_statics ); + + for (i = 0; SUCCEEDED(hr) && i < len; i++) + { + const DEVPROPERTY *prop = &props[i]; + const DEVPROPKEY *propkey = &prop->CompKey.Key; + HSTRING canonical_name; + IInspectable *val; + boolean replaced; + WCHAR *name; + + switch (prop->Type) + { + case DEVPROP_TYPE_BOOLEAN: + hr = IPropertyValueStatics_CreateBoolean( propval_statics, !!*(DEVPROP_BOOLEAN *)prop->Buffer, &val ); + break; + case DEVPROP_TYPE_BYTE: + case DEVPROP_TYPE_SBYTE: + hr = IPropertyValueStatics_CreateUInt8( propval_statics, *(BYTE *)prop->Buffer, &val ); + break; + case DEVPROP_TYPE_UINT16: + hr = IPropertyValueStatics_CreateUInt16( propval_statics, *(UINT16 *)prop->Buffer, &val ); + break; + case DEVPROP_TYPE_INT16: + hr = IPropertyValueStatics_CreateInt16( propval_statics, *(INT16 *)prop->Buffer, &val ); + break; + case DEVPROP_TYPE_UINT32: + hr = IPropertyValueStatics_CreateUInt32( propval_statics, *(UINT32 *)prop->Buffer, &val ); + break; + case DEVPROP_TYPE_INT32: + hr = IPropertyValueStatics_CreateInt32( propval_statics, *(INT32 *)prop->Buffer, &val ); + break; + case DEVPROP_TYPE_UINT64: + hr = IPropertyValueStatics_CreateUInt64( propval_statics, *(UINT64 *)prop->Buffer, &val ); + break; + case DEVPROP_TYPE_INT64: + hr = IPropertyValueStatics_CreateInt64( propval_statics, *(INT64 *)prop->Buffer, &val ); + break; + case DEVPROP_TYPE_FLOAT: + hr = IPropertyValueStatics_CreateSingle( propval_statics, *(FLOAT *)prop->Buffer, &val ); + break; + case DEVPROP_TYPE_DOUBLE: + hr = IPropertyValueStatics_CreateDouble( propval_statics, *(DOUBLE *)prop->Buffer, &val ); + break; + case DEVPROP_TYPE_GUID: + hr = IPropertyValueStatics_CreateGuid( propval_statics, *(GUID *)prop->Buffer, &val ); + break; + case DEVPROP_TYPE_FILETIME: + hr = IPropertyValueStatics_CreateDateTime( propval_statics, *(DateTime *)prop->Buffer, &val ); + break; + case DEVPROP_TYPE_STRING: + { + if (SUCCEEDED(hr = WindowsCreateString( prop->Buffer, wcslen( prop->Buffer ), &str ))) + { + hr = IPropertyValueStatics_CreateString( propval_statics, str, &val ); + WindowsDeleteString( str ); + } + break; + } + default: + FIXME("Unsupported DEVPROPTYPE: %#lx\n", prop->Type ); + continue; + } + if (FAILED(hr)) break; + if (SUCCEEDED(hr = PSGetNameFromPropertyKey( (PROPERTYKEY *)propkey, &name ))) + { + hr = WindowsCreateString( name, wcslen( name ), &canonical_name ); + CoTaskMemFree( name ); + } + else if (hr == TYPE_E_ELEMENTNOTFOUND) + { + const GUID *fmtid = &propkey->fmtid; + WCHAR buf[80]; + + WARN( "Unknown property key: %s\n", debugstr_DEVPROPKEY( propkey ) ); + swprintf( buf, ARRAY_SIZE( buf ), L"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x} %lu", fmtid->Data1, fmtid->Data2, fmtid->Data3, + fmtid->Data4[0], fmtid->Data4[1], fmtid->Data4[2], fmtid->Data4[3], fmtid->Data4[4], fmtid->Data4[5], fmtid->Data4[6], fmtid->Data4[7], propkey->pid ); + hr = WindowsCreateString( buf, wcslen( buf ), &canonical_name ); + } + + if (SUCCEEDED(hr)) + { + hr = IMap_HSTRING_IInspectable_Insert( *map, canonical_name, val, &replaced ); + IInspectable_Release( val ); + WindowsDeleteString( canonical_name ); + break; + } + IInspectable_Release( val ); + } + +done: + if (propval_statics) IPropertyValueStatics_Release( propval_statics ); + if (FAILED(hr) && *map) IMap_HSTRING_IInspectable_Release( *map ); + return hr; +} + +static const char *debugstr_DEV_OBJECT_TYPE( DEV_OBJECT_TYPE type ) +{ + static const char *str[] = { + "DevObjectTypeUnknown", + "DevObjectTypeDeviceInterface", + "DevObjectTypeDeviceContainer", + "DevObjectTypeDevice", + "DevObjectTypeDeviceInterfaceClass", + "DevObjectTypeAEP", + "DevObjectTypeAEPContainer", + "DevObjectTypeDeviceInstallerClass", + "DevObjectTypeDeviceInterfaceDisplay", + "DevObjectTypeDeviceContainerDisplay", + "DevObjectTypeAEPService", + "DevObjectTypeDevicePanel", + "DevObjectTypeAEPProtocol", + }; + if (type >= ARRAY_SIZE( str )) return wine_dbg_sprintf( "(unknown %d)", type ); + return wine_dbg_sprintf( "%s", str[type] ); +} + +static const char *debugstr_DEV_OBJECT( const DEV_OBJECT *obj ) +{ + if (!obj) return "(null)"; + return wine_dbg_sprintf( "{%s, %s, %lu, %p}", debugstr_DEV_OBJECT_TYPE( obj->ObjectType ), debugstr_w( obj->pszObjectId ), obj->cPropertyCount, + obj->pProperties ); +} + +HRESULT device_information_create( const DEV_OBJECT *obj, IDeviceInformation **info ) { struct device_information *impl; HRESULT hr;
- TRACE( "path %s, info %p\n", debugstr_w(path), info ); + TRACE( "obj %s, info %p\n", debugstr_DEV_OBJECT( obj ), info );
if (!(impl = calloc( 1, sizeof(*impl) ))) return E_OUTOFMEMORY; impl->IDeviceInformation_iface.lpVtbl = &device_information_vtbl; impl->ref = 1; + if (FAILED(hr = create_device_properties( obj->pProperties, obj->cPropertyCount, &impl->properties ))) + { + free( impl ); + return hr; + }
- if (FAILED(hr = WindowsCreateString( path, wcslen( path ), &impl->path ))) + if (FAILED(hr = WindowsCreateString( obj->pszObjectId, wcslen( obj->pszObjectId ), &impl->id ))) { + IMap_HSTRING_IInspectable_Release( impl->properties ); free( impl ); return hr; } diff --git a/dlls/windows.devices.enumeration/main.c b/dlls/windows.devices.enumeration/main.c index 2125689eeef..c965ca363e0 100644 --- a/dlls/windows.devices.enumeration/main.c +++ b/dlls/windows.devices.enumeration/main.c @@ -24,10 +24,9 @@
#include "initguid.h" #include "private.h" -#include "devpropdef.h" -#include "devfiltertypes.h" #include "devquery.h" #include "aqs.h" +#include "devpkey.h"
#include "wine/debug.h"
@@ -347,7 +346,7 @@ static void WINAPI device_object_query_callback( HDEVQUERY query, void *data, case DevQueryResultAdd: { IDeviceInformation *info; - if (FAILED(hr = device_information_create( action_data->Data.DeviceObject.pszObjectId, &info ))) + if (FAILED(hr = device_information_create( &action_data->Data.DeviceObject, &info ))) break; typed_event_handlers_notify( &watcher->added_handlers, (IInspectable *)iface, (IInspectable *)info ); IDeviceInformation_Release( info ); @@ -361,6 +360,12 @@ static void WINAPI device_object_query_callback( HDEVQUERY query, void *data, IDeviceWatcher_Release( iface ); }
+static const DEVPROPCOMPKEY device_iface_default_props[] = +{ + { DEVPKEY_DeviceInterface_Enabled, DEVPROP_STORE_SYSTEM, NULL }, + { DEVPKEY_Device_InstanceId, DEVPROP_STORE_SYSTEM, NULL }, +}; + static HRESULT WINAPI device_watcher_Start( IDeviceWatcher *iface ) { struct device_watcher *impl = impl_from_IDeviceWatcher( iface ); @@ -394,8 +399,8 @@ static HRESULT WINAPI device_watcher_Start( IDeviceWatcher *iface ) }
IWeakReferenceSource_GetWeakReference( &impl->weak_reference_source.IWeakReferenceSource_iface, &weak ); - hr = DevCreateObjectQuery( DevObjectTypeDeviceInterfaceDisplay, DevQueryFlagAsyncClose, 0, NULL, filters_len, filters, device_object_query_callback, - weak, &impl->query ); + hr = DevCreateObjectQuery( DevObjectTypeDeviceInterfaceDisplay, DevQueryFlagAsyncClose, ARRAY_SIZE( device_iface_default_props ), + device_iface_default_props, filters_len, filters, device_object_query_callback, weak, &impl->query ); if (FAILED(hr)) { ERR( "Failed to create device query: %#lx\n", hr ); @@ -645,16 +650,17 @@ 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; - if (FAILED(hr = DevGetObjects( DevObjectTypeDeviceInterfaceDisplay, DevQueryFlagNone, 0, NULL, filters_len, filters, &len, &objects ))) + hr = DevGetObjects( DevObjectTypeDeviceInterfaceDisplay, DevQueryFlagNone, ARRAY_SIZE( device_iface_default_props ), device_iface_default_props, filters_len, filters, + &len, &objects ); + if (FAILED(hr)) { IVector_IInspectable_Release( vector ); - ERR("DevGetObjects failed, hr %#lx\n", hr); return hr; } for (i = 0; i < len && SUCCEEDED(hr); i++) { IDeviceInformation *info; - if (SUCCEEDED(hr = device_information_create( objects[i].pszObjectId, &info ))) + if (SUCCEEDED(hr = device_information_create( &objects[i], &info ))) { hr = IVector_IInspectable_Append( vector, (IInspectable *)info ); IDeviceInformation_Release( info ); diff --git a/dlls/windows.devices.enumeration/private.h b/dlls/windows.devices.enumeration/private.h index 0ce5624b21c..033e866b506 100644 --- a/dlls/windows.devices.enumeration/private.h +++ b/dlls/windows.devices.enumeration/private.h @@ -28,6 +28,9 @@ #include "winbase.h" #include "winstring.h" #include "objbase.h" +#include "devpropdef.h" +#include "devfiltertypes.h" +#include "devquerydef.h" #include "propsys.h"
#include "activation.h" @@ -63,7 +66,7 @@ extern HRESULT async_operation_inspectable_create( const GUID *iid, IUnknown *in 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 ); +extern HRESULT device_information_create( const DEV_OBJECT *obj, IDeviceInformation **info );
#define DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from, iface_mem, expr ) \ static inline impl_type *impl_from( iface_type *iface ) \ diff --git a/dlls/windows.devices.enumeration/tests/devices.c b/dlls/windows.devices.enumeration/tests/devices.c index 5917bae9408..a4294075e38 100644 --- a/dlls/windows.devices.enumeration/tests/devices.c +++ b/dlls/windows.devices.enumeration/tests/devices.c @@ -705,9 +705,7 @@ static void test_DeviceInformation_properties( IDeviceInformation *info, const s SIZE_T i;
hr = IDeviceInformation_get_Properties( info, &properties ); - todo_wine ok( hr == S_OK, "got hr %#lx\n", hr ); - if (FAILED(hr)) return; - + ok( hr == S_OK, "got hr %#lx\n", hr ); hr = IDeviceInformation_get_Id( info, &id ); ok( hr == S_OK, "got hr %#lx\n", hr ); for (i = 0; i < exp_props_len; i++)
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 ))
On Mon Sep 29 15:15:05 2025 +0000, Vibhav Pant wrote:
changed this line in [version 5 of the diff](/wine/wine/-/merge_requests/9045/diffs?diff_id=212779&start_sha=5b3899c96d19294dbb54d6de5d60d2585878c08a#ebd3b7400dcf4b0a56cc0a8cb7934f0c4ec6b741_225_221)
Sure.