From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/cfgmgr32/cfgmgr32.c | 58 ++++++++++++++++++++++++++++- dlls/cfgmgr32/cfgmgr32.spec | 4 +- dlls/cfgmgr32/tests/cfgmgr32.c | 67 ++++++++++++++++++++++++++++++++++ 3 files changed, 126 insertions(+), 3 deletions(-) diff --git a/dlls/cfgmgr32/cfgmgr32.c b/dlls/cfgmgr32/cfgmgr32.c index 42cd5a42d28..24a9ccb5643 100644 --- a/dlls/cfgmgr32/cfgmgr32.c +++ b/dlls/cfgmgr32/cfgmgr32.c @@ -740,6 +740,52 @@ static LSTATUS get_device_property( HKEY root, const struct device *dev, struct return err; } +LSTATUS enum_device_property_keys( HKEY hkey, const struct device *dev, DEVPROPKEY *buffer, ULONG *size ) +{ + ULONG capacity = *size, count = 0; + LSTATUS err = ERROR_SUCCESS; + HKEY props_key; + + if (capacity < ++count || !buffer) err = ERROR_MORE_DATA; + else buffer[count - 1] = DEVPKEY_Device_InstanceId; + + for (UINT i = 0; i < ARRAY_SIZE(device_properties); i++) + { + const struct property_desc *desc = device_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_device_property_keys( HKEY root, const struct device *dev, DEVPROPKEY *buffer, ULONG *size ) +{ + LSTATUS err; + HKEY hkey; + + if ((err = open_device_key( root, dev, KEY_QUERY_VALUE, TRUE, &hkey ))) return err; + err = enum_device_property_keys( hkey, dev, buffer, size ); + RegCloseKey( hkey ); + + return err; +} + static CRITICAL_SECTION devnode_cs; static CRITICAL_SECTION_DEBUG devnode_cs_debug = { 0, 0, &devnode_cs, @@ -1649,11 +1695,21 @@ CONFIGRET WINAPI CM_Get_DevNode_PropertyW( DEVINST node, const DEVPROPKEY *key, */ CONFIGRET WINAPI CM_Get_DevNode_Property_Keys_Ex( DEVINST node, DEVPROPKEY *keys, ULONG *count, ULONG flags, HMACHINE machine ) { + struct device dev; + LSTATUS err; + TRACE( "node %#lx, keys %p, count %p, flags %#lx, machine %p\n", node, keys, count, flags, machine ); if (machine) FIXME( "machine %p not implemented!\n", machine ); if (flags) FIXME( "flags %#lx not implemented!\n", flags ); - return CR_CALL_NOT_IMPLEMENTED; + if (!count) return CR_INVALID_POINTER; + if (*count && !keys) return CR_INVALID_POINTER; + if (devnode_get_device( node, &dev )) return CR_INVALID_DEVNODE; + + err = get_device_property_keys( HKEY_LOCAL_MACHINE, &dev, keys, count ); + if (err && err != ERROR_MORE_DATA) *count = 0; + if (err == ERROR_FILE_NOT_FOUND) return CR_NO_SUCH_DEVICE_INTERFACE; + return map_error( err ); } /*********************************************************************** diff --git a/dlls/cfgmgr32/cfgmgr32.spec b/dlls/cfgmgr32/cfgmgr32.spec index a728a908a2e..ae538de0a15 100644 --- a/dlls/cfgmgr32/cfgmgr32.spec +++ b/dlls/cfgmgr32/cfgmgr32.spec @@ -86,8 +86,8 @@ @ stub CM_Get_DevNode_Custom_Property_ExW @ stdcall CM_Get_DevNode_PropertyW(long ptr ptr ptr ptr long) @ stdcall CM_Get_DevNode_Property_ExW(long ptr ptr ptr ptr long ptr) -@ stub CM_Get_DevNode_Property_Keys -@ stub CM_Get_DevNode_Property_Keys_Ex +@ stdcall CM_Get_DevNode_Property_Keys(long ptr ptr long) +@ stdcall CM_Get_DevNode_Property_Keys_Ex(long ptr ptr long ptr) @ stdcall CM_Get_DevNode_Registry_PropertyA(long long ptr ptr ptr long) @ stdcall CM_Get_DevNode_Registry_PropertyW(long long ptr ptr ptr long) @ stdcall CM_Get_DevNode_Registry_Property_ExA(long long ptr ptr ptr long ptr) diff --git a/dlls/cfgmgr32/tests/cfgmgr32.c b/dlls/cfgmgr32/tests/cfgmgr32.c index 540b38f12ca..8939cf008b3 100644 --- a/dlls/cfgmgr32/tests/cfgmgr32.c +++ b/dlls/cfgmgr32/tests/cfgmgr32.c @@ -3564,9 +3564,12 @@ static void test_CM_Get_DevNode_Property(void) len = sizeof(buffer); ret = CM_Get_DevNode_PropertyW( node, &DEVPKEY_Device_BusRelations, &type, (BYTE *)buffer, &len, 0 ); ok_x4( ret, ==, CR_NO_SUCH_VALUE ); + type = 0xdeadbeef; len = sizeof(buffer); ret = CM_Get_DevNode_PropertyW( node, &DEVPKEY_Device_Parent, &type, (BYTE *)buffer, &len, 0 ); todo_wine ok_x4( ret, ==, CR_SUCCESS ); + todo_wine ok_u4( type, ==, DEVPROP_TYPE_STRING ); + todo_wine ok_u4( len, >, 1 ); len = sizeof(buffer); ret = CM_Get_DevNode_PropertyW( node, &DEVPKEY_Device_Children, &type, (BYTE *)buffer, &len, 0 ); ok_x4( ret, ==, CR_NO_SUCH_VALUE ); @@ -3613,6 +3616,69 @@ static void test_CM_Get_DevNode_Property(void) todo_wine ok_u4( len, >, 1 ); } +static void test_CM_Get_DevNode_Property_Keys(void) +{ + WCHAR iface[4096], instance_id[MAX_PATH]; + DEVPROPKEY buffer[128]; + DWORD i, size, type; + CONFIGRET ret; + DEVINST node; + GUID guid; + + + guid = GUID_DEVINTERFACE_HID; + ret = CM_Get_Device_Interface_ListW( &guid, NULL, iface, ARRAY_SIZE(iface), CM_GET_DEVICE_INTERFACE_LIST_PRESENT ); + if (broken( !*iface )) + { + skip( "No HID device present, skipping tests\n" ); + return; + } + ok_x4( ret, ==, CR_SUCCESS ); + size = sizeof(instance_id); + ret = CM_Get_Device_Interface_PropertyW( iface, &DEVPKEY_Device_InstanceId, &type, (BYTE *)instance_id, &size, 0 ); + ok_x4( ret, ==, CR_SUCCESS ); + ok_x4( type, ==, DEVPROP_TYPE_STRING ); + + node = 0xdeadbeef; + ret = CM_Locate_DevNodeW( &node, instance_id, 0 ); + ok_x4( ret, ==, CR_SUCCESS ); + todo_wine ok_x4( node, ==, 2 ); + + size = ARRAY_SIZE(buffer); + ret = CM_Get_DevNode_Property_Keys( 0, buffer, &size, 0 ); + ok_x4( ret, ==, CR_INVALID_DEVNODE ); + ok_u4( size, ==, ARRAY_SIZE(buffer) ); + size = ARRAY_SIZE(buffer); + ret = CM_Get_DevNode_Property_Keys( 0xdeadbeef, buffer, &size, 0 ); + ok_x4( ret, ==, CR_INVALID_DEVNODE ); + ok_u4( size, ==, ARRAY_SIZE(buffer) ); + size = ARRAY_SIZE(buffer); + ret = CM_Get_DevNode_Property_Keys( node, NULL, NULL, 0 ); + ok_x4( ret, ==, CR_INVALID_POINTER ); + size = ARRAY_SIZE(buffer); + ret = CM_Get_DevNode_Property_Keys( node, buffer, NULL, 0 ); + ok_x4( ret, ==, CR_INVALID_POINTER ); + size = ARRAY_SIZE(buffer); + ret = CM_Get_DevNode_Property_Keys( node, NULL, &size, 0 ); + ok_x4( ret, ==, CR_INVALID_POINTER ); + ok_u4( size, ==, ARRAY_SIZE(buffer) ); + size = 0; + ret = CM_Get_DevNode_Property_Keys( node, NULL, &size, 0 ); + ok_x4( ret, ==, CR_BUFFER_SMALL ); + ok_u4( size, >, 3 ); + size = ARRAY_SIZE(buffer); + memset( buffer, 0xcd, sizeof(buffer) ); + ret = CM_Get_DevNode_Property_Keys( node, buffer, &size, 0 ); + ok_x4( ret, ==, CR_SUCCESS ); + ok_u4( size, >, 3 ); + todo_wine ok( !memcmp( buffer + 0, &DEVPKEY_Device_DeviceDesc, sizeof(*buffer) ), "got {%s,%#lx}\n", debugstr_guid( &buffer[0].fmtid ), buffer[0].pid ); + todo_wine ok( !memcmp( buffer + 1, &DEVPKEY_Device_HardwareIds, sizeof(*buffer) ), "got {%s,%#lx}\n", debugstr_guid( &buffer[1].fmtid ), buffer[1].pid ); + todo_wine ok( !memcmp( buffer + 2, &DEVPKEY_Device_CompatibleIds, sizeof(*buffer) ), "got {%s,%#lx}\n", debugstr_guid( &buffer[2].fmtid ), buffer[2].pid ); + + for (i = 0; i < size; i++) if (!memcmp( buffer + i, &DEVPKEY_Device_Parent, sizeof(*buffer) )) break; + todo_wine ok( i < size, "DEVPKEY_Device_Parent not found\n" ); +} + static void test_CM_Get_Class_Property_Keys(void) { GUID guid = GUID_DEVCLASS_HIDCLASS; @@ -3690,6 +3756,7 @@ START_TEST(cfgmgr32) test_CM_Open_DevNode_Key(); test_CM_Get_DevNode_Registry_Property(); test_CM_Get_DevNode_Property(); + test_CM_Get_DevNode_Property_Keys(); test_DevGetObjects(); test_DevCreateObjectQuery(); test_DevGetObjectProperties_invalid(); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10584