mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2026-01-15 08:23:17 -03:00
Merge pull request #14016 from jordan-woyak/usbutils-CfgMgr32
USBUtils: Replace GetDeviceNameUsingSetupAPI with GetDeviceNameUsingCfgMgr32
This commit is contained in:
@@ -14,29 +14,6 @@
|
||||
|
||||
namespace Common
|
||||
{
|
||||
std::wstring GetDeviceProperty(const HDEVINFO& device_info, const PSP_DEVINFO_DATA device_data,
|
||||
const DEVPROPKEY* requested_property)
|
||||
{
|
||||
DWORD required_size = 0;
|
||||
DEVPROPTYPE device_property_type;
|
||||
BOOL result;
|
||||
|
||||
result = SetupDiGetDeviceProperty(device_info, device_data, requested_property,
|
||||
&device_property_type, nullptr, 0, &required_size, 0);
|
||||
if (!result && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
||||
return std::wstring();
|
||||
|
||||
std::vector<TCHAR> unicode_buffer(required_size / sizeof(TCHAR));
|
||||
|
||||
result = SetupDiGetDeviceProperty(
|
||||
device_info, device_data, requested_property, &device_property_type,
|
||||
reinterpret_cast<PBYTE>(unicode_buffer.data()), required_size, nullptr, 0);
|
||||
if (!result)
|
||||
return std::wstring();
|
||||
|
||||
return std::wstring(unicode_buffer.data());
|
||||
}
|
||||
|
||||
std::optional<std::wstring> GetPropertyHelper(auto function, auto dev,
|
||||
const DEVPROPKEY* requested_property,
|
||||
DEVPROPTYPE expected_type)
|
||||
@@ -83,6 +60,36 @@ std::optional<std::wstring> GetDeviceInterfaceStringProperty(LPCWSTR iface,
|
||||
DEVPROP_TYPE_STRING);
|
||||
}
|
||||
|
||||
NullTerminatedStringList<WCHAR> GetDeviceInterfaceList(LPGUID iface_class_guid, DEVINSTID device_id,
|
||||
ULONG flags)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
ULONG list_size = 0;
|
||||
const auto size_result =
|
||||
CM_Get_Device_Interface_List_Size(&list_size, iface_class_guid, device_id, flags);
|
||||
if (size_result != CR_SUCCESS || list_size == 0)
|
||||
list_size = 1;
|
||||
|
||||
auto buffer = std::make_unique_for_overwrite<WCHAR[]>(list_size);
|
||||
const auto list_result =
|
||||
CM_Get_Device_Interface_List(iface_class_guid, device_id, buffer.get(), list_size, flags);
|
||||
|
||||
// "A new device can be added to the system causing the size returned to no longer be valid."
|
||||
// Microsoft recommends trying again in a loop.
|
||||
if (list_result == CR_BUFFER_SMALL)
|
||||
continue;
|
||||
|
||||
if (list_result != CR_SUCCESS)
|
||||
{
|
||||
ERROR_LOG_FMT(COMMON, "CM_Get_Device_Interface_List: {}", list_result);
|
||||
buffer[0] = 0;
|
||||
}
|
||||
|
||||
return {std::move(buffer)};
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Common
|
||||
|
||||
#endif
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
@@ -22,16 +24,53 @@
|
||||
|
||||
namespace Common
|
||||
{
|
||||
// Obtains a device property and returns it as a wide string.
|
||||
std::wstring GetDeviceProperty(const HANDLE& device_info, const PSP_DEVINFO_DATA device_data,
|
||||
const DEVPROPKEY* requested_property);
|
||||
|
||||
std::optional<std::wstring> GetDevNodeStringProperty(DEVINST device,
|
||||
const DEVPROPKEY* requested_property);
|
||||
|
||||
std::optional<std::wstring> GetDeviceInterfaceStringProperty(LPCWSTR iface,
|
||||
const DEVPROPKEY* requested_property);
|
||||
|
||||
// Allows iterating null-separated/terminated string lists returned by the Windows API.
|
||||
template <typename T>
|
||||
struct NullTerminatedStringList
|
||||
{
|
||||
class Iterator
|
||||
{
|
||||
friend NullTerminatedStringList;
|
||||
|
||||
public:
|
||||
constexpr T* operator*() { return m_ptr; }
|
||||
|
||||
constexpr Iterator& operator++()
|
||||
{
|
||||
m_ptr += std::basic_string_view(m_ptr).size() + 1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr Iterator operator++(int)
|
||||
{
|
||||
const auto result{*this};
|
||||
++*this;
|
||||
return result;
|
||||
}
|
||||
|
||||
constexpr bool operator==(std::default_sentinel_t) const { return *m_ptr == T{}; }
|
||||
|
||||
private:
|
||||
constexpr Iterator(T* ptr) : m_ptr{ptr} {}
|
||||
|
||||
T* m_ptr;
|
||||
};
|
||||
|
||||
constexpr auto begin() const { return Iterator{list.get()}; }
|
||||
constexpr auto end() const { return std::default_sentinel; }
|
||||
|
||||
std::unique_ptr<T[]> list;
|
||||
};
|
||||
|
||||
NullTerminatedStringList<WCHAR> GetDeviceInterfaceList(LPGUID iface_class_guid, DEVINSTID device_id,
|
||||
ULONG flags);
|
||||
|
||||
} // namespace Common
|
||||
|
||||
#endif
|
||||
|
||||
@@ -583,20 +583,8 @@ auto WiimoteScannerWindows::FindWiimoteHIDDevices() -> FindResults
|
||||
// Enumerate connected HID interfaces IDs.
|
||||
auto class_guid = GUID_DEVINTERFACE_HID;
|
||||
constexpr ULONG flags = CM_GET_DEVICE_INTERFACE_LIST_PRESENT;
|
||||
ULONG list_size = 0;
|
||||
CM_Get_Device_Interface_List_Size(&list_size, &class_guid, nullptr, flags);
|
||||
|
||||
const auto buffer = std::make_unique_for_overwrite<WCHAR[]>(list_size);
|
||||
const auto list_result =
|
||||
CM_Get_Device_Interface_List(&class_guid, nullptr, buffer.get(), list_size, flags);
|
||||
if (list_result != CR_SUCCESS)
|
||||
{
|
||||
ERROR_LOG_FMT(WIIMOTE, "CM_Get_Device_Interface_List: {}", list_result);
|
||||
return results;
|
||||
}
|
||||
|
||||
for (const WCHAR* hid_iface = buffer.get(); *hid_iface != L'\0';
|
||||
hid_iface += wcslen(hid_iface) + 1)
|
||||
for (auto* hid_iface : Common::GetDeviceInterfaceList(&class_guid, nullptr, flags))
|
||||
{
|
||||
// TODO: WiimoteWindows::GetId() does a redundant conversion.
|
||||
const auto hid_iface_utf8 = WStringToUTF8(hid_iface);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "Core/USBUtils.h"
|
||||
|
||||
#include <array>
|
||||
#include <charconv>
|
||||
#include <cwchar>
|
||||
#include <functional>
|
||||
@@ -21,9 +22,11 @@
|
||||
#include <libusb.h>
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
#include <SetupAPI.h>
|
||||
#include <cfgmgr32.h>
|
||||
#include <devpkey.h>
|
||||
#include <initguid.h>
|
||||
// initguid.h must be included before usbiodef.h
|
||||
#include <usbiodef.h>
|
||||
|
||||
#include "Common/StringUtil.h"
|
||||
#include "Common/WindowsDevice.h"
|
||||
@@ -119,43 +122,36 @@ static std::optional<std::string> GetDeviceNameUsingKnownDevices(u16 vid, u16 pi
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
static std::optional<std::string> GetDeviceNameUsingSetupAPI(u16 vid, u16 pid)
|
||||
static std::optional<std::string> GetDeviceNameUsingCfgMgr32(u16 vid, u16 pid)
|
||||
{
|
||||
std::optional<std::string> device_name;
|
||||
auto class_guid = GUID_DEVINTERFACE_USB_DEVICE;
|
||||
const ULONG flags = CM_GET_DEVICE_INTERFACE_LIST_PRESENT;
|
||||
const std::wstring filter = fmt::format(L"VID_{:04X}&PID_{:04X}", vid, pid);
|
||||
|
||||
HDEVINFO dev_info =
|
||||
SetupDiGetClassDevs(nullptr, nullptr, nullptr, DIGCF_PRESENT | DIGCF_ALLCLASSES);
|
||||
if (dev_info == INVALID_HANDLE_VALUE)
|
||||
return std::nullopt;
|
||||
SP_DEVINFO_DATA dev_info_data;
|
||||
dev_info_data.cbSize = sizeof(SP_DEVINFO_DATA);
|
||||
|
||||
for (DWORD i = 0; SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data); ++i)
|
||||
for (auto* iface : Common::GetDeviceInterfaceList(&class_guid, nullptr, flags))
|
||||
{
|
||||
TCHAR instance_id[MAX_DEVICE_ID_LEN];
|
||||
if (CM_Get_Device_ID(dev_info_data.DevInst, instance_id, MAX_DEVICE_ID_LEN, 0) != CR_SUCCESS)
|
||||
if (!std::basic_string_view{iface}.contains(filter))
|
||||
continue;
|
||||
|
||||
const std::wstring_view id_wstr(instance_id);
|
||||
if (id_wstr.find(filter) == std::wstring::npos)
|
||||
continue;
|
||||
auto dev_inst_id = Common::GetDeviceInterfaceStringProperty(iface, &DEVPKEY_Device_InstanceId);
|
||||
if (!dev_inst_id.has_value())
|
||||
return std::nullopt;
|
||||
|
||||
std::wstring property_value =
|
||||
Common::GetDeviceProperty(dev_info, &dev_info_data, &DEVPKEY_Device_FriendlyName);
|
||||
if (property_value.empty())
|
||||
DEVINST dev_inst{};
|
||||
if (CM_Locate_DevNode(&dev_inst, dev_inst_id->data(), CM_LOCATE_DEVNODE_NORMAL) != CR_SUCCESS)
|
||||
{
|
||||
property_value =
|
||||
Common::GetDeviceProperty(dev_info, &dev_info_data, &DEVPKEY_Device_DeviceDesc);
|
||||
ERROR_LOG_FMT(COMMON, "CM_Locate_DevNode");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (!property_value.empty())
|
||||
device_name = WStringToUTF8(property_value);
|
||||
break;
|
||||
// FYI: BusReportedDeviceDesc seems to be more of a friendly name
|
||||
// while DeviceDesc tends to be something more like "USB Input Device".
|
||||
return Common::GetDevNodeStringProperty(dev_inst, &DEVPKEY_Device_BusReportedDeviceDesc)
|
||||
.or_else(std::bind(Common::GetDevNodeStringProperty, dev_inst, &DEVPKEY_Device_DeviceDesc))
|
||||
.transform(WStringToUTF8);
|
||||
}
|
||||
|
||||
SetupDiDestroyDeviceInfoList(dev_info);
|
||||
return device_name;
|
||||
return std::nullopt;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -245,7 +241,7 @@ std::optional<std::string> GetDeviceNameFromVIDPID(u16 vid, u16 pid)
|
||||
&GetDeviceNameUsingHWDB,
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
&GetDeviceNameUsingSetupAPI,
|
||||
&GetDeviceNameUsingCfgMgr32,
|
||||
#endif
|
||||
#if defined(__LIBUSB__) && !defined(_WIN32)
|
||||
&GetDeviceNameUsingLibUSB,
|
||||
|
||||
Reference in New Issue
Block a user