From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/cfgmgr32/cfgmgr32.c | 56 ++++++++++++++++++- dlls/cfgmgr32/cfgmgr32.spec | 4 +- dlls/cfgmgr32/tests/cfgmgr32.c | 99 +++++++++++++++++++++++++++++++++- 3 files changed, 154 insertions(+), 5 deletions(-) diff --git a/dlls/cfgmgr32/cfgmgr32.c b/dlls/cfgmgr32/cfgmgr32.c index 5d3ad003a8b..ac194614645 100644 --- a/dlls/cfgmgr32/cfgmgr32.c +++ b/dlls/cfgmgr32/cfgmgr32.c @@ -96,9 +96,14 @@ static HKEY cache_root_key( HKEY root, const WCHAR *key, const WCHAR **path ) static LSTATUS open_key( HKEY root, const WCHAR *key, REGSAM access, BOOL open, HKEY *hkey ) { + LSTATUS err; + if ((root = cache_root_key( root, key, &key )) == (HKEY)-1) return ERROR_FILE_NOT_FOUND; if (open) return RegOpenKeyExW( root, key, 0, access, hkey ); - return RegCreateKeyExW( root, key, 0, NULL, 0, access, NULL, hkey, NULL ); + + err = RegCreateKeyExW( root, key, 0, NULL, 0, access, NULL, hkey, NULL ); + if (err == ERROR_CHILD_MUST_BE_VOLATILE) err = RegCreateKeyExW( root, key, 0, NULL, REG_OPTION_VOLATILE, access, NULL, hkey, NULL ); + return err; } static LSTATUS query_value( HKEY hkey, const WCHAR *value, WCHAR *buffer, DWORD len ) @@ -1343,3 +1348,52 @@ CONFIGRET WINAPI CM_Get_Device_IDA( DEVINST node, char *buffer, ULONG len, ULONG { return CM_Get_Device_ID_ExA( node, buffer, len, flags, NULL ); } + +/*********************************************************************** + * CM_Open_DevNode_Key_Ex (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Open_DevNode_Key_Ex( DEVINST node, REGSAM access, ULONG profile, REGDISPOSITION disposition, HKEY *hkey, ULONG flags, HMACHINE machine ) +{ + BOOL open = disposition == RegDisposition_OpenExisting; + HKEY root = HKEY_LOCAL_MACHINE, dev_key; + struct device dev; + LSTATUS err; + + TRACE( "node %#lx, access %#lx, profile %lu, disposition %#lx, hkey %p, flags %#lx, machine %p\n", node, access, profile, disposition, hkey, flags, machine ); + if (machine) FIXME( "machine %p not implemented!\n", machine ); + + if (devnode_get_device( node, &dev )) return CR_NO_SUCH_DEVNODE; + if ((flags & (CM_REGISTRY_USER | CM_REGISTRY_CONFIG)) == (CM_REGISTRY_USER | CM_REGISTRY_CONFIG)) return CR_INVALID_FLAG; + + if (flags & CM_REGISTRY_CONFIG) root = HKEY_CURRENT_CONFIG; + else if (flags & CM_REGISTRY_USER) root = HKEY_CURRENT_USER; + + if (flags & CM_REGISTRY_SOFTWARE) + { + WCHAR driver[MAX_PATH]; + DWORD len = sizeof(driver); + + if ((err = open_device_key( HKEY_LOCAL_MACHINE, &dev, access, open, &dev_key ))) return map_error( err ); + if (RegQueryValueExW( dev_key, L"Driver", NULL, NULL, (BYTE *)driver, &len )) err = ERROR_NOT_FOUND; + RegCloseKey( dev_key ); + + if (!err) err = open_class_key( root, driver, access, open, hkey ); + return map_error( err ); + } + + if (root != HKEY_LOCAL_MACHINE) return map_error( open_device_key( root, &dev, access, open, hkey ) ); + + if ((err = open_device_key( root, &dev, access, open, &dev_key ))) return map_error( err ); + err = open_key( dev_key, L"Device Parameters", access, open, hkey ); + RegCloseKey( dev_key ); + + return map_error( err ); +} + +/*********************************************************************** + * CM_Open_DevNode_Key (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Open_DevNode_Key( DEVINST node, REGSAM access, ULONG profile, REGDISPOSITION disposition, HKEY *hkey, ULONG flags ) +{ + return CM_Open_DevNode_Key_Ex( node, access, profile, disposition, hkey, flags, NULL ); +} diff --git a/dlls/cfgmgr32/cfgmgr32.spec b/dlls/cfgmgr32/cfgmgr32.spec index 1b8a515ab8a..59e628d6165 100644 --- a/dlls/cfgmgr32/cfgmgr32.spec +++ b/dlls/cfgmgr32/cfgmgr32.spec @@ -180,8 +180,8 @@ @ stdcall CM_Open_Class_KeyW(ptr wstr long long ptr long) @ stdcall CM_Open_Class_Key_ExA(ptr str long long ptr long ptr) @ stdcall CM_Open_Class_Key_ExW(ptr wstr long long ptr long ptr) -@ stdcall CM_Open_DevNode_Key(long long long long ptr long) setupapi.CM_Open_DevNode_Key -@ stub CM_Open_DevNode_Key_Ex +@ stdcall CM_Open_DevNode_Key(long long long long ptr long) +@ stdcall CM_Open_DevNode_Key_Ex(long long long long ptr long ptr) @ stdcall CM_Open_Device_Interface_KeyA(str long long ptr long) @ stdcall CM_Open_Device_Interface_KeyW(wstr long long ptr long) @ stdcall CM_Open_Device_Interface_Key_ExA(str long long ptr long ptr) diff --git a/dlls/cfgmgr32/tests/cfgmgr32.c b/dlls/cfgmgr32/tests/cfgmgr32.c index 9cf0eb37c11..1babd6e52da 100644 --- a/dlls/cfgmgr32/tests/cfgmgr32.c +++ b/dlls/cfgmgr32/tests/cfgmgr32.c @@ -2253,8 +2253,8 @@ static BOOL compare_unicode_string( const UNICODE_STRING *string, const WCHAR *e !wcsnicmp( string->Buffer, expect, string->Length / sizeof(WCHAR) ); } -#define check_object_name( a, b ) _check_object_name( __LINE__, a, b ) -static void _check_object_name( unsigned line, HANDLE handle, const WCHAR *expected_name ) +#define check_object_name( a, b ) check_object_name_( __LINE__, a, b, FALSE ) +static void check_object_name_( unsigned line, HANDLE handle, const WCHAR *expected_name, BOOL todo ) { char buffer[1024]; UNICODE_STRING *str = (UNICODE_STRING *)buffer, expect; @@ -2267,6 +2267,7 @@ static void _check_object_name( unsigned line, HANDLE handle, const WCHAR *expec status = NtQueryObject( handle, ObjectNameInformation, buffer, sizeof(buffer), &len ); ok_(__FILE__, line)( status == STATUS_SUCCESS, "NtQueryObject failed %lx\n", status ); ok_(__FILE__, line)( len >= sizeof(OBJECT_NAME_INFORMATION) + str->Length, "unexpected len %lu\n", len ); + todo_wine_if(todo) ok_(__FILE__, line)( compare_unicode_string( str, expected_name ), "got %s, expected %s\n", debugstr_w(str->Buffer), debugstr_w(expected_name) ); } @@ -2995,6 +2996,99 @@ static void test_CM_Locate_DevNode(void) ok_wcs( instance_id, path ); } +static void test_CM_Open_DevNode_Key(void) +{ + WCHAR iface[4096], driver[MAX_PATH], path[MAX_PATH], instance_id[MAX_PATH]; + UNICODE_STRING user; + DWORD size, type; + CONFIGRET ret; + DEVINST node; + GUID guid; + HKEY hkey; + + RtlFormatCurrentUserKeyPath( &user ); + + 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 ); + ok_x4( node, ==, next_devinst - 1 ); + + size = ARRAY_SIZE(driver); + swprintf( path, ARRAY_SIZE(path), L"System\\CurrentControlSet\\Enum\\%s", instance_id ); + ret = RegGetValueW( HKEY_LOCAL_MACHINE, path, L"Driver", RRF_RT_ANY, NULL, (BYTE *)driver, &size ); + ok_u4( ret, ==, ERROR_SUCCESS ); + + + ret = CM_Open_DevNode_Key( node, KEY_QUERY_VALUE, 0, RegDisposition_OpenExisting, &hkey, CM_REGISTRY_HARDWARE ); + ok_x4( ret, ==, CR_SUCCESS ); + swprintf( path, ARRAY_SIZE(path), L"\\REGISTRY\\MACHINE\\SYSTEM\\ControlSet001\\Enum\\%s\\Device Parameters", instance_id ); + check_object_name( hkey, path ); + RegCloseKey( hkey ); + + ret = CM_Open_DevNode_Key( node, KEY_QUERY_VALUE, 0, RegDisposition_OpenExisting, &hkey, CM_REGISTRY_USER ); + ok_x4( ret, ==, CR_NO_SUCH_REGISTRY_KEY ); + ret = CM_Open_DevNode_Key( node, KEY_QUERY_VALUE, 0, RegDisposition_OpenAlways, &hkey, CM_REGISTRY_USER ); + ok_x4( ret, ==, CR_SUCCESS ); + swprintf( path, ARRAY_SIZE(path), L"%s\\System\\CurrentControlSet\\Enum\\%s", user.Buffer, instance_id ); + check_object_name( hkey, path ); + RegCloseKey( hkey ); + swprintf( path, ARRAY_SIZE(path), L"System\\CurrentControlSet\\Enum\\%s", instance_id ); + RegDeleteKeyW( HKEY_CURRENT_USER, path ); + + ret = CM_Open_DevNode_Key( node, KEY_QUERY_VALUE, 0, RegDisposition_OpenExisting, &hkey, CM_REGISTRY_CONFIG ); + ok_x4( ret, ==, CR_NO_SUCH_REGISTRY_KEY ); + ret = CM_Open_DevNode_Key( node, KEY_QUERY_VALUE, 0, RegDisposition_OpenAlways, &hkey, CM_REGISTRY_CONFIG ); + ok_x4( ret, ==, CR_SUCCESS ); + swprintf( path, ARRAY_SIZE(path), L"\\REGISTRY\\MACHINE\\SYSTEM\\ControlSet001\\Hardware Profiles\\0001\\System\\CurrentControlSet\\Enum\\%s", instance_id ); + check_object_name_( __LINE__, hkey, path, TRUE ); + RegCloseKey( hkey ); + swprintf( path, ARRAY_SIZE(path), L"System\\CurrentControlSet\\Enum\\%s", instance_id ); + RegDeleteKeyW( HKEY_CURRENT_CONFIG, path ); + + + ret = CM_Open_DevNode_Key( node, KEY_QUERY_VALUE, 0, RegDisposition_OpenExisting, &hkey, CM_REGISTRY_SOFTWARE ); + ok_x4( ret, ==, CR_SUCCESS ); + swprintf( path, ARRAY_SIZE(path), L"\\REGISTRY\\MACHINE\\SYSTEM\\ControlSet001\\Control\\Class\\%s", driver ); + check_object_name( hkey, path ); + RegCloseKey( hkey ); + + ret = CM_Open_DevNode_Key( node, KEY_QUERY_VALUE, 0, RegDisposition_OpenExisting, &hkey, CM_REGISTRY_SOFTWARE | CM_REGISTRY_USER ); + ok_x4( ret, ==, CR_NO_SUCH_REGISTRY_KEY ); + ret = CM_Open_DevNode_Key( node, KEY_QUERY_VALUE, 0, RegDisposition_OpenAlways, &hkey, CM_REGISTRY_SOFTWARE | CM_REGISTRY_USER ); + ok_x4( ret, ==, CR_SUCCESS ); + swprintf( path, ARRAY_SIZE(path), L"%s\\System\\CurrentControlSet\\Control\\Class\\%s", user.Buffer, driver ); + check_object_name( hkey, path ); + RegCloseKey( hkey ); + swprintf( path, ARRAY_SIZE(path), L"System\\CurrentControlSet\\Control\\Class\\%s", driver ); + RegDeleteKeyW( HKEY_CURRENT_USER, path ); + + ret = CM_Open_DevNode_Key( node, KEY_QUERY_VALUE, 0, RegDisposition_OpenExisting, &hkey, CM_REGISTRY_SOFTWARE | CM_REGISTRY_CONFIG ); + ok_x4( ret, ==, CR_NO_SUCH_REGISTRY_KEY ); + ret = CM_Open_DevNode_Key( node, KEY_QUERY_VALUE, 0, RegDisposition_OpenAlways, &hkey, CM_REGISTRY_SOFTWARE | CM_REGISTRY_CONFIG ); + ok_x4( ret, ==, CR_SUCCESS ); + swprintf( path, ARRAY_SIZE(path), L"\\REGISTRY\\MACHINE\\SYSTEM\\ControlSet001\\Hardware Profiles\\0001\\System\\CurrentControlSet\\Control\\Class\\%s", driver ); + check_object_name_( __LINE__, hkey, path, TRUE ); + RegCloseKey( hkey ); + swprintf( path, ARRAY_SIZE(path), L"System\\CurrentControlSet\\Control\\Class\\%s", driver ); + RegDeleteKeyW( HKEY_CURRENT_CONFIG, path ); + + + RtlFreeUnicodeString( &user ); +} + static void test_CM_Get_Class_Property_Keys(void) { GUID guid = GUID_DEVCLASS_HIDCLASS; @@ -3069,6 +3163,7 @@ START_TEST(cfgmgr32) test_CM_Get_Device_Interface_Property_setupapi(); test_CM_Get_Device_ID_List(); test_CM_Register_Notification(); + test_CM_Open_DevNode_Key(); test_DevGetObjects(); test_DevCreateObjectQuery(); test_DevGetObjectProperties_invalid(); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10436