From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/cfgmgr32/cfgmgr32.c | 84 ++++++++++++++++++++++++++++++++++ dlls/cfgmgr32/cfgmgr32.spec | 4 +- dlls/cfgmgr32/tests/cfgmgr32.c | 47 +++++++++++++++++++ 3 files changed, 133 insertions(+), 2 deletions(-) diff --git a/dlls/cfgmgr32/cfgmgr32.c b/dlls/cfgmgr32/cfgmgr32.c index 74f4c7317b2..8902d157ee7 100644 --- a/dlls/cfgmgr32/cfgmgr32.c +++ b/dlls/cfgmgr32/cfgmgr32.c @@ -39,6 +39,17 @@ static const WCHAR *guid_string( const GUID *guid, WCHAR *buffer, UINT length ) return buffer; } +static LSTATUS propkey_from_string( const WCHAR *str, DEVPROPKEY *key ) +{ + const WCHAR *pid; + LSTATUS err; + + if (!(pid = wcsrchr( str, '\\' ))) return ERROR_INVALID_DATA; + if ((err = guid_from_string( str, &key->fmtid ))) return err; + if (swscanf( pid + 1, L"%04X", &key->pid ) != 1) return ERROR_INVALID_DATA; + return ERROR_SUCCESS; +} + static const WCHAR *propkey_string( const DEVPROPKEY *key, const WCHAR *prefix, WCHAR *buffer, UINT length ) { swprintf( buffer, length, L"%s{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\\%04X", prefix, @@ -241,6 +252,51 @@ static LSTATUS get_class_property( const GUID *class, struct property *prop ) return err; } +static LSTATUS enum_class_property_keys( HKEY hkey, DEVPROPKEY *buffer, ULONG *size ) +{ + ULONG capacity = *size, count = 0; + LSTATUS err = ERROR_SUCCESS; + HKEY props_key; + + for (UINT i = 0; i < ARRAY_SIZE(class_properties); i++) + { + const struct property_desc *desc = class_properties + i; + if (desc->name && !RegQueryValueExW( hkey, desc->name, NULL, NULL, NULL, NULL )) + { + if (capacity < ++count || !buffer) err = ERROR_MORE_DATA; + else buffer[count - 1] = *desc->key; + } + } + + if (!open_key( hkey, L"Properties", KEY_ENUMERATE_SUB_KEYS, TRUE, &props_key )) + { + WCHAR name[MAX_PATH]; + for (ULONG i = 0, len = ARRAY_SIZE(name); !RegEnumValueW( props_key, i, name, &len, 0, NULL, NULL, NULL ); i++, len = ARRAY_SIZE(name)) + { + if (capacity < ++count || !buffer) err = ERROR_MORE_DATA; + else err = propkey_from_string( name, buffer + count - 1 ); + } + RegCloseKey( props_key ); + } + + *size = count; + return err; +} + +static LSTATUS get_class_property_keys( const GUID *class, DEVPROPKEY *buffer, ULONG *size ) +{ + WCHAR path[39]; + LSTATUS err; + HKEY hkey; + + guid_string( class, path, ARRAY_SIZE(path) ); + if ((err = open_class_key( HKEY_LOCAL_MACHINE, path, KEY_ALL_ACCESS, TRUE, &hkey ))) return err; + err = enum_class_property_keys( hkey, buffer, size ); + RegCloseKey( hkey ); + + return err; +} + struct device_interface { GUID class_guid; @@ -576,6 +632,34 @@ CONFIGRET WINAPI CM_Get_Class_PropertyW( const GUID *class, const DEVPROPKEY *ke return CM_Get_Class_Property_ExW( class, key, type, buffer, size, flags, NULL ); } +/*********************************************************************** + * CM_Get_Class_Property_Keys_Ex (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Get_Class_Property_Keys_Ex( const GUID *class, DEVPROPKEY *keys, ULONG *count, ULONG flags, HMACHINE machine ) +{ + LSTATUS err; + + TRACE( "class %s, keys %p, size %p, flags %#lx, machine %p\n", debugstr_guid(class), keys, count, flags, machine ); + if (machine) FIXME( "machine %p not implemented!\n", machine ); + if (flags) FIXME( "flags %#lx not implemented!\n", flags ); + + if (!class) return CR_INVALID_POINTER; + if (!count) return CR_INVALID_POINTER; + if (*count && !keys) return CR_INVALID_POINTER; + + err = get_class_property_keys( class, keys, count ); + if (err && err != ERROR_MORE_DATA) *count = 0; + return map_error( err ); +} + +/*********************************************************************** + * CM_Get_Class_Property_Keys (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Get_Class_Property_Keys( const GUID *class, DEVPROPKEY *keys, ULONG *count, ULONG flags ) +{ + return CM_Get_Class_Property_Keys_Ex( class, keys, count, flags, NULL ); +} + /*********************************************************************** * CM_Open_Device_Interface_Key_ExW (cfgmgr32.@) */ diff --git a/dlls/cfgmgr32/cfgmgr32.spec b/dlls/cfgmgr32/cfgmgr32.spec index 99aef888aa2..275b6d6f509 100644 --- a/dlls/cfgmgr32/cfgmgr32.spec +++ b/dlls/cfgmgr32/cfgmgr32.spec @@ -74,8 +74,8 @@ @ stub CM_Get_Class_Name_ExW @ stdcall CM_Get_Class_PropertyW(ptr ptr ptr ptr long long) @ stdcall CM_Get_Class_Property_ExW(ptr ptr ptr ptr long long ptr) -@ stdcall CM_Get_Class_Property_Keys(ptr ptr ptr long) setupapi.CM_Get_Class_Property_Keys -@ stdcall CM_Get_Class_Property_Keys_Ex(ptr ptr ptr long ptr) setupapi.CM_Get_Class_Property_Keys_Ex +@ stdcall CM_Get_Class_Property_Keys(ptr ptr ptr long) +@ stdcall CM_Get_Class_Property_Keys_Ex(ptr ptr ptr long ptr) @ stdcall CM_Get_Class_Registry_PropertyA(ptr long ptr ptr long long ptr) @ stdcall CM_Get_Class_Registry_PropertyW(ptr long ptr ptr long long ptr) @ stub CM_Get_Depth diff --git a/dlls/cfgmgr32/tests/cfgmgr32.c b/dlls/cfgmgr32/tests/cfgmgr32.c index beba61591e6..f98af2a9a99 100644 --- a/dlls/cfgmgr32/tests/cfgmgr32.c +++ b/dlls/cfgmgr32/tests/cfgmgr32.c @@ -2481,6 +2481,52 @@ static void test_CM_Open_Device_Interface_Key(void) } } +static void test_CM_Get_Class_Property_Keys(void) +{ + GUID guid = GUID_DEVCLASS_HIDCLASS; + DEVPROPKEY buffer[64]; + CONFIGRET ret; + ULONG len; + + ret = CM_Get_Class_Property_Keys( &guid, buffer, NULL, 0 ); + ok_x4( ret, ==, CR_INVALID_POINTER ); + ret = CM_Get_Class_Property_Keys( NULL, buffer, &len, 0 ); + ok_x4( ret, ==, CR_INVALID_POINTER ); + len = 1; + ret = CM_Get_Class_Property_Keys( &guid, NULL, &len, 0 ); + ok_x4( ret, ==, CR_INVALID_POINTER ); + + len = 0; + ret = CM_Get_Class_Property_Keys( &guid, NULL, &len, 0 ); + ok_x4( ret, ==, CR_BUFFER_SMALL ); + todo_wine ok( len == 9 || broken(len == 10), "got len %lu\n", len ); + len = 0; + ret = CM_Get_Class_Property_Keys( &guid, buffer, &len, 0 ); + ok_x4( ret, ==, CR_BUFFER_SMALL ); + todo_wine ok( len == 9 || broken(len == 10), "got len %lu\n", len ); + + memset( &guid, 0xcd, sizeof(guid) ); + len = ARRAY_SIZE(buffer); + memset( buffer, 0xcd, sizeof(buffer) ); + ret = CM_Get_Class_Property_Keys( &guid, buffer, &len, 0 ); + ok_x4( ret, ==, CR_NO_SUCH_REGISTRY_KEY ); + ok_u4( len, ==, 0 ); + + guid = GUID_DEVCLASS_HIDCLASS; + len = ARRAY_SIZE(buffer); + memset( buffer, 0xcd, sizeof(buffer) ); + ret = CM_Get_Class_Property_Keys( &guid, buffer, &len, 0 ); + ok_x4( ret, ==, CR_SUCCESS ); + todo_wine ok( len == 9 || broken(len == 10), "got len %lu\n", len ); + + ok( !memcmp( buffer + 0, &DEVPKEY_DeviceClass_ClassName, sizeof(*buffer) ), "got %s\n", debugstr_DEVPROPKEY( buffer + 0 ) ); + ok( !memcmp( buffer + 1, &DEVPKEY_DeviceClass_Name, sizeof(*buffer) ), "got %s\n", debugstr_DEVPROPKEY( buffer + 1 ) ); + todo_wine ok( !memcmp( buffer + 2, &DEVPKEY_DeviceClass_Security, sizeof(*buffer) ), "got %s\n", debugstr_DEVPROPKEY( buffer + 2 ) ); + todo_wine ok( !memcmp( buffer + 3, &DEVPKEY_DeviceClass_NoInstallClass, sizeof(*buffer) ), "got %s\n", debugstr_DEVPROPKEY( buffer + 3 ) ); + todo_wine ok( !memcmp( buffer + 4, &DEVPKEY_DeviceClass_IconPath, sizeof(*buffer) ), "got %s\n", debugstr_DEVPROPKEY( buffer + 4 ) ); + if (len == 9) todo_wine ok( !memcmp( buffer + 5, &DEVPKEY_NAME, sizeof(*buffer) ), "got %s\n", debugstr_DEVPROPKEY( buffer + 5 ) ); +} + START_TEST(cfgmgr32) { HMODULE mod = GetModuleHandleA("cfgmgr32.dll"); @@ -2499,6 +2545,7 @@ START_TEST(cfgmgr32) test_CM_Open_Class_Key(); test_CM_Get_Class_Registry_Property(); test_CM_Get_Class_Property(); + test_CM_Get_Class_Property_Keys(); test_CM_Open_Device_Interface_Key(); test_CM_Get_Device_ID_List(); test_CM_Register_Notification(); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10148