From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/cfgmgr32/Makefile.in | 2 +- dlls/cfgmgr32/cfgmgr32.c | 22 ++++- dlls/cfgmgr32/cfgmgr32_private.h | 8 ++ dlls/cfgmgr32/devobject.c | 154 ++++++++++++++----------------- dlls/cfgmgr32/tests/cfgmgr32.c | 8 ++ 5 files changed, 104 insertions(+), 90 deletions(-) diff --git a/dlls/cfgmgr32/Makefile.in b/dlls/cfgmgr32/Makefile.in index 1c04637124f..b33d300ce6a 100644 --- a/dlls/cfgmgr32/Makefile.in +++ b/dlls/cfgmgr32/Makefile.in @@ -1,6 +1,6 @@ MODULE = cfgmgr32.dll IMPORTLIB = cfgmgr32 -IMPORTS = advapi32 rpcrt4 sechost setupapi +IMPORTS = advapi32 rpcrt4 sechost SOURCES = \ cfgmgr32.c \ diff --git a/dlls/cfgmgr32/cfgmgr32.c b/dlls/cfgmgr32/cfgmgr32.c index 481c595ac7a..ff179295f02 100644 --- a/dlls/cfgmgr32/cfgmgr32.c +++ b/dlls/cfgmgr32/cfgmgr32.c @@ -191,8 +191,6 @@ static LSTATUS return_property_bool( struct property *prop, DEVPROP_BOOLEAN valu return return_property( prop, DEVPROP_TYPE_BOOLEAN, &value, sizeof(value) ); } -typedef LSTATUS (*enum_objects_cb)( HKEY hkey, const void *object, const WCHAR *path, UINT path_len, void *context ); - static LSTATUS enum_objects_size( HKEY hkey, const void *object, const WCHAR *path, UINT path_len, void *context ) { UINT *total = context; @@ -397,6 +395,26 @@ static LSTATUS enum_class_device_interfaces( HKEY root, struct device_interface return err; } +LSTATUS enum_device_interfaces( BOOL all, enum_objects_cb callback, void *context ) +{ + struct device_interface iface; + LSTATUS err = ERROR_SUCCESS; + HKEY root, class_key; + + if ((root = cache_root_key( HKEY_LOCAL_MACHINE, device_classesW, NULL )) == (HKEY)-1) return ERROR_FILE_NOT_FOUND; + + for (UINT i = 0; !err && !(err = RegEnumKeyW( root, i, iface.class, ARRAY_SIZE(iface.class) )); i++) + { + if ((err = guid_from_string( iface.class, &iface.class_guid ))) continue; + if ((err = open_key( root, iface.class, KEY_ENUMERATE_SUB_KEYS, TRUE, &class_key ))) continue; + err = enum_class_device_interfaces( class_key, &iface, NULL, all, callback, context ); + RegCloseKey( class_key ); + } + if (err == ERROR_NO_MORE_ITEMS) err = ERROR_SUCCESS; + + return err; +} + static LSTATUS enum_device_interface_list( GUID *class, DEVINSTID_W instance_id, BOOL all, enum_objects_cb callback, void *context ) { struct device_interface iface; diff --git a/dlls/cfgmgr32/cfgmgr32_private.h b/dlls/cfgmgr32/cfgmgr32_private.h index 9d98da62585..81ebd413c12 100644 --- a/dlls/cfgmgr32/cfgmgr32_private.h +++ b/dlls/cfgmgr32/cfgmgr32_private.h @@ -70,6 +70,14 @@ struct device_interface WCHAR refstr[MAX_PATH]; }; +static inline const char *debugstr_device_interface( const struct device_interface *iface ) +{ + return wine_dbg_sprintf( "{%s %s %s}", debugstr_w(iface->class), debugstr_w(iface->name), debugstr_w(iface->refstr) ); +} + +typedef LSTATUS (*enum_objects_cb)( HKEY hkey, const void *object, const WCHAR *path, UINT path_len, void *context ); +extern LSTATUS enum_device_interfaces( BOOL all, enum_objects_cb callback, void *context ); + extern LSTATUS init_device_interface( struct device_interface *iface, const WCHAR *name ); extern LSTATUS open_device_interface_key( const struct device_interface *iface, REGSAM access, BOOL open, HKEY *hkey ); extern LSTATUS enum_device_interface_property_keys( HKEY hkey, const struct device_interface *iface, DEVPROPKEY *buffer, ULONG *size ); diff --git a/dlls/cfgmgr32/devobject.c b/dlls/cfgmgr32/devobject.c index fac4107b0ab..2ee2c1f8387 100644 --- a/dlls/cfgmgr32/devobject.c +++ b/dlls/cfgmgr32/devobject.c @@ -403,19 +403,81 @@ static void select_properties( const DEVPROPCOMPKEY *keys, ULONG keys_len, DEVPR } } +struct enum_dev_object_params +{ + DEV_OBJECT_TYPE type; + const DEVPROPCOMPKEY *props; + ULONG props_len; + BOOL all_props; + const DEVPROP_FILTER_EXPRESSION *filters; + const DEVPROP_FILTER_EXPRESSION *filters_end; + enum_device_object_cb callback; + void *context; +}; + +static LSTATUS enum_dev_objects_device_interface( HKEY hkey, const void *object, const WCHAR *name, UINT name_len, void *context ) +{ + struct enum_dev_object_params *params = context; + ULONG keys_len = params->props_len, properties_len = 0; + const struct device_interface *iface = object; + const DEVPROPCOMPKEY *keys = params->props; + DEVPROPERTY *properties = NULL; + LSTATUS err = ERROR_SUCCESS; + BOOL matches; + + TRACE( "hkey %p object %s name %s\n", hkey, debugstr_device_interface(iface), debugstr_w(name) ); + + /* If we're also filtering objects, get all properties for this object. Once the filters have been + * evaluated, free properties that have not been requested, and set cPropertyCount to comp_keys_len. */ + if (params->all_props || params->filters) err = copy_device_interface_property_keys( hkey, iface, &keys, &keys_len ); + if (!err) + { + if (keys_len && !(properties = calloc( keys_len, sizeof(*properties) ))) err = ERROR_OUTOFMEMORY; + else err = copy_device_interface_properties( hkey, iface, keys, keys_len, properties, &properties_len ); + } + + if (!err) + { + /* Sort properties by DEVPROPCOMPKEY for faster filter evaluation. */ + if (params->filters) qsort( properties, properties_len, sizeof(*properties), devproperty_compare ); + + /* By default, the evaluation is performed by AND-ing all individual filter expressions. */ + matches = devprop_filter_matches_properties( properties, properties_len, DEVPROP_OPERATOR_AND_OPEN, params->filters, params->filters_end ); + + /* Shrink properties to only the desired ones, unless DevQueryFlagAllProperties is set. */ + if (!params->all_props) select_properties( params->props, params->props_len, &properties, &properties_len ); + + if (matches) err = params->callback( params->type, name, &properties_len, &properties, params->context ); + } + + DevFreeObjectProperties( properties_len, properties ); + if (params->all_props || params->filters) free( (void *)keys ); + + return err; +} + static LSTATUS enum_dev_objects( DEV_OBJECT_TYPE type, const DEVPROPCOMPKEY *props, ULONG props_len, BOOL all_props, const DEVPROP_FILTER_EXPRESSION *filters, const DEVPROP_FILTER_EXPRESSION *filters_end, - enum_device_object_cb callback, void *data ) + enum_device_object_cb callback, void *context ) { - LSTATUS err = ERROR_SUCCESS; - HKEY iface_key; - DWORD i; + struct enum_dev_object_params params = + { + .type = type, + .props = props, + .props_len = props_len, + .all_props = all_props, + .filters = filters, + .filters_end = filters_end, + .callback = callback, + .context = context, + }; switch (type) { case DevObjectTypeDeviceInterface: case DevObjectTypeDeviceInterfaceDisplay: - break; + return enum_device_interfaces( TRUE, enum_dev_objects_device_interface, ¶ms ); + case DevObjectTypeDeviceContainer: case DevObjectTypeDevice: case DevObjectTypeDeviceInterfaceClass: @@ -430,88 +492,6 @@ static LSTATUS enum_dev_objects( DEV_OBJECT_TYPE type, const DEVPROPCOMPKEY *pro default: return ERROR_SUCCESS; } - - if (!(iface_key = SetupDiOpenClassRegKeyExW( NULL, KEY_ENUMERATE_SUB_KEYS, DIOCR_INTERFACE, NULL, NULL ))) - return HRESULT_FROM_WIN32( GetLastError() ); - - for (i = 0; !err; i++) - { - char buffer[sizeof( SP_DEVICE_INTERFACE_DETAIL_DATA_W ) + MAX_PATH * sizeof( WCHAR )]; - SP_DEVICE_INTERFACE_DATA iface_data = {.cbSize = sizeof( iface_data )}; - SP_DEVICE_INTERFACE_DETAIL_DATA_W *detail = (void *)buffer; - HDEVINFO set = INVALID_HANDLE_VALUE; - WCHAR iface_guid_str[40]; - DWORD len, j; - GUID iface_class; - - len = ARRAY_SIZE( iface_guid_str ); - err = RegEnumKeyExW( iface_key, i, iface_guid_str, &len, NULL, NULL, NULL, NULL ); - if (err) break; - - iface_guid_str[37] = '\0'; - if (!UuidFromStringW( &iface_guid_str[1], &iface_class )) - { - set = SetupDiGetClassDevsW( &iface_class, NULL, NULL, DIGCF_DEVICEINTERFACE ); - if (set == INVALID_HANDLE_VALUE) err = GetLastError(); - } - else - { - ERR( "Could not parse device interface GUID %s\n", debugstr_w( iface_guid_str ) ); - continue; - } - - for (j = 0; !err && SetupDiEnumDeviceInterfaces( set, NULL, &iface_class, j, &iface_data ); j++) - { - ULONG keys_len = props_len, properties_len = 0; - const DEVPROPCOMPKEY *keys = props; - DEVPROPERTY *properties = NULL; - struct device_interface iface; - HKEY hkey; - - detail->cbSize = sizeof( *detail ); - if (!SetupDiGetDeviceInterfaceDetailW( set, &iface_data, detail, sizeof( buffer ), NULL, NULL )) continue; - if ((err = init_device_interface( &iface, detail->DevicePath )) || - (err = open_device_interface_key( &iface, KEY_ALL_ACCESS, TRUE, &hkey ))) - break; - - /* If we're also filtering objects, get all properties for this object. Once the filters have been - * evaluated, free properties that have not been requested, and set cPropertyCount to props_len. */ - if (all_props || filters) err = copy_device_interface_property_keys( hkey, &iface, &keys, &keys_len ); - if (!err) - { - if (keys_len && !(properties = calloc( keys_len, sizeof(*properties) ))) err = ERROR_OUTOFMEMORY; - else err = copy_device_interface_properties( hkey, &iface, keys, keys_len, properties, &properties_len ); - } - - if (!err) - { - BOOL matches; - - /* Sort properties by DEVPROPCOMPKEY for faster filter evaluation. */ - if (filters) qsort( properties, properties_len, sizeof(*properties), devproperty_compare ); - - /* By default, the evaluation is performed by AND-ing all individual filter expressions. */ - matches = devprop_filter_matches_properties( properties, properties_len, DEVPROP_OPERATOR_AND_OPEN, filters, filters_end ); - - /* Shrink properties to only the desired ones, unless DevQueryFlagAllProperties is set. */ - if (!all_props) select_properties( props, props_len, &properties, &properties_len ); - - if (matches) err = callback( type, detail->DevicePath, &properties_len, &properties, data ); - } - - DevFreeObjectProperties( properties_len, properties ); - - if (keys != props) free( (void *)keys ); - RegCloseKey( hkey ); - } - - if (set != INVALID_HANDLE_VALUE) - SetupDiDestroyDeviceInfoList( set ); - } - if (err == ERROR_NO_MORE_ITEMS) err = ERROR_SUCCESS; - - RegCloseKey( iface_key ); - return err; } struct objects_list diff --git a/dlls/cfgmgr32/tests/cfgmgr32.c b/dlls/cfgmgr32/tests/cfgmgr32.c index 676537c97bd..ae113c13bb1 100644 --- a/dlls/cfgmgr32/tests/cfgmgr32.c +++ b/dlls/cfgmgr32/tests/cfgmgr32.c @@ -1789,6 +1789,14 @@ static void test_DevGetObjects( void ) filters = calloc( obj->cPropertyCount, sizeof( *filters ) ); /* If there are no logical operators present, then logical AND is used. */ filter_add_props( filters, obj->cPropertyCount, obj->pProperties, TRUE ); + + /* setupapi touches the DeviceInstance property, changing it to upper case when it shouldn't */ + if (i == 0 && !wcsnicmp( obj->pszObjectId, L"\\\\?\\DISPLAY", 11 )) + { + for (UINT k = 0; k < obj->cPropertyCount; k++) + filters[k].Operator |= DEVPROP_OPERATOR_MODIFIER_IGNORE_CASE; + } + hr = pDevGetObjects( test_cases[i].object_type, DevQueryFlagAllProperties, 0, NULL, obj->cPropertyCount, filters, &len2, &objects2 ); ok( hr == S_OK, "got hr %#lx\n", hr ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10204