From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/cfgmgr32/cfgmgr32.c | 84 ++++++++++++++++++++++++++++++++++ dlls/cfgmgr32/cfgmgr32.spec | 8 ++-- dlls/cfgmgr32/tests/cfgmgr32.c | 73 +++++++++++++++++++++++++++++ include/cfgmgr32.h | 4 ++ 4 files changed, 165 insertions(+), 4 deletions(-) diff --git a/dlls/cfgmgr32/cfgmgr32.c b/dlls/cfgmgr32/cfgmgr32.c index f01b2aabd3e..9b144af0052 100644 --- a/dlls/cfgmgr32/cfgmgr32.c +++ b/dlls/cfgmgr32/cfgmgr32.c @@ -31,6 +31,39 @@ static const WCHAR *guid_string( const GUID *guid, WCHAR *buffer, UINT length ) return buffer; } +static const WCHAR control_classW[] = L"System\\CurrentControlSet\\Control\\Class\\"; +static const WCHAR device_classesW[] = L"System\\CurrentControlSet\\Control\\DeviceClasses\\"; + +static LSTATUS open_key( HKEY root, const WCHAR *key, REGSAM access, BOOL open, HKEY *hkey ) +{ + if (open) return RegOpenKeyExW( root, key, 0, access, hkey ); + return RegCreateKeyExW( root, key, 0, NULL, 0, access, NULL, hkey, NULL ); +} + +static LSTATUS open_class_key( HKEY root, const WCHAR *key, REGSAM access, BOOL open, HKEY *hkey ) +{ + WCHAR path[MAX_PATH]; + swprintf( path, ARRAY_SIZE(path), L"%s%s", control_classW, key ); + return open_key( root, path, access, open, hkey ); +} + +static LSTATUS open_device_classes_key( HKEY root, const WCHAR *key, REGSAM access, BOOL open, HKEY *hkey ) +{ + WCHAR path[MAX_PATH]; + swprintf( path, ARRAY_SIZE(path), L"%s%s", device_classesW, key ); + return open_key( root, path, access, open, hkey ); +} + +static CONFIGRET map_error( LSTATUS err ) +{ + switch (err) + { + case ERROR_FILE_NOT_FOUND: return CR_NO_SUCH_REGISTRY_KEY; + case ERROR_SUCCESS: return CR_SUCCESS; + default: WARN( "unmapped error %lu\n", err ); return CR_FAILURE; + } +} + /*********************************************************************** * CM_MapCrToWin32Err (cfgmgr32.@) */ @@ -117,6 +150,57 @@ CONFIGRET WINAPI CM_Get_Class_Key_NameA( GUID *class, char *name, ULONG *len, UL return CM_Get_Class_Key_Name_ExA( class, name, len, flags, NULL ); } +/*********************************************************************** + * CM_Open_Class_Key_ExW (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Open_Class_Key_ExW( GUID *class, const WCHAR *name, REGSAM access, REGDISPOSITION disposition, HKEY *hkey, ULONG flags, HMACHINE machine ) +{ + BOOL open = disposition == RegDisposition_OpenExisting; + WCHAR buffer[39]; + + TRACE( "class %s, name %s, access %#lx, disposition %#lx, hkey %p, flags %#lx\n", debugstr_guid(class), debugstr_w(name), access, disposition, hkey, flags ); + if (machine) FIXME( "machine %p not implemented!\n", machine ); + + if (name) return CR_INVALID_DATA; + if (!hkey) return CR_INVALID_POINTER; + if (flags & ~CM_OPEN_CLASS_KEY_BITS) return CR_INVALID_FLAG; + + if (!class) *buffer = 0; + else guid_string( class, buffer, ARRAY_SIZE(buffer) ); + + if (flags == CM_OPEN_CLASS_KEY_INSTALLER) return map_error( open_class_key( HKEY_LOCAL_MACHINE, buffer, access, open, hkey ) ); + return map_error( open_device_classes_key( HKEY_LOCAL_MACHINE, buffer, access, open, hkey ) ); +} + +/*********************************************************************** + * CM_Open_Class_Key_ExA (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Open_Class_Key_ExA( GUID *class, const char *nameA, REGSAM access, REGDISPOSITION disposition, HKEY *hkey, ULONG flags, HMACHINE machine ) +{ + WCHAR nameW[MAX_PATH]; + + TRACE( "guid %s, nameA %s, access %#lx, disposition %#lx, hkey %p, flags %#lx\n", debugstr_guid(class), debugstr_a(nameA), access, disposition, hkey, flags ); + + if (nameA) MultiByteToWideChar( CP_ACP, 0, nameA, -1, nameW, ARRAY_SIZE(nameW) ); + return CM_Open_Class_Key_ExW( class, nameA ? nameW : NULL, access, disposition, hkey, flags, machine ); +} + +/*********************************************************************** + * CM_Open_Class_KeyW (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Open_Class_KeyW( GUID *class, const WCHAR *name, REGSAM access, REGDISPOSITION disposition, HKEY *hkey, ULONG flags ) +{ + return CM_Open_Class_Key_ExW( class, name, access, disposition, hkey, flags, NULL ); +} + +/*********************************************************************** + * CM_Open_Class_KeyA (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Open_Class_KeyA( GUID *class, const char *name, REGSAM access, REGDISPOSITION disposition, HKEY *hkey, ULONG flags ) +{ + return CM_Open_Class_Key_ExA( class, name, access, disposition, hkey, flags, NULL ); +} + /*********************************************************************** * CM_Get_Device_Interface_PropertyW (cfgmgr32.@) */ diff --git a/dlls/cfgmgr32/cfgmgr32.spec b/dlls/cfgmgr32/cfgmgr32.spec index c5b6107e736..4bafdae1ed1 100644 --- a/dlls/cfgmgr32/cfgmgr32.spec +++ b/dlls/cfgmgr32/cfgmgr32.spec @@ -176,10 +176,10 @@ @ stub CM_Move_DevNode @ stub CM_Move_DevNode_Ex @ stub CM_Next_Range -@ stub CM_Open_Class_KeyA -@ stub CM_Open_Class_KeyW -@ stub CM_Open_Class_Key_ExA -@ stub CM_Open_Class_Key_ExW +@ stdcall CM_Open_Class_KeyA(ptr str long long ptr long) +@ 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 @ stub CM_Open_Device_Interface_KeyA diff --git a/dlls/cfgmgr32/tests/cfgmgr32.c b/dlls/cfgmgr32/tests/cfgmgr32.c index 271c5d515ef..0f47bdd1fa8 100644 --- a/dlls/cfgmgr32/tests/cfgmgr32.c +++ b/dlls/cfgmgr32/tests/cfgmgr32.c @@ -1962,6 +1962,78 @@ static void test_CM_Get_Class_Key_Name(void) ok_wcs( L"{cdcdcdcd-cdcd-cdcd-cdcd-cdcdcdcdcdcd}", buffer ); } +static BOOL compare_unicode_string( const UNICODE_STRING *string, const WCHAR *expect ) +{ + return string->Length == wcslen( expect ) * sizeof(WCHAR) && + !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 ) +{ + char buffer[1024]; + UNICODE_STRING *str = (UNICODE_STRING *)buffer, expect; + ULONG len = 0; + NTSTATUS status; + + RtlInitUnicodeString( &expect, expected_name ); + + memset( buffer, 0, sizeof(buffer) ); + 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 ); + ok_(__FILE__, line)( compare_unicode_string( str, expected_name ), "got %s, expected %s\n", + debugstr_w(str->Buffer), debugstr_w(expected_name) ); +} + +static void test_CM_Open_Class_Key(void) +{ + CONFIGRET ret; + GUID guid; + HKEY hkey; + + ret = CM_Open_Class_KeyW( NULL, NULL, KEY_QUERY_VALUE, RegDisposition_OpenExisting, &hkey, CM_OPEN_CLASS_KEY_INSTALLER ); + ok_x4( ret, ==, CR_SUCCESS ); + check_object_name( hkey, L"\\REGISTRY\\MACHINE\\SYSTEM\\ControlSet001\\Control\\Class" ); + RegCloseKey( hkey ); + + ret = CM_Open_Class_KeyW( NULL, NULL, KEY_QUERY_VALUE, RegDisposition_OpenExisting, &hkey, CM_OPEN_CLASS_KEY_INTERFACE ); + ok_x4( ret, ==, CR_SUCCESS ); + check_object_name( hkey, L"\\REGISTRY\\MACHINE\\SYSTEM\\ControlSet001\\Control\\DeviceClasses" ); + RegCloseKey( hkey ); + + guid = GUID_DEVCLASS_DISPLAY; + ret = CM_Open_Class_KeyW( &guid, NULL, KEY_QUERY_VALUE, RegDisposition_OpenExisting, &hkey, CM_OPEN_CLASS_KEY_INSTALLER ); + ok_x4( ret, ==, CR_SUCCESS ); + check_object_name( hkey, L"\\REGISTRY\\MACHINE\\SYSTEM\\ControlSet001\\Control\\Class\\{4d36e968-e325-11ce-bfc1-08002be10318}" ); + RegCloseKey( hkey ); + + guid = GUID_DEVINTERFACE_DISPLAY_ADAPTER; + ret = CM_Open_Class_KeyW( &guid, NULL, KEY_QUERY_VALUE, RegDisposition_OpenExisting, &hkey, CM_OPEN_CLASS_KEY_INTERFACE ); + ok_x4( ret, ==, CR_SUCCESS ); + check_object_name( hkey, L"\\REGISTRY\\MACHINE\\SYSTEM\\ControlSet001\\Control\\DeviceClasses\\{5b45201d-f2f2-4f3b-85bb-30ff1f953599}" ); + RegCloseKey( hkey ); + + memset( &guid, 0xcd, sizeof(guid) ); + ret = CM_Open_Class_KeyW( &guid, NULL, KEY_QUERY_VALUE, RegDisposition_OpenExisting, &hkey, CM_OPEN_CLASS_KEY_INSTALLER ); + ok_x4( ret, ==, CR_NO_SUCH_REGISTRY_KEY ); + ret = CM_Open_Class_KeyW( &guid, NULL, KEY_QUERY_VALUE, RegDisposition_OpenAlways, &hkey, CM_OPEN_CLASS_KEY_INSTALLER ); + ok_x4( ret, ==, CR_SUCCESS ); + check_object_name( hkey, L"\\REGISTRY\\MACHINE\\SYSTEM\\ControlSet001\\Control\\Class\\{cdcdcdcd-cdcd-cdcd-cdcd-cdcdcdcdcdcd}" ); + RegCloseKey( hkey ); + ret = RegDeleteKeyW( HKEY_LOCAL_MACHINE, L"SYSTEM\\ControlSet001\\Control\\Class\\{cdcdcdcd-cdcd-cdcd-cdcd-cdcdcdcdcdcd}" ); + ok_x4( ret, ==, ERROR_SUCCESS ); + + ret = CM_Open_Class_KeyW( &guid, NULL, KEY_QUERY_VALUE, RegDisposition_OpenExisting, &hkey, CM_OPEN_CLASS_KEY_INTERFACE ); + ok_x4( ret, ==, CR_NO_SUCH_REGISTRY_KEY ); + ret = CM_Open_Class_KeyW( &guid, NULL, KEY_QUERY_VALUE, RegDisposition_OpenAlways, &hkey, CM_OPEN_CLASS_KEY_INTERFACE ); + ok_x4( ret, ==, CR_SUCCESS ); + check_object_name( hkey, L"\\REGISTRY\\MACHINE\\SYSTEM\\ControlSet001\\Control\\DeviceClasses\\{cdcdcdcd-cdcd-cdcd-cdcd-cdcdcdcdcdcd}" ); + RegCloseKey( hkey ); + ret = RegDeleteKeyW( HKEY_LOCAL_MACHINE, L"SYSTEM\\ControlSet001\\Control\\DeviceClasses\\{cdcdcdcd-cdcd-cdcd-cdcd-cdcdcdcdcdcd}" ); + ok_x4( ret, ==, ERROR_SUCCESS ); +} + START_TEST(cfgmgr32) { HMODULE mod = GetModuleHandleA("cfgmgr32.dll"); @@ -1975,6 +2047,7 @@ START_TEST(cfgmgr32) test_CM_MapCrToWin32Err(); test_CM_Get_Class_Key_Name(); + test_CM_Open_Class_Key(); test_CM_Get_Device_ID_List(); test_CM_Register_Notification(); test_CM_Get_Device_Interface_List(); diff --git a/include/cfgmgr32.h b/include/cfgmgr32.h index e1f417a93a7..29a3673dbe9 100644 --- a/include/cfgmgr32.h +++ b/include/cfgmgr32.h @@ -201,6 +201,10 @@ typedef DWORD CONFIGRET; #define CM_GET_DEVICE_INTERFACE_LIST_ALL_DEVICES 0x00000001 #define CM_GET_DEVICE_INTERFACE_LIST_BITS 0x00000001 +#define CM_OPEN_CLASS_KEY_INSTALLER 0x00000000 +#define CM_OPEN_CLASS_KEY_INTERFACE 0x00000001 +#define CM_OPEN_CLASS_KEY_BITS 0x00000001 + typedef DWORD DEVINST, *PDEVINST; typedef DWORD DEVNODE, *PDEVNODE; typedef HANDLE HMACHINE, *PHMACHINE; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10078