From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/cfgmgr32/cfgmgr32.c | 113 ++++++++++++++++++++++----------- dlls/cfgmgr32/cfgmgr32.spec | 2 +- dlls/cfgmgr32/tests/cfgmgr32.c | 96 +++++++++++++++++++++++++++- 3 files changed, 172 insertions(+), 39 deletions(-) diff --git a/dlls/cfgmgr32/cfgmgr32.c b/dlls/cfgmgr32/cfgmgr32.c index 811f4304017..db9b65e9acb 100644 --- a/dlls/cfgmgr32/cfgmgr32.c +++ b/dlls/cfgmgr32/cfgmgr32.c @@ -187,6 +187,20 @@ static LSTATUS query_named_property( HKEY hkey, const WCHAR *nameW, DEVPROPTYPE return err; } +static LSTATUS return_property( struct property *prop, DEVPROPTYPE type, const void *buffer, UINT size ) +{ + LSTATUS err = *prop->size >= size ? ERROR_SUCCESS : ERROR_MORE_DATA; + if (!err && prop->buffer) memcpy( prop->buffer, buffer, size ); + *prop->size = size; + *prop->type = type; + return err; +} + +static LSTATUS return_property_bool( struct property *prop, DEVPROP_BOOLEAN value ) +{ + return return_property( prop, DEVPROP_TYPE_BOOLEAN, &value, sizeof(value) ); +} + typedef LSTATUS (*enum_objects_cb)( HKEY hkey, const void *object, const WCHAR *path, UINT path_len, void *context ); static LSTATUS enum_objects_size( HKEY hkey, const void *object, const WCHAR *path, UINT path_len, void *context ) @@ -418,6 +432,50 @@ static LSTATUS enum_device_interface_list( GUID *class, DEVINSTID_W instance_id, return err; } +static const struct property_desc device_interface_properties[] = +{ + { &DEVPKEY_Device_ContainerId, DEVPROP_TYPE_GUID }, + { &DEVPKEY_DeviceInterface_FriendlyName, DEVPROP_TYPE_STRING, L"FriendlyName" }, +}; + +static LSTATUS query_device_interface_property( HKEY hkey, const struct device_interface *iface, struct property *prop ) +{ + WCHAR prefix[MAX_PATH]; + + if (!memcmp( &DEVPKEY_DeviceInterface_Enabled, &prop->key, sizeof(prop->key) )) + return return_property_bool( prop, device_interface_enabled( hkey, iface ) ); + if (!memcmp( &DEVPKEY_Device_InstanceId, &prop->key, sizeof(prop->key) )) + return query_named_property( hkey, L"DeviceInstance", DEVPROP_TYPE_STRING, prop ); + if (!memcmp( &DEVPKEY_DeviceInterface_ClassGuid, &prop->key, sizeof(prop->key) )) + return return_property( prop, DEVPROP_TYPE_GUID, &iface->class_guid, sizeof(iface->class_guid) ); + + swprintf( prefix, ARRAY_SIZE(prefix), L"%s\\Properties\\", iface->refstr ); + for (UINT i = 0; i < ARRAY_SIZE(device_interface_properties); i++) + { + const struct property_desc *desc = device_interface_properties + i; + if (memcmp( desc->key, &prop->key, sizeof(prop->key) )) continue; + if (!desc->name) return query_property( hkey, prefix, desc->type, prop ); + return query_named_property( hkey, desc->name, desc->type, prop ); + } + + return query_property( hkey, prefix, DEVPROP_TYPE_EMPTY, prop ); +} + +static LSTATUS get_device_interface_property( const struct device_interface *iface, struct property *prop ) +{ + LSTATUS err; + HKEY hkey; + + if (!(err = open_device_interface_key( iface, KEY_QUERY_VALUE, TRUE, &hkey ))) + { + err = query_device_interface_property( hkey, iface, prop ); + RegCloseKey( hkey ); + } + + if (err && err != ERROR_MORE_DATA) *prop->size = 0; + return err; +} + static CONFIGRET map_error( LSTATUS err ) { switch (err) @@ -909,47 +967,30 @@ CONFIGRET WINAPI CM_Open_Device_Interface_KeyA( const char *iface, REGSAM access } /*********************************************************************** - * CM_Get_Device_Interface_PropertyW (cfgmgr32.@) + * CM_Get_Device_Interface_Property_ExW (cfgmgr32.@) */ -CONFIGRET WINAPI CM_Get_Device_Interface_PropertyW( LPCWSTR device_interface, const DEVPROPKEY *property_key, - DEVPROPTYPE *property_type, BYTE *property_buffer, - ULONG *property_buffer_size, ULONG flags ) +CONFIGRET WINAPI CM_Get_Device_Interface_Property_ExW( const WCHAR *name, const DEVPROPKEY *key, DEVPROPTYPE *type, + BYTE *buffer, ULONG *size, ULONG flags, HMACHINE machine ) { - SP_DEVICE_INTERFACE_DATA iface = {sizeof(iface)}; - HDEVINFO set; - DWORD err; - BOOL ret; + struct device_interface iface; + struct property prop; + LSTATUS err; - TRACE( "%s %p %p %p %p %ld.\n", debugstr_w(device_interface), property_key, property_type, property_buffer, - property_buffer_size, flags); + TRACE( "name %s, key %p, type %p, buffer %p, size %p, flags %#lx\n", debugstr_w(name), key, type, buffer, size, flags); + if (machine) FIXME( "machine %p not implemented!\n", machine ); - if (!property_key) return CR_FAILURE; - if (!device_interface || !property_type || !property_buffer_size) return CR_INVALID_POINTER; - if (*property_buffer_size && !property_buffer) return CR_INVALID_POINTER; + if (!name) return CR_INVALID_POINTER; + if (init_device_interface( &iface, name )) return CR_NO_SUCH_DEVICE_INTERFACE; + if ((err = init_property( &prop, key, type, buffer, size ))) return map_error( err ); if (flags) return CR_INVALID_FLAG; - set = SetupDiCreateDeviceInfoListExW( NULL, NULL, NULL, NULL ); - if (set == INVALID_HANDLE_VALUE) return CR_OUT_OF_MEMORY; - if (!SetupDiOpenDeviceInterfaceW( set, device_interface, 0, &iface )) - { - SetupDiDestroyDeviceInfoList( set ); - TRACE( "No interface %s, err %lu.\n", debugstr_w( device_interface ), GetLastError()); - return CR_NO_SUCH_DEVICE_INTERFACE; - } + return map_error( get_device_interface_property( &iface, &prop ) ); +} - ret = SetupDiGetDeviceInterfacePropertyW( set, &iface, property_key, property_type, property_buffer, - *property_buffer_size, property_buffer_size, 0 ); - err = ret ? 0 : GetLastError(); - SetupDiDestroyDeviceInfoList( set ); - switch (err) - { - case ERROR_SUCCESS: - return CR_SUCCESS; - case ERROR_INSUFFICIENT_BUFFER: - return CR_BUFFER_SMALL; - case ERROR_NOT_FOUND: - return CR_NO_SUCH_VALUE; - default: - return CR_FAILURE; - } +/*********************************************************************** + * CM_Get_Device_Interface_PropertyW (cfgmgr32.@) + */ +CONFIGRET WINAPI CM_Get_Device_Interface_PropertyW( const WCHAR *iface, const DEVPROPKEY *key, DEVPROPTYPE *type, BYTE *buffer, ULONG *size, ULONG flags ) +{ + return CM_Get_Device_Interface_Property_ExW( iface, key, type, buffer, size, flags, NULL ); } diff --git a/dlls/cfgmgr32/cfgmgr32.spec b/dlls/cfgmgr32/cfgmgr32.spec index 580f45e0ba4..e2d4c029a01 100644 --- a/dlls/cfgmgr32/cfgmgr32.spec +++ b/dlls/cfgmgr32/cfgmgr32.spec @@ -121,7 +121,7 @@ @ stdcall CM_Get_Device_Interface_List_Size_ExA(ptr ptr str long ptr) @ stdcall CM_Get_Device_Interface_List_Size_ExW(ptr ptr wstr long ptr) @ stdcall CM_Get_Device_Interface_PropertyW(wstr ptr ptr ptr ptr long) -@ stub CM_Get_Device_Interface_Property_ExW +@ stdcall CM_Get_Device_Interface_Property_ExW(wstr ptr ptr ptr ptr long ptr) @ stub CM_Get_Device_Interface_Property_KeysW @ stub CM_Get_Device_Interface_Property_Keys_ExW @ stub CM_Get_First_Log_Conf diff --git a/dlls/cfgmgr32/tests/cfgmgr32.c b/dlls/cfgmgr32/tests/cfgmgr32.c index 90d9132b1bb..1ea1c715331 100644 --- a/dlls/cfgmgr32/tests/cfgmgr32.c +++ b/dlls/cfgmgr32/tests/cfgmgr32.c @@ -471,7 +471,7 @@ static void check_device_path_casing(const WCHAR *original_path) free(path); } -static void test_CM_Get_Device_Interface_PropertyW(void) +static void test_CM_Get_Device_Interface_Property_setupapi(void) { BYTE iface_detail_buffer[sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) + 256 * sizeof(WCHAR)]; SP_DEVICE_INTERFACE_DATA iface = {sizeof(iface)}; @@ -607,6 +607,97 @@ static void test_CM_Get_Device_Interface_PropertyW(void) ok(ret == CR_NO_SUCH_DEVICE_INTERFACE || broken(ret == CR_INVALID_DATA) /* w7 */, "got %#lx.\n", ret); } +static void test_CM_Get_Device_Interface_PropertyW(void) +{ + WCHAR expect[MAX_PATH]; + DEVINSTID_W iface; + BYTE buffer[4096]; + ULONG type, len; + CONFIGRET ret; + GUID guid; + + guid = GUID_DEVINTERFACE_HID; + ret = CM_Get_Device_Interface_List_SizeW( &len, &guid, NULL, CM_GET_DEVICE_INTERFACE_LIST_PRESENT ); + ok_x4( ret, ==, CR_SUCCESS ); + iface = malloc( len * sizeof(*iface) ); + ok_ptr( iface, !=, NULL ); + ret = CM_Get_Device_Interface_ListW( &guid, NULL, iface, len, CM_GET_DEVICE_INTERFACE_LIST_PRESENT ); + ok_x4( ret, ==, CR_SUCCESS ); + + len = sizeof(buffer); + ret = CM_Get_Device_Interface_PropertyW( NULL, &DEVPKEY_Device_InstanceId, &type, buffer, &len, 0 ); + ok_x4( ret, ==, CR_INVALID_POINTER ); + ok_u4( len, ==, sizeof(buffer) ); + len = sizeof(buffer); + ret = CM_Get_Device_Interface_PropertyW( L"qqq", &DEVPKEY_Device_InstanceId, &type, buffer, &len, 0 ); + ok_x4( ret, ==, CR_NO_SUCH_DEVICE_INTERFACE ); + todo_wine ok_u4( len, ==, 0 ); + len = sizeof(buffer); + ret = CM_Get_Device_Interface_PropertyW( iface, &DEVPKEY_Device_InstanceId, &type, NULL, NULL, 0 ); + ok_x4( ret, ==, CR_INVALID_POINTER ); + len = sizeof(buffer); + ret = CM_Get_Device_Interface_PropertyW( iface, &DEVPKEY_Device_InstanceId, &type, buffer, NULL, 0 ); + ok_x4( ret, ==, CR_INVALID_POINTER ); + len = sizeof(buffer); + ret = CM_Get_Device_Interface_PropertyW( iface, NULL, &type, buffer, &len, 0 ); + ok_x4( ret, ==, CR_FAILURE ); + len = sizeof(buffer); + ret = CM_Get_Device_Interface_PropertyW( iface, &DEVPKEY_Device_InstanceId, NULL, buffer, &len, 0 ); + ok_x4( ret, ==, CR_INVALID_POINTER ); + len = sizeof(buffer); + ret = CM_Get_Device_Interface_PropertyW( iface, &DEVPKEY_Device_InstanceId, &type, NULL, &len, 0 ); + ok_x4( ret, ==, CR_INVALID_POINTER ); + ok_u4( len, ==, sizeof(buffer) ); + len = 0; + ret = CM_Get_Device_Interface_PropertyW( iface, &DEVPKEY_Device_InstanceId, &type, NULL, &len, 0 ); + ok_x4( ret, ==, CR_BUFFER_SMALL ); + ok( len > sizeof(WCHAR), "got %#lx\n", len ); + + type = 0xdeadbeef; + len = sizeof(buffer); + memset( buffer, 0xcd, sizeof(buffer) ); + ret = CM_Get_Device_Interface_PropertyW( iface, &DEVPKEY_DeviceInterface_Enabled, &type, buffer, &len, 0 ); + ok_x4( ret, ==, CR_SUCCESS ); + ok_x4( type, ==, DEVPROP_TYPE_BOOLEAN ); + ok_x4( len, ==, 1 ); + ok_x4( *buffer, ==, 0xff ); + + type = 0xdeadbeef; + len = sizeof(buffer); + memset( buffer, 0xcd, sizeof(buffer) ); + ret = CM_Get_Device_Interface_PropertyW( iface, &DEVPKEY_Device_InstanceId, &type, buffer, &len, 0 ); + ok_x4( ret, ==, CR_SUCCESS ); + ok_x4( type, ==, DEVPROP_TYPE_STRING ); + ok_x4( len, ==, (wcslen( (WCHAR *)buffer ) + 1) * sizeof(WCHAR) ); + ok( !wcsncmp( (WCHAR *)buffer, L"HID\\", 4 ), "got %s\n", debugstr_w( (WCHAR *)buffer ) ); + wcscpy( expect, (WCHAR *)buffer ); + wcsupr( expect ); /* uppercase HID\\XXXX\\ */ + len = wcschr( expect + 4, '\\' ) - expect; + wcscpy( expect + len, (WCHAR *)buffer + len ); + wcslwr( wcsrchr( expect, '\\' ) ); /* lowercase instance + refstring */ + ok_wcs( expect, (WCHAR *)buffer ); + + type = 0xdeadbeef; + len = sizeof(buffer); + memset( buffer, 0xcd, sizeof(buffer) ); + ret = CM_Get_Device_Interface_PropertyW( iface, &DEVPKEY_DeviceInterface_ClassGuid, &type, buffer, &len, 0 ); + ok_x4( ret, ==, CR_SUCCESS ); + ok_x4( type, ==, DEVPROP_TYPE_GUID ); + ok_x4( len, ==, 16 ); + ok( IsEqualGUID( (GUID *)buffer, &GUID_DEVINTERFACE_HID ), "got %s\n", debugstr_guid( (GUID *)buffer ) ); + + type = 0xdeadbeef; + len = sizeof(buffer); + memset( buffer, 0xcd, sizeof(buffer) ); + ret = CM_Get_Device_Interface_PropertyW( iface, &DEVPKEY_Device_ContainerId, &type, buffer, &len, 0 ); + todo_wine ok_x4( ret, ==, CR_SUCCESS ); + todo_wine ok_x4( type, ==, DEVPROP_TYPE_GUID ); + todo_wine ok_x4( len, ==, 16 ); + + + free( iface ); +} + struct test_property { DEVPROPKEY key; @@ -2730,9 +2821,10 @@ START_TEST(cfgmgr32) test_CM_Get_Device_Interface_List_Size(); test_CM_Get_Device_Interface_List(); test_CM_Open_Device_Interface_Key(); + test_CM_Get_Device_Interface_PropertyW(); test_CM_Get_Device_ID_List(); test_CM_Register_Notification(); - test_CM_Get_Device_Interface_PropertyW(); + test_CM_Get_Device_Interface_Property_setupapi(); test_DevGetObjects(); test_DevCreateObjectQuery(); test_DevGetObjectProperties_invalid(); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10148