From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/cfgmgr32/cfgmgr32.c | 192 +++++++++++++++++++++++++++++++++ dlls/cfgmgr32/cfgmgr32.spec | 16 +-- dlls/cfgmgr32/tests/cfgmgr32.c | 184 ++++++++++++++++++++++++++++++- 3 files changed, 382 insertions(+), 10 deletions(-) diff --git a/dlls/cfgmgr32/cfgmgr32.c b/dlls/cfgmgr32/cfgmgr32.c index 8902d157ee7..811f4304017 100644 --- a/dlls/cfgmgr32/cfgmgr32.c +++ b/dlls/cfgmgr32/cfgmgr32.c @@ -101,6 +101,11 @@ static LSTATUS open_key( HKEY root, const WCHAR *key, REGSAM access, BOOL open, return RegCreateKeyExW( root, key, 0, NULL, 0, access, NULL, hkey, NULL ); } +static LSTATUS query_value( HKEY hkey, const WCHAR *value, WCHAR *buffer, DWORD len ) +{ + return RegQueryValueExW( hkey, value, NULL, NULL, (BYTE *)buffer, &len ); +} + static LSTATUS open_class_key( HKEY root, const WCHAR *key, REGSAM access, BOOL open, HKEY *hkey ) { WCHAR path[MAX_PATH]; @@ -182,6 +187,33 @@ static LSTATUS query_named_property( HKEY hkey, const WCHAR *nameW, DEVPROPTYPE return err; } +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; + *total += WideCharToMultiByte( CP_ACP, 0, path, path_len, NULL, 0, 0, 0 ); + return ERROR_SUCCESS; +} + +struct enum_objects_append_params +{ + WCHAR *buffer; + UINT len; +}; + +static LSTATUS enum_objects_append( HKEY hkey, const void *object, const WCHAR *path, UINT path_len, void *context ) +{ + struct enum_objects_append_params *params = context; + + if (path_len > params->len) return ERROR_MORE_DATA; + memcpy( params->buffer, path, path_len * sizeof(WCHAR) ); + params->buffer += path_len; + params->len -= path_len; + + return ERROR_SUCCESS; +} + struct property_desc { const DEVPROPKEY *key; @@ -328,6 +360,64 @@ static LSTATUS open_device_interface_key( const struct device_interface *iface, return open_device_classes_key( HKEY_LOCAL_MACHINE, path, access, open, hkey ); } +static DEVPROP_BOOLEAN device_interface_enabled( HKEY hkey, const struct device_interface *iface ) +{ + DWORD linked, linked_size = sizeof(linked); + WCHAR control[MAX_PATH]; + + swprintf( control, ARRAY_SIZE(control), L"%s\\Control", iface->refstr ); + if (RegGetValueW( hkey, control, L"Linked", RRF_RT_DWORD, NULL, &linked, &linked_size )) return DEVPROP_FALSE; + return linked ? DEVPROP_TRUE : DEVPROP_FALSE; +} + +static LSTATUS enum_class_device_interfaces( HKEY root, struct device_interface *iface, DEVINSTID_W instance_id, BOOL all, + enum_objects_cb callback, void *context ) +{ + LSTATUS err = ERROR_SUCCESS; + HKEY iface_key; + + for (UINT i = 0; !err && !(err = RegEnumKeyW( root, i, iface->name, ARRAY_SIZE(iface->name) )); i++) + { + WCHAR *tmp, instance[MAX_PATH], path[MAX_PATH]; + + if ((err = open_key( root, iface->name, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, TRUE, &iface_key ))) continue; + + if (!(err = query_value( iface_key, L"DeviceInstance", instance, ARRAY_SIZE(instance) )) && + (!instance_id || !wcsicmp( instance_id, instance ))) + { + for (tmp = wcschr( instance, '\\' ); tmp; tmp = wcschr( tmp, '\\' )) *tmp = '#'; + for (UINT j = 0; !err && !(err = RegEnumKeyW( iface_key, j, iface->refstr, ARRAY_SIZE(iface->refstr) )); j++) + { + ULONG len = swprintf( path, ARRAY_SIZE(path), L"\\\\?\\%s%s%s", instance, iface->refstr, iface->class ); + if (all || device_interface_enabled( iface_key, iface )) err = callback( iface_key, iface, path, len + 1, context ); + } + if (err == ERROR_NO_MORE_ITEMS) err = ERROR_SUCCESS; + } + + RegCloseKey( iface_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; + HKEY class_key; + LSTATUS err; + + if (instance_id && !*instance_id) instance_id = NULL; + + guid_string( class, iface.class, ARRAY_SIZE(iface.class) ); + if ((err = open_device_classes_key( HKEY_LOCAL_MACHINE, iface.class, KEY_ENUMERATE_SUB_KEYS, TRUE, &class_key ))) return err; + err = enum_class_device_interfaces( class_key, &iface, instance_id, all, callback, context ); + RegCloseKey( class_key ); + + if (!err) callback( NULL, NULL, L"", 1, context ); + return err; +} + static CONFIGRET map_error( LSTATUS err ) { switch (err) @@ -660,6 +750,108 @@ CONFIGRET WINAPI CM_Get_Class_Property_Keys( const GUID *class, DEVPROPKEY *keys return CM_Get_Class_Property_Keys_Ex( class, keys, count, flags, NULL ); } +/*********************************************************************** + * CM_Get_Device_Interface_List_Size_ExW (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Get_Device_Interface_List_Size_ExW( ULONG *len, GUID *class, DEVINSTID_W instance_id, ULONG flags, HMACHINE machine ) +{ + BOOL all = flags == CM_GET_DEVICE_INTERFACE_LIST_ALL_DEVICES; + + TRACE( "len %p, class %s, instance %s, flags %#lx, machine %p\n", len, debugstr_guid(class), debugstr_w(instance_id), flags, machine ); + if (machine) FIXME( "machine %p not implemented!\n", machine ); + + if (!class) return CR_FAILURE; + if (!len) return CR_INVALID_POINTER; + if (flags & ~CM_GET_DEVICE_INTERFACE_LIST_BITS) return CR_INVALID_FLAG; + + *len = 0; + return map_error( enum_device_interface_list( class, instance_id, all, enum_objects_size, len ) ); +} + +/*********************************************************************** + * CM_Get_Device_Interface_List_Size_ExA (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Get_Device_Interface_List_Size_ExA( ULONG *len, GUID *class, DEVINSTID_A instance_idA, ULONG flags, HMACHINE machine ) +{ + WCHAR instance_idW[MAX_PATH]; + + if (instance_idA) MultiByteToWideChar( CP_ACP, 0, instance_idA, -1, instance_idW, ARRAY_SIZE(instance_idW) ); + return CM_Get_Device_Interface_List_Size_ExW( len, class, instance_idA ? instance_idW : NULL, flags, machine ); +} + +/*********************************************************************** + * CM_Get_Device_Interface_List_SizeW (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Get_Device_Interface_List_SizeW( ULONG *len, GUID *class, DEVINSTID_W instance_id, ULONG flags ) +{ + return CM_Get_Device_Interface_List_Size_ExW( len, class, instance_id, flags, NULL ); +} + +/*********************************************************************** + * CM_Get_Device_Interface_List_SizeA (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Get_Device_Interface_List_SizeA( ULONG *len, GUID *class, DEVINSTID_A instance_id, ULONG flags ) +{ + return CM_Get_Device_Interface_List_Size_ExA( len, class, instance_id, flags, NULL ); +} + +/*********************************************************************** + * CM_Get_Device_Interface_List_ExW (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Get_Device_Interface_List_ExW( GUID *class, DEVINSTID_W instance_id, WCHAR *buffer, ULONG len, ULONG flags, HMACHINE machine ) +{ + struct enum_objects_append_params params = {.buffer = buffer, .len = len}; + BOOL all = flags == CM_GET_DEVICE_INTERFACE_LIST_ALL_DEVICES; + + TRACE( "class %s, instance %s, buffer %p, len %lu, flags %#lx, machine %p\n", debugstr_guid(class), debugstr_w(instance_id), buffer, len, flags, machine ); + if (machine) FIXME( "machine %p not implemented!\n", machine ); + + if (!class) return CR_FAILURE; + if (!buffer) return CR_INVALID_POINTER; + if (!len) return CR_BUFFER_SMALL; + if (flags & ~CM_GET_DEVICE_INTERFACE_LIST_BITS) return CR_INVALID_FLAG; + + memset( buffer, 0, len * sizeof(WCHAR) ); + return map_error( enum_device_interface_list( class, instance_id, all, enum_objects_append, ¶ms ) ); +} + +/*********************************************************************** + * CM_Get_Device_Interface_List_ExA (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Get_Device_Interface_List_ExA( GUID *class, DEVINSTID_A instance_idA, char *bufferA, ULONG len, ULONG flags, HMACHINE machine ) +{ + WCHAR instance_idW[MAX_PATH], *bufferW; + CONFIGRET ret; + + bufferW = bufferA ? malloc( len * sizeof(WCHAR) ) : NULL; + if (instance_idA) MultiByteToWideChar( CP_ACP, 0, instance_idA, -1, instance_idW, ARRAY_SIZE(instance_idW) ); + ret = CM_Get_Device_Interface_List_ExW( class, instance_idA ? instance_idW : NULL, bufferA ? bufferW : NULL, len, flags, machine ); + if (!ret && bufferA && !WideCharToMultiByte( CP_ACP, 0, bufferW, len, bufferA, len, 0, 0 )) + { + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) ret = CR_BUFFER_SMALL; + else ret = CR_FAILURE; + } + free( bufferW ); + + return ret; +} + +/*********************************************************************** + * CM_Get_Device_Interface_ListW (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Get_Device_Interface_ListW( GUID *class, DEVINSTID_W instance_id, WCHAR *buffer, ULONG len, ULONG flags ) +{ + return CM_Get_Device_Interface_List_ExW( class, instance_id, buffer, len, flags, NULL ); +} + +/*********************************************************************** + * CM_Get_Device_Interface_ListA (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Get_Device_Interface_ListA( GUID *class, DEVINSTID_A instance_id, char *buffer, ULONG len, ULONG flags ) +{ + return CM_Get_Device_Interface_List_ExA( class, instance_id, buffer, len, flags, NULL ); +} + /*********************************************************************** * CM_Open_Device_Interface_Key_ExW (cfgmgr32.@) */ diff --git a/dlls/cfgmgr32/cfgmgr32.spec b/dlls/cfgmgr32/cfgmgr32.spec index 275b6d6f509..580f45e0ba4 100644 --- a/dlls/cfgmgr32/cfgmgr32.spec +++ b/dlls/cfgmgr32/cfgmgr32.spec @@ -112,14 +112,14 @@ @ stdcall CM_Get_Device_Interface_AliasW(wstr ptr ptr ptr long) setupapi.CM_Get_Device_Interface_AliasW @ stub CM_Get_Device_Interface_Alias_ExA @ stub CM_Get_Device_Interface_Alias_ExW -@ stdcall CM_Get_Device_Interface_ListA(ptr ptr ptr long long) setupapi.CM_Get_Device_Interface_ListA -@ stdcall CM_Get_Device_Interface_ListW(ptr ptr ptr long long) setupapi.CM_Get_Device_Interface_ListW -@ stdcall CM_Get_Device_Interface_List_ExA(ptr ptr ptr long long ptr) setupapi.CM_Get_Device_Interface_List_ExA -@ stdcall CM_Get_Device_Interface_List_ExW(ptr ptr ptr long long ptr) setupapi.CM_Get_Device_Interface_List_ExW -@ stdcall CM_Get_Device_Interface_List_SizeA(ptr ptr str long) setupapi.CM_Get_Device_Interface_List_SizeA -@ stdcall CM_Get_Device_Interface_List_SizeW(ptr ptr wstr long) setupapi.CM_Get_Device_Interface_List_SizeW -@ stdcall CM_Get_Device_Interface_List_Size_ExA(ptr ptr str long ptr) setupapi.CM_Get_Device_Interface_List_Size_ExA -@ stdcall CM_Get_Device_Interface_List_Size_ExW(ptr ptr wstr long ptr) setupapi.CM_Get_Device_Interface_List_Size_ExW +@ stdcall CM_Get_Device_Interface_ListA(ptr ptr ptr long long) +@ stdcall CM_Get_Device_Interface_ListW(ptr ptr ptr long long) +@ stdcall CM_Get_Device_Interface_List_ExA(ptr ptr ptr long long ptr) +@ stdcall CM_Get_Device_Interface_List_ExW(ptr ptr ptr long long ptr) +@ stdcall CM_Get_Device_Interface_List_SizeA(ptr ptr str long) +@ stdcall CM_Get_Device_Interface_List_SizeW(ptr ptr wstr long) +@ stdcall CM_Get_Device_Interface_List_Size_ExA(ptr ptr str long ptr) +@ stdcall CM_Get_Device_Interface_List_Size_ExW(ptr ptr wstr long ptr) @ stdcall CM_Get_Device_Interface_PropertyW(wstr ptr ptr ptr ptr long) @ stub CM_Get_Device_Interface_Property_ExW @ stub CM_Get_Device_Interface_Property_KeysW diff --git a/dlls/cfgmgr32/tests/cfgmgr32.c b/dlls/cfgmgr32/tests/cfgmgr32.c index f98af2a9a99..be82e6125f0 100644 --- a/dlls/cfgmgr32/tests/cfgmgr32.c +++ b/dlls/cfgmgr32/tests/cfgmgr32.c @@ -76,6 +76,7 @@ static const char *debugstr_ok( const char *cond ) } while (0) #define ok_u4( r, op, e ) ok_ex( r, op, e, UINT, "%u" ) #define ok_x4( r, op, e ) ok_ex( r, op, e, UINT, "%#x" ) +#define ok_ptr( r, op, e ) ok_ex( r, op, e, void *, "%p" ) static const WCHAR *guid_string( const GUID *guid, WCHAR *buffer, UINT length ) { @@ -470,7 +471,7 @@ static void check_device_path_casing(const WCHAR *original_path) free(path); } -static void test_CM_Get_Device_Interface_List(void) +static void test_CM_Get_Device_Interface_PropertyW(void) { BYTE iface_detail_buffer[sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) + 256 * sizeof(WCHAR)]; SP_DEVICE_INTERFACE_DATA iface = {sizeof(iface)}; @@ -2441,6 +2442,183 @@ static void test_CM_Get_Class_Property(void) ok_x4( ret, ==, CR_NO_SUCH_VALUE ); } +static void test_CM_Get_Device_Interface_List_Size(void) +{ + GUID guid = GUID_DEVINTERFACE_HID; + ULONG size_all, size_present, size; + CONFIGRET ret; + + ret = CM_Get_Device_Interface_List_SizeW( NULL, &guid, NULL, CM_GET_DEVICE_INTERFACE_LIST_PRESENT ); + ok_x4( ret, ==, CR_INVALID_POINTER ); + ret = CM_Get_Device_Interface_List_SizeW( &size, NULL, NULL, CM_GET_DEVICE_INTERFACE_LIST_PRESENT ); + ok_x4( ret, ==, CR_FAILURE ); + for (UINT flag = 2; flag; flag <<= 1) + { + winetest_push_context( "%#x", flag ); + ret = CM_Get_Device_Interface_List_SizeW( &size, &guid, NULL, flag ); + ok_x4( ret, ==, CR_INVALID_FLAG ); + winetest_pop_context(); + } + size = 0xdeadbeef; + ret = CM_Get_Device_Interface_List_SizeW( &size, &guid, (WCHAR *)L"INVALID", CM_GET_DEVICE_INTERFACE_LIST_ALL_DEVICES ); + todo_wine ok_x4( ret, ==, CR_INVALID_DEVNODE ); + todo_wine ok_u4( size, ==, 0 ); + ret = CM_Get_Device_Interface_List_SizeW( &size, &guid, (WCHAR *)L"\\\\?\\", CM_GET_DEVICE_INTERFACE_LIST_ALL_DEVICES ); + todo_wine ok_x4( ret, ==, CR_INVALID_DEVNODE ); + + size_present = 0; + ret = CM_Get_Device_Interface_List_SizeW( &size_present, &guid, NULL, CM_GET_DEVICE_INTERFACE_LIST_PRESENT ); + ok_x4( ret, ==, CR_SUCCESS ); + ok_u4( size_present, >, 0 ); + size_all = 0; + ret = CM_Get_Device_Interface_List_SizeW( &size_all, &guid, NULL, CM_GET_DEVICE_INTERFACE_LIST_ALL_DEVICES ); + ok_x4( ret, ==, CR_SUCCESS ); + ok_u4( size_all, >, 0 ); + + size = 0; + ret = CM_Get_Device_Interface_List_SizeW( &size, &guid, (WCHAR *)L"", CM_GET_DEVICE_INTERFACE_LIST_ALL_DEVICES ); + ok_x4( ret, ==, CR_SUCCESS ); + ok( size == size_all || broken(size == 1), "got size %lu\n", size ); + + + size = 0; + ret = CM_Get_Device_Interface_List_SizeA( &size, &guid, NULL, CM_GET_DEVICE_INTERFACE_LIST_ALL_DEVICES ); + ok_x4( ret, ==, CR_SUCCESS ); + ok_u4( size, ==, size_all ); + size = 0; + ret = CM_Get_Device_Interface_List_SizeA( &size, &guid, NULL, CM_GET_DEVICE_INTERFACE_LIST_PRESENT ); + ok_x4( ret, ==, CR_SUCCESS ); + ok_u4( size, ==, size_present ); +} + +static void test_CM_Get_Device_Interface_List(void) +{ + GUID guid = GUID_DEVINTERFACE_HID; + WCHAR *tmp, *tmp2, *buffer, *bufferW, instance[MAX_PATH]; + CONFIGRET ret; + char *bufferA; + ULONG size; + + size = 0; + ret = CM_Get_Device_Interface_List_SizeW( &size, &guid, NULL, CM_GET_DEVICE_INTERFACE_LIST_ALL_DEVICES ); + ok_x4( ret, ==, CR_SUCCESS ); + ok_u4( size, >, 0 ); + + buffer = malloc( size * sizeof(*buffer) ); + ok_ptr( buffer, !=, NULL ); + + + ret = CM_Get_Device_Interface_ListW( &guid, NULL, NULL, 0, CM_GET_DEVICE_INTERFACE_LIST_PRESENT ); + ok_x4( ret, ==, CR_INVALID_POINTER ); + ret = CM_Get_Device_Interface_ListW( NULL, NULL, buffer, size, CM_GET_DEVICE_INTERFACE_LIST_PRESENT ); + ok_x4( ret, ==, CR_FAILURE ); + for (UINT flag = 2; flag; flag <<= 1) + { + winetest_push_context( "%#x", flag ); + ret = CM_Get_Device_Interface_ListW( &guid, NULL, buffer, size, flag ); + ok_x4( ret, ==, CR_INVALID_FLAG ); + winetest_pop_context(); + } + ret = CM_Get_Device_Interface_ListW( &guid, (WCHAR *)L"INVALID", buffer, size, CM_GET_DEVICE_INTERFACE_LIST_ALL_DEVICES ); + todo_wine ok_x4( ret, ==, CR_INVALID_DEVNODE ); + ret = CM_Get_Device_Interface_ListW( &guid, (WCHAR *)L"\\\\?\\", buffer, size, CM_GET_DEVICE_INTERFACE_LIST_ALL_DEVICES ); + todo_wine ok_x4( ret, ==, CR_INVALID_DEVNODE ); + + + ret = CM_Get_Device_Interface_ListW( &guid, NULL, buffer, size, CM_GET_DEVICE_INTERFACE_LIST_PRESENT ); + ok_x4( ret, ==, CR_SUCCESS ); + ok( !wcsncmp( buffer, L"\\\\?\\HID#VID_", 12 ), "got %s\n", debugstr_wn( buffer, size ) ); + for (tmp = buffer; *tmp; tmp = tmp + wcslen( tmp ) + 1) + { + WCHAR sep, substr[MAX_PATH], upper[MAX_PATH]; + ok( !wcsncmp( tmp, L"\\\\?\\HID#VID_", 12 ), "got %s\n", debugstr_wn( buffer, size ) ); + + /* \\\\?\\HID#VID_XXXX&PID_XXXX upper case prefix */ + wcscpy( substr, tmp ); + sep = substr[25]; + substr[25] = 0; + wcscpy( upper, substr ); + wcsupr( upper ); + ok_wcs( upper, substr ); + substr[25] = sep; + + /* lower case instance, refstr and guid suffix */ + wcscpy( substr, wcschr( substr + 25, '#' ) ); + wcscpy( upper, substr ); + wcslwr( upper ); + flaky_wine ok_wcs( upper, substr ); + } + ok( tmp > buffer, "got %s\n", debugstr_wn( buffer, size ) ); + + + bufferA = malloc( size * sizeof(*bufferA) ); + ok_ptr( bufferA, !=, NULL ); + ret = CM_Get_Device_Interface_ListA( &guid, NULL, bufferA, size, CM_GET_DEVICE_INTERFACE_LIST_PRESENT ); + ok_x4( ret, ==, CR_SUCCESS ); + + bufferW = malloc( size * sizeof(*bufferW) ); + ok_ptr( bufferW, !=, NULL ); + memset( bufferW, 0xcc, size * sizeof(*bufferW) ); + MultiByteToWideChar( CP_ACP, 0, bufferA, size, bufferW, size ); + for (tmp = buffer, tmp2 = bufferW; *tmp && *tmp2; tmp = tmp + wcslen( tmp ) + 1, tmp2 = tmp2 + wcslen( tmp2 ) + 1) + ok( !wcscmp( tmp, tmp2 ), "got %s, %s.\n", debugstr_wn( bufferW, size ), debugstr_wn( buffer, size ) ); + ok( !*tmp, "got %s, %s.\n", debugstr_wn( bufferW, size ), debugstr_wn( buffer, size ) ); + ok( !*tmp2, "got %s, %s.\n", debugstr_wn( bufferW, size ), debugstr_wn( buffer, size ) ); + + + free( bufferA ); + free( bufferW ); + + + wcscpy( instance, buffer + 4 ); + *wcsrchr( instance, '#' ) = 0; + while ((tmp = wcschr( instance, '#' ))) *tmp = '\\'; + ret = CM_Get_Device_Interface_ListW( &guid, instance, buffer, size, CM_GET_DEVICE_INTERFACE_LIST_PRESENT ); + ok_x4( ret, ==, CR_SUCCESS ); + ok( !wcsncmp( buffer, L"\\\\?\\", 4 ), "got %s\n", debugstr_wn( buffer, size ) ); + ok( !wcscmp( buffer + wcslen( buffer ) + 1, L"" ), "got %s\n", debugstr_wn( buffer, size ) ); + + + free( buffer ); + + + guid = GUID_DEVINTERFACE_DISPLAY_ADAPTER; + + size = 0; + ret = CM_Get_Device_Interface_List_SizeW( &size, &guid, NULL, CM_GET_DEVICE_INTERFACE_LIST_ALL_DEVICES ); + ok_x4( ret, ==, CR_SUCCESS ); + ok_u4( size, >, 0 ); + + buffer = malloc( size * sizeof(*buffer) ); + ok_ptr( buffer, !=, NULL ); + + ret = CM_Get_Device_Interface_ListW( &guid, NULL, buffer, size, CM_GET_DEVICE_INTERFACE_LIST_PRESENT ); + ok_x4( ret, ==, CR_SUCCESS ); + ok( !wcsncmp( buffer, L"\\\\?\\", 4 ), "got %s\n", debugstr_wn( buffer, size ) ); + for (tmp = buffer; *tmp; tmp = tmp + wcslen( tmp ) + 1) + { + WCHAR *sep, substr[MAX_PATH], upper[MAX_PATH]; + ok( !wcsncmp( tmp, L"\\\\?\\", 4 ), "got %s\n", debugstr_wn( buffer, size ) ); + + /* upper case enumerator prefix */ + wcscpy( substr, tmp ); + if ((sep = wcschr( substr, '#' ))) *sep = 0; + wcscpy( upper, substr ); + wcsupr( upper ); + ok_wcs( upper, substr ); + *sep = '#'; + + /* lower case instance, refstr and guid suffix */ + wcscpy( substr, wcschr( sep + 1, '#' ) ); + wcscpy( upper, substr ); + wcslwr( upper ); + ok_wcs( upper, substr ); + } + ok( tmp > buffer, "got %s\n", debugstr_wn( buffer, size ) ); + + free( buffer ); +} + static void test_CM_Open_Device_Interface_Key(void) { WCHAR iface[4096], name[MAX_PATH], expect[MAX_PATH], buffer[39], *refstr; @@ -2546,10 +2724,12 @@ START_TEST(cfgmgr32) test_CM_Get_Class_Registry_Property(); test_CM_Get_Class_Property(); test_CM_Get_Class_Property_Keys(); + test_CM_Get_Device_Interface_List_Size(); + test_CM_Get_Device_Interface_List(); test_CM_Open_Device_Interface_Key(); test_CM_Get_Device_ID_List(); test_CM_Register_Notification(); - test_CM_Get_Device_Interface_List(); + test_CM_Get_Device_Interface_PropertyW(); test_DevGetObjects(); test_DevCreateObjectQuery(); test_DevGetObjectProperties_invalid(); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10148