[PATCH 0/6] MR10110: cfgmgr32: Implement CM_Get_Class_(Registry_)Property(_Ex)W and other base functions.
From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/cfgmgr32/cfgmgr32.c | 61 ++++++++++++++++++++++++++++++++++ dlls/cfgmgr32/cfgmgr32.spec | 8 ++--- dlls/cfgmgr32/tests/cfgmgr32.c | 48 ++++++++++++++++++++++++++ 3 files changed, 113 insertions(+), 4 deletions(-) diff --git a/dlls/cfgmgr32/cfgmgr32.c b/dlls/cfgmgr32/cfgmgr32.c index 2d85662b47a..60320f94a96 100644 --- a/dlls/cfgmgr32/cfgmgr32.c +++ b/dlls/cfgmgr32/cfgmgr32.c @@ -41,6 +41,7 @@ static const WCHAR *guid_string( const GUID *guid, WCHAR *buffer, UINT length ) static const WCHAR control_classW[] = L"System\\CurrentControlSet\\Control\\Class\\"; static const WCHAR device_classesW[] = L"System\\CurrentControlSet\\Control\\DeviceClasses\\"; +static const WCHAR enum_rootW[] = L"System\\CurrentControlSet\\Enum\\"; static struct key_cache { @@ -52,6 +53,7 @@ static struct key_cache { { HKEY_LOCAL_MACHINE, control_classW, ARRAY_SIZE(control_classW) - 1, (HKEY)-1 }, { HKEY_LOCAL_MACHINE, device_classesW, ARRAY_SIZE(device_classesW) - 1, (HKEY)-1 }, + { HKEY_LOCAL_MACHINE, enum_rootW, ARRAY_SIZE(enum_rootW) - 1, (HKEY)-1 }, }; static HKEY cache_root_key( HKEY root, const WCHAR *key, const WCHAR **path ) @@ -172,6 +174,65 @@ CONFIGRET WINAPI CM_Enumerate_Classes( ULONG index, GUID *class, ULONG flags ) return CM_Enumerate_Classes_Ex( index, class, flags, NULL ); } +/*********************************************************************** + * CM_Enumerate_Enumerators_ExW (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Enumerate_Enumerators_ExW( ULONG index, WCHAR *buffer, ULONG *len, ULONG flags, HMACHINE machine ) +{ + LSTATUS err; + HKEY root; + + TRACE( "index %lu, buffer %p, len %p, flags %#lx, machine %p\n", index, buffer, len, flags, machine ); + if (machine) FIXME( "machine %p not implemented!\n", machine ); + + if (!buffer || !len) return CR_INVALID_POINTER; + if (!*len && buffer) return CR_INVALID_DATA; + if (flags) return CR_INVALID_FLAG; + + root = cache_root_key( HKEY_LOCAL_MACHINE, enum_rootW, NULL ); + if (root == (HKEY)-1) return CR_NO_SUCH_REGISTRY_KEY; + + if (!(err = RegEnumKeyExW( root, index, buffer, len, NULL, NULL, NULL, NULL ))) *len += 1; + return map_error( err ); +} + +/*********************************************************************** + * CM_Enumerate_Enumerators_ExA (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Enumerate_Enumerators_ExA( ULONG index, char *bufferA, ULONG *lenA, ULONG flags, HMACHINE machine ) +{ + WCHAR bufferW[MAX_PATH]; + DWORD lenW = ARRAY_SIZE(bufferW), maxA; + CONFIGRET ret; + + TRACE( "index %lu, bufferA %p, lenA %p, flags %#lx, machine %p\n", index, bufferA, lenA, flags, machine ); + + if (!bufferA || !lenA) return CR_INVALID_POINTER; + if (!(maxA = *lenA) && bufferA) return CR_INVALID_DATA; + + if ((ret = CM_Enumerate_Enumerators_ExW( index, bufferW, &lenW, flags, NULL ))) return ret; + if ((*lenA = WideCharToMultiByte( CP_ACP, 0, bufferW, lenW, NULL, 0, NULL, NULL )) > maxA || !bufferA) return CR_BUFFER_SMALL; + WideCharToMultiByte( CP_ACP, 0, bufferW, lenW, bufferA, maxA, NULL, NULL ); + + return CR_SUCCESS; +} + +/*********************************************************************** + * CM_Enumerate_EnumeratorsW (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Enumerate_EnumeratorsW( ULONG index, WCHAR *buffer, ULONG *len, ULONG flags ) +{ + return CM_Enumerate_Enumerators_ExW( index, buffer, len, flags, NULL ); +} + +/*********************************************************************** + * CM_Enumerate_EnumeratorsA (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Enumerate_EnumeratorsA( ULONG index, char *buffer, ULONG *len, ULONG flags ) +{ + return CM_Enumerate_Enumerators_ExA( index, buffer, len, flags, NULL ); +} + /*********************************************************************** * CM_Get_Class_Key_Name_ExW (cfgmgr32.@) */ diff --git a/dlls/cfgmgr32/cfgmgr32.spec b/dlls/cfgmgr32/cfgmgr32.spec index 4865cadaf53..457654f2324 100644 --- a/dlls/cfgmgr32/cfgmgr32.spec +++ b/dlls/cfgmgr32/cfgmgr32.spec @@ -48,10 +48,10 @@ @ stub CM_Enable_DevNode_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 -@ stub CM_Enumerate_Enumerators_ExW +@ stdcall CM_Enumerate_EnumeratorsA(long ptr ptr long) +@ stdcall CM_Enumerate_EnumeratorsW(long ptr ptr long) +@ stdcall CM_Enumerate_Enumerators_ExA(long ptr ptr long ptr) +@ stdcall CM_Enumerate_Enumerators_ExW(long ptr ptr long ptr) @ stub CM_Find_Range @ stub CM_First_Range @ stub CM_Free_Log_Conf diff --git a/dlls/cfgmgr32/tests/cfgmgr32.c b/dlls/cfgmgr32/tests/cfgmgr32.c index c2d9d4d7c34..f26abb72913 100644 --- a/dlls/cfgmgr32/tests/cfgmgr32.c +++ b/dlls/cfgmgr32/tests/cfgmgr32.c @@ -1932,6 +1932,53 @@ static void test_CM_Enumerate_Classes(void) ok_x4( ret, ==, CR_NO_SUCH_VALUE ); } +static void test_CM_Enumerate_Enumerators(void) +{ + WCHAR buffer[MAX_PATH], upper[MAX_PATH]; + CONFIGRET ret; + ULONG len; + + len = 0; + ret = CM_Enumerate_EnumeratorsW( 0, NULL, &len, 0 ); + ok_x4( ret, ==, CR_INVALID_POINTER ); + ok_x4( len, ==, 0 ); + len = 1; + ret = CM_Enumerate_EnumeratorsW( 0, NULL, &len, 0 ); + ok_x4( ret, ==, CR_INVALID_POINTER ); + ok_x4( len, ==, 1 ); + ret = CM_Enumerate_EnumeratorsW( 0, buffer, NULL, 0 ); + ok_x4( ret, ==, CR_INVALID_POINTER ); + len = 0; + ret = CM_Enumerate_EnumeratorsW( 0, buffer, &len, 0 ); + ok_x4( ret, ==, CR_INVALID_DATA ); + ok_x4( len, ==, 0 ); + + for (UINT flag = 1; flag; flag <<= 1) + { + winetest_push_context( "%#x", flag ); + len = ARRAY_SIZE(buffer); + ret = CM_Enumerate_EnumeratorsW( 0, buffer, &len, flag ); + ok_x4( ret, ==, CR_INVALID_FLAG ); + winetest_pop_context(); + } + + len = ARRAY_SIZE(buffer); + ret = CM_Enumerate_EnumeratorsW( -1, buffer, &len, 0 ); + ok_x4( ret, ==, CR_NO_SUCH_VALUE ); + ok_x4( len, ==, ARRAY_SIZE(buffer) ); + + memset( buffer, 0xcd, sizeof(buffer) ); + for (ULONG i = 0, len = ARRAY_SIZE(buffer); !(ret = CM_Enumerate_EnumeratorsW( i, buffer, &len, 0 )); i++, len = ARRAY_SIZE(buffer)) + { + wcscpy( upper, buffer ); + wcsupr( upper ); + ok_wcs( upper, buffer ); + if (!memcmp( buffer, L"HID\0\xcdcd", 5 )) break; + memset( buffer, 0xcd, sizeof(buffer) ); + } + ok_x4( ret, ==, CR_SUCCESS ); +} + static void test_CM_Get_Class_Key_Name(void) { GUID guid = GUID_DEVCLASS_DISPLAY; @@ -2079,6 +2126,7 @@ START_TEST(cfgmgr32) test_CM_MapCrToWin32Err(); test_CM_Enumerate_Classes(); + test_CM_Enumerate_Enumerators(); test_CM_Get_Class_Key_Name(); test_CM_Open_Class_Key(); test_CM_Get_Device_ID_List(); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10110
From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/setupapi/setupapi.spec | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dlls/setupapi/setupapi.spec b/dlls/setupapi/setupapi.spec index 7fea0020bc9..868fa2b042a 100644 --- a/dlls/setupapi/setupapi.spec +++ b/dlls/setupapi/setupapi.spec @@ -40,10 +40,10 @@ @ stub CM_Enable_DevNode_Ex @ stdcall CM_Enumerate_Classes(long ptr long) cfgmgr32.CM_Enumerate_Classes @ stdcall CM_Enumerate_Classes_Ex(long ptr long ptr) cfgmgr32.CM_Enumerate_Classes_Ex -@ stub CM_Enumerate_EnumeratorsA -@ stub CM_Enumerate_EnumeratorsW -@ stub CM_Enumerate_Enumerators_ExA -@ stub CM_Enumerate_Enumerators_ExW +@ stdcall CM_Enumerate_EnumeratorsA(long ptr ptr long) cfgmgr32.CM_Enumerate_EnumeratorsA +@ stdcall CM_Enumerate_EnumeratorsW(long ptr ptr long) cfgmgr32.CM_Enumerate_EnumeratorsW +@ stdcall CM_Enumerate_Enumerators_ExA(long ptr ptr long ptr) cfgmgr32.CM_Enumerate_Enumerators_ExA +@ stdcall CM_Enumerate_Enumerators_ExW(long ptr ptr long ptr) cfgmgr32.CM_Enumerate_Enumerators_ExW @ stub CM_Find_Range @ stub CM_First_Range @ stub CM_Free_Log_Conf -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10110
From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/cfgmgr32/cfgmgr32.c | 87 ++++++++++++++++++++++++++++++++++ dlls/cfgmgr32/cfgmgr32.spec | 8 ++-- dlls/cfgmgr32/tests/cfgmgr32.c | 49 +++++++++++++++++++ 3 files changed, 140 insertions(+), 4 deletions(-) diff --git a/dlls/cfgmgr32/cfgmgr32.c b/dlls/cfgmgr32/cfgmgr32.c index 60320f94a96..c47e50f37e5 100644 --- a/dlls/cfgmgr32/cfgmgr32.c +++ b/dlls/cfgmgr32/cfgmgr32.c @@ -96,6 +96,37 @@ static LSTATUS open_device_classes_key( HKEY root, const WCHAR *key, REGSAM acce return open_key( root, path, access, open, hkey ); } +struct device_interface +{ + GUID class_guid; + WCHAR class[39]; + WCHAR name[MAX_PATH]; + WCHAR refstr[MAX_PATH]; +}; + +static LSTATUS init_device_interface( struct device_interface *iface, const WCHAR *name ) +{ + WCHAR *tmp; + UINT len; + + if (wcsncmp( name, L"\\\\?\\", 4 )) return ERROR_FILE_NOT_FOUND; + len = swprintf( iface->name, MAX_PATH, L"##?#%s", name + 4 ); + + if ((tmp = wcschr( iface->name, '\\' ))) *tmp++ = 0; + else tmp = iface->name + len; + swprintf( iface->refstr, MAX_PATH, L"#%s", tmp ); + + if (!(tmp = wcsrchr( iface->name, '#' ))) return ERROR_FILE_NOT_FOUND; + return guid_from_string( wcscpy( iface->class, tmp + 1 ), &iface->class_guid ); +} + +static LSTATUS open_device_interface_key( const struct device_interface *iface, REGSAM access, BOOL open, HKEY *hkey ) +{ + WCHAR path[MAX_PATH]; + swprintf( path, ARRAY_SIZE(path), L"%s\\%s", iface->class, iface->name ); + return open_device_classes_key( HKEY_LOCAL_MACHINE, path, access, open, hkey ); +} + static CONFIGRET map_error( LSTATUS err ) { switch (err) @@ -334,6 +365,62 @@ CONFIGRET WINAPI CM_Open_Class_KeyA( GUID *class, const char *name, REGSAM acces return CM_Open_Class_Key_ExA( class, name, access, disposition, hkey, flags, NULL ); } +/*********************************************************************** + * CM_Open_Device_Interface_Key_ExW (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Open_Device_Interface_Key_ExW( const WCHAR *name, REGSAM access, REGDISPOSITION disposition, HKEY *hkey, ULONG flags, HMACHINE machine ) +{ + BOOL open = disposition == RegDisposition_OpenExisting; + struct device_interface iface; + WCHAR path[MAX_PATH]; + HKEY iface_key; + LSTATUS err; + + TRACE( "name %s, access %#lx, disposition %#lx, hkey %p, flags %#lx\n", debugstr_w(name), access, disposition, hkey, flags ); + if (machine) FIXME( "machine %p not implemented!\n", machine ); + + if (!name) return CR_INVALID_POINTER; + if (init_device_interface( &iface, name )) return CR_INVALID_DATA; + if (!hkey) return CR_INVALID_POINTER; + if (flags) return CR_INVALID_FLAG; + + if (open_device_interface_key( &iface, KEY_ALL_ACCESS, TRUE, &iface_key )) return CR_NO_SUCH_DEVICE_INTERFACE; + swprintf( path, ARRAY_SIZE(path), L"%s\\Device Parameters", iface.refstr ); + err = open_key( iface_key, path, access, open, hkey ); + RegCloseKey( iface_key ); + + return map_error( err ); +} + +/*********************************************************************** + * CM_Open_Device_Interface_Key_ExA (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Open_Device_Interface_Key_ExA( const char *ifaceA, REGSAM access, REGDISPOSITION disposition, HKEY *hkey, ULONG flags, HMACHINE machine ) +{ + WCHAR ifaceW[MAX_PATH]; + + TRACE( "ifaceA %s, access %#lx, disposition %#lx, hkey %p, flags %#lx\n", debugstr_a(ifaceA), access, disposition, hkey, flags ); + + if (ifaceA) MultiByteToWideChar( CP_ACP, 0, ifaceA, -1, ifaceW, ARRAY_SIZE(ifaceW) ); + return CM_Open_Device_Interface_Key_ExW( ifaceA ? ifaceW : NULL, access, disposition, hkey, flags, machine ); +} + +/*********************************************************************** + * CM_Open_Device_Interface_KeyW (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Open_Device_Interface_KeyW( const WCHAR *iface, REGSAM access, REGDISPOSITION disposition, HKEY *hkey, ULONG flags ) +{ + return CM_Open_Device_Interface_Key_ExW( iface, access, disposition, hkey, flags, NULL ); +} + +/*********************************************************************** + * CM_Open_Device_Interface_KeyA (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Open_Device_Interface_KeyA( const char *iface, REGSAM access, REGDISPOSITION disposition, HKEY *hkey, ULONG flags ) +{ + return CM_Open_Device_Interface_Key_ExA( iface, access, disposition, hkey, flags, NULL ); +} + /*********************************************************************** * CM_Get_Device_Interface_PropertyW (cfgmgr32.@) */ diff --git a/dlls/cfgmgr32/cfgmgr32.spec b/dlls/cfgmgr32/cfgmgr32.spec index 457654f2324..0695e73a685 100644 --- a/dlls/cfgmgr32/cfgmgr32.spec +++ b/dlls/cfgmgr32/cfgmgr32.spec @@ -182,10 +182,10 @@ @ 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 -@ stub CM_Open_Device_Interface_KeyW -@ stub CM_Open_Device_Interface_Key_ExA -@ stub CM_Open_Device_Interface_Key_ExW +@ 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) +@ stdcall CM_Open_Device_Interface_Key_ExW(wstr long long ptr long ptr) @ stub CM_Query_And_Remove_SubTreeA @ stub CM_Query_And_Remove_SubTreeW @ stub CM_Query_And_Remove_SubTree_ExA diff --git a/dlls/cfgmgr32/tests/cfgmgr32.c b/dlls/cfgmgr32/tests/cfgmgr32.c index f26abb72913..4bc26755ad3 100644 --- a/dlls/cfgmgr32/tests/cfgmgr32.c +++ b/dlls/cfgmgr32/tests/cfgmgr32.c @@ -71,6 +71,14 @@ static const char *debugstr_ok( const char *cond ) #define ok_u4( r, op, e ) ok_ex( r, op, e, UINT, "%u" ) #define ok_x4( r, op, e ) ok_ex( r, op, e, UINT, "%#x" ) +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}", + guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], guid->Data4[2], + guid->Data4[3], guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7] ); + return buffer; +} + static void test_CM_MapCrToWin32Err(void) { unsigned int i; @@ -2113,6 +2121,46 @@ static void test_CM_Open_Class_Key(void) ok_x4( ret, ==, ERROR_SUCCESS ); } +static void test_CM_Open_Device_Interface_Key(void) +{ + WCHAR iface[4096], name[MAX_PATH], expect[MAX_PATH], buffer[39], *refstr; + CONFIGRET ret; + HKEY hkey; + GUID guid; + + guid = GUID_DEVINTERFACE_HID; + ret = CM_Get_Device_Interface_ListW( &guid, NULL, iface, ARRAY_SIZE(iface), CM_GET_DEVICE_INTERFACE_LIST_PRESENT ); + ok_x4( ret, ==, CR_SUCCESS ); + + wcscpy( name, iface + 4 ); + if ((refstr = wcschr( name, '\\' ))) *refstr++ = 0; + else refstr = (WCHAR *)L""; + swprintf( expect, ARRAY_SIZE(expect), L"\\REGISTRY\\MACHINE\\SYSTEM\\ControlSet001\\Control\\DeviceClasses\\%s\\##?#%s\\#%s\\Device Parameters", + guid_string( &guid, buffer, ARRAY_SIZE(buffer) ), name, refstr ); + + ret = CM_Open_Device_Interface_KeyW( NULL, KEY_QUERY_VALUE, RegDisposition_OpenExisting, &hkey, 0 ); + ok_x4( ret, ==, CR_INVALID_POINTER ); + ret = CM_Open_Device_Interface_KeyW( L"DISPLAY_ADAPTER", KEY_QUERY_VALUE, RegDisposition_OpenExisting, &hkey, 0 ); + ok_x4( ret, ==, CR_INVALID_DATA ); + ret = CM_Open_Device_Interface_KeyW( L"\\\\?\\WINETEST#WINETEST#0123456#{5b45201d-f2f2-4f3b-85bb-30ff1f953599}", KEY_QUERY_VALUE, RegDisposition_OpenAlways, &hkey, 0 ); + ok_x4( ret, ==, CR_NO_SUCH_DEVICE_INTERFACE ); + + ret = CM_Open_Device_Interface_KeyW( iface, KEY_QUERY_VALUE, RegDisposition_OpenExisting, &hkey, 0 ); + if (ret == CR_NO_SUCH_REGISTRY_KEY) ret = CM_Open_Device_Interface_KeyW( iface, KEY_QUERY_VALUE, RegDisposition_OpenAlways, &hkey, 0 ); + ok_x4( ret, ==, CR_SUCCESS ); + check_object_name( hkey, expect ); + RegCloseKey( hkey ); + if (ret == CR_NO_SUCH_REGISTRY_KEY) RegDeleteKeyW( HKEY_LOCAL_MACHINE, expect + wcslen( L"\\REGISTRY\\MACHINE\\" ) ); + + for (UINT flag = 1; flag; flag <<= 1) + { + winetest_push_context( "%#x", flag ); + ret = CM_Open_Device_Interface_KeyW( iface, KEY_QUERY_VALUE, RegDisposition_OpenExisting, &hkey, flag ); + ok_x4( ret, ==, CR_INVALID_FLAG ); + winetest_pop_context(); + } +} + START_TEST(cfgmgr32) { HMODULE mod = GetModuleHandleA("cfgmgr32.dll"); @@ -2129,6 +2177,7 @@ START_TEST(cfgmgr32) test_CM_Enumerate_Enumerators(); test_CM_Get_Class_Key_Name(); test_CM_Open_Class_Key(); + test_CM_Open_Device_Interface_Key(); test_CM_Get_Device_ID_List(); test_CM_Register_Notification(); test_CM_Get_Device_Interface_List(); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10110
From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/cfgmgr32/cfgmgr32.c | 128 ++++++++++++++++++++++++++++ dlls/cfgmgr32/cfgmgr32.spec | 4 +- dlls/cfgmgr32/tests/cfgmgr32.c | 148 +++++++++++++++++++++++++++++++++ 3 files changed, 278 insertions(+), 2 deletions(-) diff --git a/dlls/cfgmgr32/cfgmgr32.c b/dlls/cfgmgr32/cfgmgr32.c index c47e50f37e5..cfa1d430409 100644 --- a/dlls/cfgmgr32/cfgmgr32.c +++ b/dlls/cfgmgr32/cfgmgr32.c @@ -96,6 +96,94 @@ static LSTATUS open_device_classes_key( HKEY root, const WCHAR *key, REGSAM acce return open_key( root, path, access, open, hkey ); } +struct property +{ + BOOL ansi; + DEVPROPKEY key; + DEVPROPTYPE *type; + DWORD *reg_type; + void *buffer; + DWORD *size; +}; + +static LSTATUS init_registry_property( struct property *prop, const DEVPROPKEY *base, UINT property, DWORD *type, void *buffer, DWORD *size, BOOL ansi ) +{ + if (!(prop->size = size)) return ERROR_INVALID_USER_BUFFER; + if (!(prop->buffer = buffer) && (*prop->size)) return ERROR_INVALID_USER_BUFFER; + prop->type = NULL; + prop->ansi = ansi; + memcpy( &prop->key, base, sizeof(prop->key) ); + prop->key.pid = property + 1; + prop->reg_type = type; + return ERROR_SUCCESS; +} + +static LSTATUS query_named_property( HKEY hkey, const WCHAR *nameW, DEVPROPTYPE type, struct property *prop ) +{ + LSTATUS err; + + if (!prop->ansi) err = RegQueryValueExW( hkey, nameW, NULL, prop->reg_type, prop->buffer, prop->size ); + else + { + char nameA[MAX_PATH]; + if (nameW) WideCharToMultiByte( CP_ACP, 0, nameW, -1, nameA, sizeof(nameA), NULL, NULL ); + err = RegQueryValueExA( hkey, nameW ? nameA : NULL, NULL, prop->reg_type, prop->buffer, prop->size ); + } + + if (!err && !prop->buffer) err = ERROR_MORE_DATA; + if ((!err || err == ERROR_MORE_DATA) && prop->type) *prop->type = type; + if (err == ERROR_FILE_NOT_FOUND) return ERROR_NOT_FOUND; + return err; +} + +struct property_desc +{ + const DEVPROPKEY *key; + DEVPROPTYPE type; + const WCHAR *name; +}; + +static const struct property_desc class_properties[] = +{ + /* ansi-compatible CM_CRP properties */ + { &DEVPKEY_DeviceClass_UpperFilters, DEVPROP_TYPE_STRING, L"UpperFilters" }, + { &DEVPKEY_DeviceClass_LowerFilters, DEVPROP_TYPE_STRING, L"LowerFilters" }, + { &DEVPKEY_DeviceClass_Security, DEVPROP_TYPE_SECURITY_DESCRIPTOR, L"Security" }, + { &DEVPKEY_DeviceClass_SecuritySDS, DEVPROP_TYPE_SECURITY_DESCRIPTOR_STRING, L"SecuritySDS" }, + { &DEVPKEY_DeviceClass_DevType, DEVPROP_TYPE_UINT32, L"DevType" }, + { &DEVPKEY_DeviceClass_Exclusive, DEVPROP_TYPE_BOOLEAN, L"Exclusive" }, + { &DEVPKEY_DeviceClass_Characteristics, DEVPROP_TYPE_INT32, L"Characteristics" }, +}; + +static LSTATUS query_class_property( HKEY hkey, struct property *prop ) +{ + for (UINT i = 0; i < ARRAY_SIZE(class_properties); i++) + { + const struct property_desc *desc = class_properties + i; + if (memcmp( desc->key, &prop->key, sizeof(prop->key) )) continue; + return query_named_property( hkey, desc->name, desc->type, prop ); + } + + return ERROR_UNKNOWN_PROPERTY; +} + +static LSTATUS get_class_property( const GUID *class, struct property *prop ) +{ + WCHAR path[39]; + LSTATUS err; + HKEY hkey; + + guid_string( class, path, ARRAY_SIZE(path) ); + if (!(err = open_class_key( HKEY_LOCAL_MACHINE, path, KEY_QUERY_VALUE, TRUE, &hkey ))) + { + err = query_class_property( hkey, prop ); + RegCloseKey( hkey ); + } + + if (err && err != ERROR_MORE_DATA) *prop->size = 0; + return err; +} + struct device_interface { GUID class_guid; @@ -131,9 +219,13 @@ static CONFIGRET map_error( LSTATUS err ) { switch (err) { + case ERROR_INVALID_USER_BUFFER: return CR_INVALID_POINTER; case ERROR_FILE_NOT_FOUND: return CR_NO_SUCH_REGISTRY_KEY; + case ERROR_MORE_DATA: return CR_BUFFER_SMALL; case ERROR_NO_MORE_ITEMS: return CR_NO_SUCH_VALUE; + case ERROR_NOT_FOUND: return CR_NO_SUCH_VALUE; case ERROR_SUCCESS: return CR_SUCCESS; + case ERROR_UNKNOWN_PROPERTY: return CR_INVALID_PROPERTY; default: WARN( "unmapped error %lu\n", err ); return CR_FAILURE; } } @@ -365,6 +457,42 @@ CONFIGRET WINAPI CM_Open_Class_KeyA( GUID *class, const char *name, REGSAM acces return CM_Open_Class_Key_ExA( class, name, access, disposition, hkey, flags, NULL ); } +/*********************************************************************** + * CM_Get_Class_Registry_PropertyW (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Get_Class_Registry_PropertyW( GUID *class, ULONG property, ULONG *type, void *buffer, ULONG *len, ULONG flags, HMACHINE machine ) +{ + struct property prop; + LSTATUS err; + + TRACE( "class %s, property %#lx, type %p, buffer %p, len %p, flags %#lx, machine %p\n", debugstr_guid(class), property, type, buffer, len, 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 ((err = init_registry_property( &prop, &DEVPKEY_DeviceClass_UpperFilters, property, type, buffer, len, FALSE ))) return map_error( err ); + + return map_error( get_class_property( class, &prop ) ); +} + +/*********************************************************************** + * CM_Get_Class_Registry_PropertyA (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Get_Class_Registry_PropertyA( GUID *class, ULONG property, ULONG *type, void *buffer, ULONG *len, ULONG flags, HMACHINE machine ) +{ + struct property prop; + LSTATUS err; + + TRACE( "class %s, property %#lx, type %p, buffer %p, len %p, flags %#lx, machine %p\n", debugstr_guid(class), property, type, buffer, len, 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 ((err = init_registry_property( &prop, &DEVPKEY_DeviceClass_UpperFilters, property, type, buffer, len, TRUE ))) return map_error( err ); + + return map_error( get_class_property( class, &prop ) ); +} + /*********************************************************************** * CM_Open_Device_Interface_Key_ExW (cfgmgr32.@) */ diff --git a/dlls/cfgmgr32/cfgmgr32.spec b/dlls/cfgmgr32/cfgmgr32.spec index 0695e73a685..ae361201e3f 100644 --- a/dlls/cfgmgr32/cfgmgr32.spec +++ b/dlls/cfgmgr32/cfgmgr32.spec @@ -76,8 +76,8 @@ @ stub CM_Get_Class_Property_ExW @ 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_Registry_PropertyA(ptr long ptr ptr long long ptr) setupapi.CM_Get_Class_Registry_PropertyA -@ stdcall CM_Get_Class_Registry_PropertyW(ptr long ptr ptr long long ptr) setupapi.CM_Get_Class_Registry_PropertyW +@ 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 @ stub CM_Get_Depth_Ex @ stub CM_Get_DevNode_Custom_PropertyA diff --git a/dlls/cfgmgr32/tests/cfgmgr32.c b/dlls/cfgmgr32/tests/cfgmgr32.c index 4bc26755ad3..41292ffa822 100644 --- a/dlls/cfgmgr32/tests/cfgmgr32.c +++ b/dlls/cfgmgr32/tests/cfgmgr32.c @@ -62,6 +62,12 @@ static const char *debugstr_ok( const char *cond ) const WCHAR *v = (r); \ ok( !wcscmp( v, (e) ), "%s %s\n", debugstr_ok(#r), debugstr_w(v) ); \ } while (0) +#define ok_str( e, r ) \ + do \ + { \ + const char *v = (r); \ + ok( !strcmp( v, (e) ), "%s %s\n", debugstr_ok(#r), debugstr_a(v) ); \ + } while (0) #define ok_ex( r, op, e, t, f, ... ) \ do \ { \ @@ -2121,6 +2127,147 @@ static void test_CM_Open_Class_Key(void) ok_x4( ret, ==, ERROR_SUCCESS ); } +static void test_CM_Get_Class_Registry_Property(void) +{ + GUID guid = GUID_DEVCLASS_DISPLAY; + WCHAR buffer[MAX_PATH]; + char bufferA[MAX_PATH]; + DWORD type, len; + CONFIGRET ret; + + ret = CM_Get_Class_Registry_PropertyW( NULL, CM_CRP_DEVTYPE, &type, buffer, &len, 0, NULL ); + ok_x4( ret, ==, CR_INVALID_POINTER ); + ret = CM_Get_Class_Registry_PropertyW( &guid, CM_CRP_DEVTYPE, NULL, NULL, NULL, 0, NULL ); + ok_x4( ret, ==, CR_INVALID_POINTER ); + ret = CM_Get_Class_Registry_PropertyW( NULL, CM_CRP_DEVTYPE, &type, buffer, &len, 0, NULL ); + ok_x4( ret, ==, CR_INVALID_POINTER ); + ret = CM_Get_Class_Registry_PropertyW( &guid, CM_CRP_DEVTYPE, &type, buffer, NULL, 0, NULL ); + ok_x4( ret, ==, CR_INVALID_POINTER ); + len = 1; + ret = CM_Get_Class_Registry_PropertyW( &guid, CM_CRP_DEVTYPE, &type, NULL, &len, 0, NULL ); + ok_x4( ret, ==, CR_INVALID_POINTER ); + + len = 0; + ret = CM_Get_Class_Registry_PropertyW( &guid, CM_CRP_DEVTYPE, &type, NULL, &len, 0, NULL ); + todo_wine ok_x4( ret, ==, CR_BUFFER_SMALL ); + todo_wine ok_x4( len, ==, 4 ); + len = 1; + ret = CM_Get_Class_Registry_PropertyW( &guid, CM_CRP_DEVTYPE, &type, buffer, &len, 0, NULL ); + todo_wine ok_x4( ret, ==, CR_BUFFER_SMALL ); + todo_wine ok_x4( len, ==, 4 ); + + len = sizeof(buffer); + memset( &guid, 0xcd, sizeof(guid) ); + ret = CM_Get_Class_Registry_PropertyW( &guid, CM_CRP_DEVTYPE, &type, buffer, &len, 0, NULL ); + ok_x4( ret, ==, CR_NO_SUCH_REGISTRY_KEY ); + ok_x4( len, ==, 0 ); + guid = GUID_DEVCLASS_DISPLAY; + + + len = sizeof(buffer); + ret = CM_Get_Class_Registry_PropertyW( &guid, 0, &type, buffer, &len, 0, NULL ); + ok_x4( ret, ==, CR_INVALID_PROPERTY ); + + len = sizeof(buffer); + ret = CM_Get_Class_Registry_PropertyW( &guid, CM_CRP_UPPERFILTERS, &type, buffer, &len, 0, NULL ); + ok_x4( ret, ==, CR_NO_SUCH_VALUE ); + ok_x4( len, ==, 0 ); + + len = sizeof(buffer); + ret = CM_Get_Class_Registry_PropertyW( &guid, CM_CRP_LOWERFILTERS, &type, buffer, &len, 0, NULL ); + ok_x4( ret, ==, CR_NO_SUCH_VALUE ); + ok_x4( len, ==, 0 ); + + type = 0xdeadbeef; + len = sizeof(buffer); + memset( buffer, 0xcd, sizeof(buffer) ); + ret = CM_Get_Class_Registry_PropertyW( &guid, CM_CRP_SECURITY, &type, buffer, &len, 0, NULL ); + todo_wine ok_x4( ret, ==, CR_SUCCESS ); + todo_wine ok_x4( type, ==, REG_BINARY ); + todo_wine ok_x4( len, ==, 0x30 ); + + ret = CM_Get_Class_Registry_PropertyW( &guid, CM_CRP_SECURITY, NULL, buffer, &len, 0, NULL ); + todo_wine ok_x4( ret, ==, CR_SUCCESS ); + + type = 0xdeadbeef; + len = sizeof(buffer); + memset( buffer, 0xcd, sizeof(buffer) ); + ret = CM_Get_Class_Registry_PropertyW( &guid, CM_CRP_SECURITY_SDS, &type, buffer, &len, 0, NULL ); + todo_wine ok_x4( ret, ==, CR_SUCCESS ); + todo_wine ok_x4( type, ==, REG_SZ ); + todo_wine ok_x4( len, ==, 0x20 ); + todo_wine ok_wcs( L"D:P(A;;GA;;;SY)", buffer ); + + + type = 0xdeadbeef; + len = sizeof(bufferA); + memset( bufferA, 0xcd, sizeof(bufferA) ); + ret = CM_Get_Class_Registry_PropertyA( &guid, CM_CRP_SECURITY, &type, bufferA, &len, 0, NULL ); + todo_wine ok_x4( ret, ==, CR_SUCCESS ); + todo_wine ok_x4( type, ==, REG_BINARY ); + todo_wine ok_x4( len, ==, 0x30 ); + + type = 0xdeadbeef; + len = sizeof(bufferA); + memset( bufferA, 0xcd, sizeof(bufferA) ); + ret = CM_Get_Class_Registry_PropertyA( &guid, CM_CRP_SECURITY_SDS, &type, bufferA, &len, 0, NULL ); + todo_wine ok_x4( ret, ==, CR_SUCCESS ); + todo_wine ok_x4( type, ==, REG_SZ ); + todo_wine ok_x4( len, ==, 0x10 ); + todo_wine ok_str( "D:P(A;;GA;;;SY)", bufferA ); + + + type = 0xdeadbeef; + len = sizeof(buffer); + memset( buffer, 0xcd, sizeof(buffer) ); + ret = CM_Get_Class_Registry_PropertyW( &guid, CM_CRP_DEVTYPE, &type, buffer, &len, 0, NULL ); + todo_wine ok_x4( ret, ==, CR_SUCCESS ); + todo_wine ok_x4( type, ==, REG_DWORD ); + todo_wine ok_x4( len, ==, 4 ); + todo_wine ok_x4( *(DWORD *)buffer, ==, 0x23 /* FILE_DEVICE_VIDEO */ ); + + len = sizeof(buffer); + ret = CM_Get_Class_Registry_PropertyW( &guid, CM_CRP_EXCLUSIVE, &type, buffer, &len, 0, NULL ); + ok_x4( ret, ==, CR_NO_SUCH_VALUE ); + ok_x4( len, ==, 0 ); + + type = 0xdeadbeef; + len = sizeof(buffer); + memset( buffer, 0xcd, sizeof(buffer) ); + ret = CM_Get_Class_Registry_PropertyW( &guid, CM_CRP_CHARACTERISTICS, &type, buffer, &len, 0, NULL ); + todo_wine ok_x4( ret, ==, CR_SUCCESS ); + todo_wine ok_x4( type, ==, REG_DWORD ); + todo_wine ok_x4( len, ==, 4 ); + todo_wine ok_x4( *(DWORD *)buffer, ==, 0x100 ); + + + guid = GUID_DEVCLASS_HIDCLASS; + len = sizeof(buffer); + ret = CM_Get_Class_Registry_PropertyW( &guid, 0, &type, buffer, &len, 0, NULL ); + ok_x4( ret, ==, CR_INVALID_PROPERTY ); + len = sizeof(buffer); + ret = CM_Get_Class_Registry_PropertyW( &guid, CM_CRP_UPPERFILTERS, &type, buffer, &len, 0, NULL ); + ok_x4( ret, ==, CR_NO_SUCH_VALUE ); + len = sizeof(buffer); + ret = CM_Get_Class_Registry_PropertyW( &guid, CM_CRP_LOWERFILTERS, &type, buffer, &len, 0, NULL ); + ok_x4( ret, ==, CR_NO_SUCH_VALUE ); + len = sizeof(buffer); + ret = CM_Get_Class_Registry_PropertyW( &guid, CM_CRP_SECURITY, &type, buffer, &len, 0, NULL ); + todo_wine ok_x4( ret, ==, CR_SUCCESS ); + len = sizeof(buffer); + ret = CM_Get_Class_Registry_PropertyW( &guid, CM_CRP_SECURITY_SDS, &type, buffer, &len, 0, NULL ); + todo_wine ok_x4( ret, ==, CR_SUCCESS ); + len = sizeof(buffer); + ret = CM_Get_Class_Registry_PropertyW( &guid, CM_CRP_DEVTYPE, &type, buffer, &len, 0, NULL ); + ok_x4( ret, ==, CR_NO_SUCH_VALUE ); + len = sizeof(buffer); + ret = CM_Get_Class_Registry_PropertyW( &guid, CM_CRP_EXCLUSIVE, &type, buffer, &len, 0, NULL ); + ok_x4( ret, ==, CR_NO_SUCH_VALUE ); + len = sizeof(buffer); + ret = CM_Get_Class_Registry_PropertyW( &guid, CM_CRP_CHARACTERISTICS, &type, buffer, &len, 0, NULL ); + ok_x4( ret, ==, CR_NO_SUCH_VALUE ); +} + static void test_CM_Open_Device_Interface_Key(void) { WCHAR iface[4096], name[MAX_PATH], expect[MAX_PATH], buffer[39], *refstr; @@ -2177,6 +2324,7 @@ START_TEST(cfgmgr32) test_CM_Enumerate_Enumerators(); test_CM_Get_Class_Key_Name(); test_CM_Open_Class_Key(); + test_CM_Get_Class_Registry_Property(); 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/10110
From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/setupapi/setupapi.spec | 4 ++-- dlls/setupapi/stubs.c | 20 -------------------- 2 files changed, 2 insertions(+), 22 deletions(-) diff --git a/dlls/setupapi/setupapi.spec b/dlls/setupapi/setupapi.spec index 868fa2b042a..a690d6538b3 100644 --- a/dlls/setupapi/setupapi.spec +++ b/dlls/setupapi/setupapi.spec @@ -63,8 +63,8 @@ @ stub CM_Get_Class_NameW @ stub CM_Get_Class_Name_ExA @ stub CM_Get_Class_Name_ExW -@ 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) +@ stdcall CM_Get_Class_Registry_PropertyA(ptr long ptr ptr long long ptr) cfgmgr32.CM_Get_Class_Registry_PropertyA +@ stdcall CM_Get_Class_Registry_PropertyW(ptr long ptr ptr long long ptr) cfgmgr32.CM_Get_Class_Registry_PropertyW @ stub CM_Get_Depth @ stub CM_Get_Depth_Ex @ stdcall CM_Get_DevNode_PropertyW(long ptr ptr ptr ptr long) diff --git a/dlls/setupapi/stubs.c b/dlls/setupapi/stubs.c index 12cf85ad5a6..3b2641f9875 100644 --- a/dlls/setupapi/stubs.c +++ b/dlls/setupapi/stubs.c @@ -344,26 +344,6 @@ CONFIGRET WINAPI CM_Get_DevNode_Status_Ex(ULONG *status, ULONG *problem, DEVINST return CR_SUCCESS; } -/*********************************************************************** - * CM_Get_Class_Registry_PropertyA (SETUPAPI.@) - */ -CONFIGRET WINAPI CM_Get_Class_Registry_PropertyA(LPGUID class, ULONG prop, PULONG regdatatype, - PVOID buf, ULONG *len, ULONG flags, HMACHINE machine) -{ - FIXME("%p %lu %p %p %p 0x%08lx %p: stub\n", class, prop, regdatatype, buf, len, flags, machine); - return CR_FAILURE; -} - -/*********************************************************************** - * CM_Get_Class_Registry_PropertyW (SETUPAPI.@) - */ -CONFIGRET WINAPI CM_Get_Class_Registry_PropertyW(LPGUID class, ULONG prop, PULONG regdatatype, - PVOID buf, ULONG *len, ULONG flags, HMACHINE machine) -{ - FIXME("%p %lu %p %p %p 0x%08lx %p: stub\n", class, prop, regdatatype, buf, len, flags, machine); - return CR_FAILURE; -} - /*********************************************************************** * CM_Get_Sibling (SETUPAPI.@) */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10110
From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/cfgmgr32/cfgmgr32.c | 85 +++++++++++++++- dlls/cfgmgr32/cfgmgr32.spec | 4 +- dlls/cfgmgr32/tests/cfgmgr32.c | 174 +++++++++++++++++++++++++++++++++ 3 files changed, 260 insertions(+), 3 deletions(-) diff --git a/dlls/cfgmgr32/cfgmgr32.c b/dlls/cfgmgr32/cfgmgr32.c index cfa1d430409..74f4c7317b2 100644 --- a/dlls/cfgmgr32/cfgmgr32.c +++ b/dlls/cfgmgr32/cfgmgr32.c @@ -39,6 +39,14 @@ static const WCHAR *guid_string( const GUID *guid, WCHAR *buffer, UINT length ) return buffer; } +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, + key->fmtid.Data1, key->fmtid.Data2, key->fmtid.Data3, key->fmtid.Data4[0], key->fmtid.Data4[1], key->fmtid.Data4[2], + key->fmtid.Data4[3], key->fmtid.Data4[4], key->fmtid.Data4[5], key->fmtid.Data4[6], key->fmtid.Data4[7], key->pid ); + return buffer; +} + static const WCHAR control_classW[] = L"System\\CurrentControlSet\\Control\\Class\\"; static const WCHAR device_classesW[] = L"System\\CurrentControlSet\\Control\\DeviceClasses\\"; static const WCHAR enum_rootW[] = L"System\\CurrentControlSet\\Enum\\"; @@ -106,6 +114,17 @@ struct property DWORD *size; }; +static LSTATUS init_property( struct property *prop, const DEVPROPKEY *key, DEVPROPTYPE *type, void *buffer, DWORD *size ) +{ + if (!key) return ERROR_INVALID_PARAMETER; + if (!(prop->type = type) || !(prop->size = size)) return ERROR_INVALID_USER_BUFFER; + if (!(prop->buffer = buffer) && (*prop->size)) return ERROR_INVALID_USER_BUFFER; + prop->ansi = FALSE; + prop->key = *key; + prop->reg_type = NULL; + return ERROR_SUCCESS; +} + static LSTATUS init_registry_property( struct property *prop, const DEVPROPKEY *base, UINT property, DWORD *type, void *buffer, DWORD *size, BOOL ansi ) { if (!(prop->size = size)) return ERROR_INVALID_USER_BUFFER; @@ -118,6 +137,22 @@ static LSTATUS init_registry_property( struct property *prop, const DEVPROPKEY * return ERROR_SUCCESS; } +static LSTATUS query_property( HKEY root, const WCHAR *prefix, DEVPROPTYPE type, struct property *prop ) +{ + WCHAR path[MAX_PATH]; + ULONG reg_type; + LSTATUS err; + + err = RegQueryValueExW( root, propkey_string( &prop->key, prefix, path, ARRAY_SIZE(path) ), + NULL, ®_type, prop->buffer, prop->size ); + if (type == DEVPROP_TYPE_EMPTY) type = reg_type & 0xffff; + + if (!err && !prop->buffer) err = ERROR_MORE_DATA; + if ((!err || err == ERROR_MORE_DATA) && prop->type) *prop->type = type; + if (err == ERROR_FILE_NOT_FOUND) return ERROR_NOT_FOUND; + return err; +} + static LSTATUS query_named_property( HKEY hkey, const WCHAR *nameW, DEVPROPTYPE type, struct property *prop ) { LSTATUS err; @@ -145,6 +180,9 @@ struct property_desc static const struct property_desc class_properties[] = { + { &DEVPKEY_DeviceClass_ClassName, DEVPROP_TYPE_STRING, L"Class" }, + { &DEVPKEY_DeviceClass_Name, DEVPROP_TYPE_STRING, L"" }, + { &DEVPKEY_NAME, DEVPROP_TYPE_STRING, L"" }, /* ansi-compatible CM_CRP properties */ { &DEVPKEY_DeviceClass_UpperFilters, DEVPROP_TYPE_STRING, L"UpperFilters" }, { &DEVPKEY_DeviceClass_LowerFilters, DEVPROP_TYPE_STRING, L"LowerFilters" }, @@ -153,6 +191,18 @@ static const struct property_desc class_properties[] = { &DEVPKEY_DeviceClass_DevType, DEVPROP_TYPE_UINT32, L"DevType" }, { &DEVPKEY_DeviceClass_Exclusive, DEVPROP_TYPE_BOOLEAN, L"Exclusive" }, { &DEVPKEY_DeviceClass_Characteristics, DEVPROP_TYPE_INT32, L"Characteristics" }, + /* unicode-only properties */ + { &DEVPKEY_DeviceClass_Icon, DEVPROP_TYPE_STRING }, + { &DEVPKEY_DeviceClass_ClassInstaller, DEVPROP_TYPE_STRING, L"Installer32" }, + { &DEVPKEY_DeviceClass_DefaultService, DEVPROP_TYPE_STRING, L"Default Service" }, + { &DEVPKEY_DeviceClass_IconPath, DEVPROP_TYPE_STRING_LIST, L"IconPath" }, + { &DEVPKEY_DeviceClass_NoDisplayClass, DEVPROP_TYPE_BOOLEAN, L"NoDisplayClass" }, + { &DEVPKEY_DeviceClass_NoInstallClass, DEVPROP_TYPE_BOOLEAN, L"NoInstallClass" }, + { &DEVPKEY_DeviceClass_NoUseClass, DEVPROP_TYPE_BOOLEAN, L"NoUseClass" }, + { &DEVPKEY_DeviceClass_PropPageProvider, DEVPROP_TYPE_STRING, L"EnumPropPages32" }, + { &DEVPKEY_DeviceClass_SilentInstall, DEVPROP_TYPE_BOOLEAN, L"SilentInstall" }, + { &DEVPKEY_DeviceClass_DHPRebalanceOptOut, DEVPROP_TYPE_BOOLEAN }, + { &DEVPKEY_DeviceClass_ClassCoInstallers, DEVPROP_TYPE_STRING_LIST }, }; static LSTATUS query_class_property( HKEY hkey, struct property *prop ) @@ -161,10 +211,17 @@ static LSTATUS query_class_property( HKEY hkey, struct property *prop ) { const struct property_desc *desc = class_properties + i; if (memcmp( desc->key, &prop->key, sizeof(prop->key) )) continue; + if (!desc->name) return query_property( hkey, L"Properties\\", desc->type, prop ); return query_named_property( hkey, desc->name, desc->type, prop ); } - return ERROR_UNKNOWN_PROPERTY; + if (!memcmp( &DEVPKEY_DeviceClass_UpperFilters, &prop->key, sizeof(prop->key.fmtid) )) + { + FIXME( "property %#lx not implemented\n", prop->key.pid - 1 ); + return ERROR_UNKNOWN_PROPERTY; + } + + return query_property( hkey, L"Properties\\", DEVPROP_TYPE_EMPTY, prop ); } static LSTATUS get_class_property( const GUID *class, struct property *prop ) @@ -219,6 +276,7 @@ static CONFIGRET map_error( LSTATUS err ) { switch (err) { + case ERROR_INVALID_PARAMETER: return CR_FAILURE; case ERROR_INVALID_USER_BUFFER: return CR_INVALID_POINTER; case ERROR_FILE_NOT_FOUND: return CR_NO_SUCH_REGISTRY_KEY; case ERROR_MORE_DATA: return CR_BUFFER_SMALL; @@ -493,6 +551,31 @@ CONFIGRET WINAPI CM_Get_Class_Registry_PropertyA( GUID *class, ULONG property, U return map_error( get_class_property( class, &prop ) ); } +/*********************************************************************** + * CM_Get_Class_Property_ExW (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Get_Class_Property_ExW( const GUID *class, const DEVPROPKEY *key, DEVPROPTYPE *type, BYTE *buffer, ULONG *size, ULONG flags, HMACHINE machine ) +{ + struct property prop; + LSTATUS err; + + TRACE( "class %s, key %s, type %p, buffer %p, size %p, flags %#lx, machine %p\n", debugstr_guid(class), debugstr_DEVPROPKEY(key), type, buffer, size, 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 ((err = init_property( &prop, key, type, buffer, size ))) return map_error( err ); + return map_error( get_class_property( class, &prop ) ); +} + +/*********************************************************************** + * CM_Get_Class_PropertyW (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Get_Class_PropertyW( const GUID *class, const DEVPROPKEY *key, DEVPROPTYPE *type, BYTE *buffer, ULONG *size, ULONG flags ) +{ + return CM_Get_Class_Property_ExW( class, key, type, buffer, size, flags, NULL ); +} + /*********************************************************************** * CM_Open_Device_Interface_Key_ExW (cfgmgr32.@) */ diff --git a/dlls/cfgmgr32/cfgmgr32.spec b/dlls/cfgmgr32/cfgmgr32.spec index ae361201e3f..99aef888aa2 100644 --- a/dlls/cfgmgr32/cfgmgr32.spec +++ b/dlls/cfgmgr32/cfgmgr32.spec @@ -72,8 +72,8 @@ @ stub CM_Get_Class_NameW @ stub CM_Get_Class_Name_ExA @ stub CM_Get_Class_Name_ExW -@ stub CM_Get_Class_PropertyW -@ stub CM_Get_Class_Property_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_Registry_PropertyA(ptr long ptr ptr long long ptr) diff --git a/dlls/cfgmgr32/tests/cfgmgr32.c b/dlls/cfgmgr32/tests/cfgmgr32.c index 41292ffa822..beba61591e6 100644 --- a/dlls/cfgmgr32/tests/cfgmgr32.c +++ b/dlls/cfgmgr32/tests/cfgmgr32.c @@ -2268,6 +2268,179 @@ static void test_CM_Get_Class_Registry_Property(void) ok_x4( ret, ==, CR_NO_SUCH_VALUE ); } +static void test_CM_Get_Class_Property(void) +{ + GUID guid = GUID_DEVCLASS_DISPLAY; + BYTE buffer[1024]; + DWORD type, len; + CONFIGRET ret; + + ret = CM_Get_Class_Property_ExW( &guid, &DEVPKEY_DeviceClass_Name, NULL, NULL, NULL, 0, NULL ); + ok_x4( ret, ==, CR_INVALID_POINTER ); + ret = CM_Get_Class_Property_ExW( NULL, &DEVPKEY_DeviceClass_Name, &type, buffer, &len, 0, NULL ); + ok_x4( ret, ==, CR_INVALID_POINTER ); + ret = CM_Get_Class_Property_ExW( &guid, NULL, &type, buffer, &len, 0, NULL ); + ok_x4( ret, ==, CR_FAILURE ); + ret = CM_Get_Class_Property_ExW( &guid, &DEVPKEY_DeviceClass_Name, &type, buffer, NULL, 0, NULL ); + ok_x4( ret, ==, CR_INVALID_POINTER ); + len = 1; + ret = CM_Get_Class_Property_ExW( &guid, &DEVPKEY_DeviceClass_Name, &type, NULL, &len, 0, NULL ); + ok_x4( ret, ==, CR_INVALID_POINTER ); + ret = CM_Get_Class_Property_ExW( &guid, &DEVPKEY_DeviceClass_Name, NULL, buffer, &len, 0, NULL ); + ok_x4( ret, ==, CR_INVALID_POINTER ); + + len = 0; + ret = CM_Get_Class_Property_ExW( &guid, &DEVPKEY_DeviceClass_Name, &type, NULL, &len, 0, NULL ); + ok_x4( ret, ==, CR_BUFFER_SMALL ); + ok_x4( len, ==, 0x22 ); + len = 1; + ret = CM_Get_Class_Property_ExW( &guid, &DEVPKEY_DeviceClass_Name, &type, buffer, &len, 0, NULL ); + ok_x4( ret, ==, CR_BUFFER_SMALL ); + ok_x4( len, ==, 0x22 ); + + len = sizeof(buffer); + memset( &guid, 0xcd, sizeof(guid) ); + ret = CM_Get_Class_Property_ExW( &guid, &DEVPKEY_DeviceClass_Name, &type, buffer, &len, 0, NULL ); + ok_x4( ret, ==, CR_NO_SUCH_REGISTRY_KEY ); + ok_x4( len, ==, 0 ); + + + guid = GUID_DEVCLASS_DISPLAY; + len = sizeof(buffer); + ret = CM_Get_Class_Property_ExW( &guid, &DEVPKEY_DeviceInterface_Enabled, &type, buffer, &len, 0, NULL ); + ok_x4( ret, ==, CR_NO_SUCH_VALUE ); + + type = 0xdeadbeef; + len = sizeof(buffer); + memset( buffer, 0xcd, sizeof(buffer) ); + ret = CM_Get_Class_Property_ExW( &guid, &DEVPKEY_DeviceClass_Name, &type, buffer, &len, 0, NULL ); + ok_x4( ret, ==, CR_SUCCESS ); + ok_x4( type, ==, DEVPROP_TYPE_STRING ); + ok_x4( len, ==, 0x22 ); + ok_wcs( L"Display adapters", (WCHAR *)buffer ); + + type = 0xdeadbeef; + len = sizeof(buffer); + memset( buffer, 0xcd, sizeof(buffer) ); + ret = CM_Get_Class_Property_ExW( &guid, &DEVPKEY_NAME, &type, buffer, &len, 0, NULL ); + ok_x4( ret, ==, CR_SUCCESS ); + ok_x4( type, ==, DEVPROP_TYPE_STRING ); + ok_x4( len, ==, 0x22 ); + ok_wcs( L"Display adapters", (WCHAR *)buffer ); + + type = 0xdeadbeef; + len = sizeof(buffer); + memset( buffer, 0xcd, sizeof(buffer) ); + ret = CM_Get_Class_Property_ExW( &guid, &DEVPKEY_DeviceClass_ClassName, &type, buffer, &len, 0, NULL ); + ok_x4( ret, ==, CR_SUCCESS ); + ok_x4( type, ==, DEVPROP_TYPE_STRING ); + ok_x4( len, ==, 0x10 ); + ok_wcs( L"Display", (WCHAR *)buffer ); + + len = sizeof(buffer); + ret = CM_Get_Class_Property_ExW( &guid, &DEVPKEY_DeviceClass_UpperFilters, &type, buffer, &len, 0, NULL ); + ok_x4( ret, ==, CR_NO_SUCH_VALUE ); + ok_x4( len, ==, 0 ); + + len = sizeof(buffer); + ret = CM_Get_Class_Property_ExW( &guid, &DEVPKEY_DeviceClass_LowerFilters, &type, buffer, &len, 0, NULL ); + ok_x4( ret, ==, CR_NO_SUCH_VALUE ); + ok_x4( len, ==, 0 ); + + type = 0xdeadbeef; + len = sizeof(buffer); + memset( buffer, 0xcd, sizeof(buffer) ); + ret = CM_Get_Class_Property_ExW( &guid, &DEVPKEY_DeviceClass_Security, &type, buffer, &len, 0, NULL ); + todo_wine ok_x4( ret, ==, CR_SUCCESS ); + todo_wine ok_x4( type, ==, DEVPROP_TYPE_SECURITY_DESCRIPTOR ); + todo_wine ok_x4( len, ==, 0x30 ); + + type = 0xdeadbeef; + len = sizeof(buffer); + memset( buffer, 0xcd, sizeof(buffer) ); + ret = CM_Get_Class_Property_ExW( &guid, &DEVPKEY_DeviceClass_SecuritySDS, &type, buffer, &len, 0, NULL ); + todo_wine ok_x4( ret, ==, CR_SUCCESS ); + todo_wine ok_x4( type, ==, DEVPROP_TYPE_SECURITY_DESCRIPTOR_STRING ); + todo_wine ok_x4( len, ==, 0x20 ); + todo_wine ok_wcs( L"D:P(A;;GA;;;SY)", (WCHAR *)buffer ); + + + type = 0xdeadbeef; + len = sizeof(buffer); + memset( buffer, 0xcd, sizeof(buffer) ); + ret = CM_Get_Class_Property_ExW( &guid, &DEVPKEY_DeviceClass_DevType, &type, buffer, &len, 0, NULL ); + todo_wine ok_x4( ret, ==, CR_SUCCESS ); + todo_wine ok_x4( type, ==, DEVPROP_TYPE_UINT32 ); + todo_wine ok_x4( len, ==, 4 ); + todo_wine ok_x4( *(DWORD *)buffer, ==, 0x23 /* FILE_DEVICE_VIDEO */ ); + + len = sizeof(buffer); + ret = CM_Get_Class_Property_ExW( &guid, &DEVPKEY_DeviceClass_Exclusive, &type, buffer, &len, 0, NULL ); + ok_x4( ret, ==, CR_NO_SUCH_VALUE ); + ok_x4( len, ==, 0 ); + + type = 0xdeadbeef; + len = sizeof(buffer); + memset( buffer, 0xcd, sizeof(buffer) ); + ret = CM_Get_Class_Property_ExW( &guid, &DEVPKEY_DeviceClass_Characteristics, &type, buffer, &len, 0, NULL ); + todo_wine ok_x4( ret, ==, CR_SUCCESS ); + todo_wine ok_x4( type, ==, DEVPROP_TYPE_UINT32 ); + todo_wine ok_x4( len, ==, 4 ); + todo_wine ok_x4( *(DWORD *)buffer, ==, 0x100 ); + + + guid = GUID_DEVCLASS_HIDCLASS; + + type = 0xdeadbeef; + len = sizeof(buffer); + memset( buffer, 0xcd, sizeof(buffer) ); + ret = CM_Get_Class_Property_ExW( &guid, &DEVPKEY_DeviceClass_Name, &type, buffer, &len, 0, NULL ); + ok_x4( ret, ==, CR_SUCCESS ); + ok_x4( type, ==, DEVPROP_TYPE_STRING ); + ok_x4( len, ==, 0x30 ); + ok_wcs( L"Human Interface Devices", (WCHAR *)buffer ); + + type = 0xdeadbeef; + len = sizeof(buffer); + memset( buffer, 0xcd, sizeof(buffer) ); + ret = CM_Get_Class_Property_ExW( &guid, &DEVPKEY_NAME, &type, buffer, &len, 0, NULL ); + ok_x4( ret, ==, CR_SUCCESS ); + ok_x4( type, ==, DEVPROP_TYPE_STRING ); + ok_x4( len, ==, 0x30 ); + ok_wcs( L"Human Interface Devices", (WCHAR *)buffer ); + + type = 0xdeadbeef; + len = sizeof(buffer); + memset( buffer, 0xcd, sizeof(buffer) ); + ret = CM_Get_Class_Property_ExW( &guid, &DEVPKEY_DeviceClass_ClassName, &type, buffer, &len, 0, NULL ); + ok_x4( ret, ==, CR_SUCCESS ); + ok_x4( type, ==, DEVPROP_TYPE_STRING ); + ok_x4( len, ==, 0x12 ); + ok_wcs( L"HIDClass", (WCHAR *)buffer ); + + len = sizeof(buffer); + ret = CM_Get_Class_Property_ExW( &guid, &DEVPKEY_DeviceClass_UpperFilters, &type, buffer, &len, 0, NULL ); + ok_x4( ret, ==, CR_NO_SUCH_VALUE ); + len = sizeof(buffer); + ret = CM_Get_Class_Property_ExW( &guid, &DEVPKEY_DeviceClass_LowerFilters, &type, buffer, &len, 0, NULL ); + ok_x4( ret, ==, CR_NO_SUCH_VALUE ); + len = sizeof(buffer); + ret = CM_Get_Class_Property_ExW( &guid, &DEVPKEY_DeviceClass_Security, &type, buffer, &len, 0, NULL ); + todo_wine ok_x4( ret, ==, CR_SUCCESS ); + len = sizeof(buffer); + ret = CM_Get_Class_Property_ExW( &guid, &DEVPKEY_DeviceClass_SecuritySDS, &type, buffer, &len, 0, NULL ); + todo_wine ok_x4( ret, ==, CR_SUCCESS ); + len = sizeof(buffer); + ret = CM_Get_Class_Property_ExW( &guid, &DEVPKEY_DeviceClass_DevType, &type, buffer, &len, 0, NULL ); + ok_x4( ret, ==, CR_NO_SUCH_VALUE ); + len = sizeof(buffer); + ret = CM_Get_Class_Property_ExW( &guid, &DEVPKEY_DeviceClass_Exclusive, &type, buffer, &len, 0, NULL ); + ok_x4( ret, ==, CR_NO_SUCH_VALUE ); + len = sizeof(buffer); + ret = CM_Get_Class_Property_ExW( &guid, &DEVPKEY_DeviceClass_Characteristics, &type, buffer, &len, 0, NULL ); + ok_x4( ret, ==, CR_NO_SUCH_VALUE ); +} + static void test_CM_Open_Device_Interface_Key(void) { WCHAR iface[4096], name[MAX_PATH], expect[MAX_PATH], buffer[39], *refstr; @@ -2325,6 +2498,7 @@ START_TEST(cfgmgr32) test_CM_Get_Class_Key_Name(); test_CM_Open_Class_Key(); test_CM_Get_Class_Registry_Property(); + test_CM_Get_Class_Property(); 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/10110
participants (2)
-
Rémi Bernon -
Rémi Bernon (@rbernon)