From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/cfgmgr32/cfgmgr32.c | 40 ++++++++++++++++++++++++++++++++++ dlls/cfgmgr32/cfgmgr32.spec | 4 ++-- dlls/cfgmgr32/tests/cfgmgr32.c | 33 ++++++++++++++++++++++++++++ include/cfgmgr32.h | 4 ++++ 4 files changed, 79 insertions(+), 2 deletions(-) diff --git a/dlls/cfgmgr32/cfgmgr32.c b/dlls/cfgmgr32/cfgmgr32.c index 2a2e9f96d33..2d85662b47a 100644 --- a/dlls/cfgmgr32/cfgmgr32.c +++ b/dlls/cfgmgr32/cfgmgr32.c @@ -23,6 +23,14 @@ WINE_DEFAULT_DEBUG_CHANNEL(setupapi); +static LSTATUS guid_from_string( const WCHAR *str, GUID *guid ) +{ + UNICODE_STRING guid_str; + RtlInitUnicodeString( &guid_str, str ); + if (RtlGUIDFromString( &guid_str, guid )) return ERROR_INVALID_DATA; + return ERROR_SUCCESS; +} + static const WCHAR *guid_string( const GUID *guid, WCHAR *buffer, UINT length ) { swprintf( buffer, length, L"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", @@ -91,6 +99,7 @@ static CONFIGRET map_error( LSTATUS err ) switch (err) { case ERROR_FILE_NOT_FOUND: return CR_NO_SUCH_REGISTRY_KEY; + case ERROR_NO_MORE_ITEMS: return CR_NO_SUCH_VALUE; case ERROR_SUCCESS: return CR_SUCCESS; default: WARN( "unmapped error %lu\n", err ); return CR_FAILURE; } @@ -132,6 +141,37 @@ DWORD WINAPI CM_MapCrToWin32Err( CONFIGRET code, DWORD default_error ) return default_error; } +/*********************************************************************** + * CM_Enumerate_Classes_Ex (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Enumerate_Classes_Ex( ULONG index, GUID *class, ULONG flags, HMACHINE machine ) +{ + WCHAR buffer[39]; + LSTATUS err; + HKEY root; + + TRACE( "index %lu, class %s, flags %#lx, machine %p\n", index, debugstr_guid(class), flags, machine ); + if (machine) FIXME( "machine %p not implemented!\n", machine ); + + if (!class) return CR_INVALID_POINTER; + if (flags & ~CM_ENUMERATE_CLASSES_BITS) return CR_INVALID_FLAG; + + if (flags == CM_ENUMERATE_CLASSES_INSTALLER) root = cache_root_key( HKEY_LOCAL_MACHINE, control_classW, NULL ); + else root = cache_root_key( HKEY_LOCAL_MACHINE, device_classesW, NULL ); + if (root == (HKEY)-1) return CR_NO_SUCH_REGISTRY_KEY; + + if ((err = RegEnumKeyW( root, index, buffer, ARRAY_SIZE(buffer) ))) return map_error( err ); + return map_error( guid_from_string( buffer, class ) ); +} + +/*********************************************************************** + * CM_Enumerate_Classes (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Enumerate_Classes( ULONG index, GUID *class, ULONG flags ) +{ + return CM_Enumerate_Classes_Ex( index, class, flags, NULL ); +} + /*********************************************************************** * CM_Get_Class_Key_Name_ExW (cfgmgr32.@) */ diff --git a/dlls/cfgmgr32/cfgmgr32.spec b/dlls/cfgmgr32/cfgmgr32.spec index 4bafdae1ed1..4865cadaf53 100644 --- a/dlls/cfgmgr32/cfgmgr32.spec +++ b/dlls/cfgmgr32/cfgmgr32.spec @@ -46,8 +46,8 @@ @ stub CM_Duplicate_PowerScheme @ stub CM_Enable_DevNode @ stub CM_Enable_DevNode_Ex -@ stdcall CM_Enumerate_Classes(long ptr long) setupapi.CM_Enumerate_Classes -@ stub CM_Enumerate_Classes_Ex +@ stdcall CM_Enumerate_Classes(long ptr long) +@ stdcall CM_Enumerate_Classes_Ex(long ptr long ptr) @ stub CM_Enumerate_EnumeratorsA @ stub CM_Enumerate_EnumeratorsW @ stub CM_Enumerate_Enumerators_ExA diff --git a/dlls/cfgmgr32/tests/cfgmgr32.c b/dlls/cfgmgr32/tests/cfgmgr32.c index 0f47bdd1fa8..c2d9d4d7c34 100644 --- a/dlls/cfgmgr32/tests/cfgmgr32.c +++ b/dlls/cfgmgr32/tests/cfgmgr32.c @@ -1900,6 +1900,38 @@ static void test_DevFindProperty_invalid( void ) ok( !prop, "got prop %p\n", prop ); } +static void test_CM_Enumerate_Classes(void) +{ + CONFIGRET ret; + GUID guid; + + ret = CM_Enumerate_Classes( 0, NULL, 0 ); + ok_x4( ret, ==, CR_INVALID_POINTER ); + for (UINT flag = 2; flag; flag <<= 1) + { + winetest_push_context( "%#x", flag ); + ret = CM_Enumerate_Classes( 0, &guid, flag ); + ok_x4( ret, ==, CR_INVALID_FLAG ); + winetest_pop_context(); + } + ret = CM_Enumerate_Classes( -1, &guid, 0 ); + ok_x4( ret, ==, CR_NO_SUCH_VALUE ); + + for (UINT i = 0; !(ret = CM_Enumerate_Classes( i, &guid, CM_ENUMERATE_CLASSES_INSTALLER )); i++) + if (IsEqualGUID( &guid, &GUID_DEVINTERFACE_HID )) break; + ok_x4( ret, ==, CR_NO_SUCH_VALUE ); + for (UINT i = 0; !(ret = CM_Enumerate_Classes( i, &guid, CM_ENUMERATE_CLASSES_INSTALLER )); i++) + if (IsEqualGUID( &guid, &GUID_DEVCLASS_HIDCLASS )) break; + ok_x4( ret, ==, CR_SUCCESS ); + + for (UINT i = 0; !(ret = CM_Enumerate_Classes( i, &guid, CM_ENUMERATE_CLASSES_INTERFACE )); i++) + if (IsEqualGUID( &guid, &GUID_DEVINTERFACE_HID )) break; + ok_x4( ret, ==, CR_SUCCESS ); + for (UINT i = 0; !(ret = CM_Enumerate_Classes( i, &guid, CM_ENUMERATE_CLASSES_INTERFACE )); i++) + if (IsEqualGUID( &guid, &GUID_DEVCLASS_HIDCLASS )) break; + ok_x4( ret, ==, CR_NO_SUCH_VALUE ); +} + static void test_CM_Get_Class_Key_Name(void) { GUID guid = GUID_DEVCLASS_DISPLAY; @@ -2046,6 +2078,7 @@ START_TEST(cfgmgr32) pDevFindProperty = (void *)GetProcAddress(mod, "DevFindProperty"); test_CM_MapCrToWin32Err(); + test_CM_Enumerate_Classes(); test_CM_Get_Class_Key_Name(); test_CM_Open_Class_Key(); test_CM_Get_Device_ID_List(); diff --git a/include/cfgmgr32.h b/include/cfgmgr32.h index 29a3673dbe9..43a2157f1cf 100644 --- a/include/cfgmgr32.h +++ b/include/cfgmgr32.h @@ -205,6 +205,10 @@ typedef DWORD CONFIGRET; #define CM_OPEN_CLASS_KEY_INTERFACE 0x00000001 #define CM_OPEN_CLASS_KEY_BITS 0x00000001 +#define CM_ENUMERATE_CLASSES_INSTALLER 0x00000000 +#define CM_ENUMERATE_CLASSES_INTERFACE 0x00000001 +#define CM_ENUMERATE_CLASSES_BITS 0x00000001 + typedef DWORD DEVINST, *PDEVINST; typedef DWORD DEVNODE, *PDEVNODE; typedef HANDLE HMACHINE, *PHMACHINE; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10078