Commit e6dffa10 authored by shaochuan's avatar shaochuan Committed by Commit bot

Replace Setup API with PnP Configuration Manager in MidiManagerWinrt

Now retrieving driver information with PnP Configuration Manager, which is much
faster than using Setup API.
With the new approach we are now able to fetch information from the actual
device driver, instead of the software interface on top which seems to be always
provided by Microsoft.

BUG=512433,642604
R=toyoshim@chromium.org

Review-Url: https://codereview.chromium.org/2318953002
Cr-Commit-Position: refs/heads/master@{#417536}
parent 5c7a196f
...@@ -143,6 +143,11 @@ component("midi") { ...@@ -143,6 +143,11 @@ component("midi") {
"midi_manager_winrt.cc", "midi_manager_winrt.cc",
"midi_manager_winrt.h", "midi_manager_winrt.h",
] ]
# This library is included in base in static builds.
if (is_component_build) {
libs += [ "cfgmgr32.lib" ]
}
} }
if (use_alsa && use_udev) { if (use_alsa && use_udev) {
......
...@@ -16,9 +16,12 @@ struct __declspec(uuid("905a0fef-bc53-11df-8c49-001e4fc686da")) ...@@ -16,9 +16,12 @@ struct __declspec(uuid("905a0fef-bc53-11df-8c49-001e4fc686da"))
} }
} }
#include <initguid.h> // Required by <devpkey.h>
#include <cfgmgr32.h>
#include <comdef.h> #include <comdef.h>
#include <devpkey.h>
#include <robuffer.h> #include <robuffer.h>
#include <setupapi.h>
#include <windows.devices.enumeration.h> #include <windows.devices.enumeration.h>
#include <windows.devices.midi.h> #include <windows.devices.midi.h>
#include <wrl/event.h> #include <wrl/event.h>
...@@ -263,28 +266,53 @@ bool IsMicrosoftSynthesizer(IDeviceInformation* info) { ...@@ -263,28 +266,53 @@ bool IsMicrosoftSynthesizer(IDeviceInformation* info) {
return result != FALSE; return result != FALSE;
} }
class ScopedDeviceInfoListTraits { void GetDevPropString(DEVINST handle,
public: const DEVPROPKEY* devprop_key,
static HDEVINFO InvalidValue() { return INVALID_HANDLE_VALUE; } std::string* out) {
DEVPROPTYPE devprop_type;
static void Free(HDEVINFO devinfo_set) { unsigned long buffer_size = 0;
SetupDiDestroyDeviceInfoList(devinfo_set);
// Retrieve |buffer_size| and allocate buffer later for receiving data.
CONFIGRET cr = CM_Get_DevNode_Property(handle, devprop_key, &devprop_type,
nullptr, &buffer_size, 0);
if (cr != CR_BUFFER_SMALL) {
// Here we print error codes in hex instead of using PrintHr() with
// HRESULT_FROM_WIN32() and CM_MapCrToWin32Err(), since only a minor set of
// CONFIGRET values are mapped to Win32 errors. Same for following VLOG()s.
VLOG(1) << "CM_Get_DevNode_Property failed: CONFIGRET 0x" << std::hex << cr;
return;
} }
}; if (devprop_type != DEVPROP_TYPE_STRING) {
VLOG(1) << "CM_Get_DevNode_Property returns wrong data type, "
<< "expected DEVPROP_TYPE_STRING";
return;
}
std::unique_ptr<uint8_t[]> buffer(new uint8_t[buffer_size]);
using ScopedDeviceInfoList = // Receive property data.
base::ScopedGeneric<HDEVINFO, ScopedDeviceInfoListTraits>; cr = CM_Get_DevNode_Property(handle, devprop_key, &devprop_type, buffer.get(),
&buffer_size, 0);
if (cr != CR_SUCCESS)
VLOG(1) << "CM_Get_DevNode_Property failed: CONFIGRET 0x" << std::hex << cr;
else
*out = base::WideToUTF8(reinterpret_cast<base::char16*>(buffer.get()));
}
// Retrieves manufacturer (provider) and version information of underlying // Retrieves manufacturer (provider) and version information of underlying
// device driver using Setup API, given device (interface) ID provided by WinRT. // device driver through PnP Configuration Manager, given device (interface) ID
// |out_manufacturer| and |out_driver_version| won't be modified if retrieval // provided by WinRT. |out_manufacturer| and |out_driver_version| won't be
// fails. Note that SetupDiBuildDriverInfoList() would block for a few hundred // modified if retrieval fails.
// milliseconds so consider calling this function in an asynchronous manner.
// //
// Device instance ID is extracted from device (interface) ID provided by WinRT // Device instance ID is extracted from device (interface) ID provided by WinRT
// APIs, for example from the following interface ID: // APIs, for example from the following interface ID:
// \\?\SWD#MMDEVAPI#MIDII_60F39FCA.P_0002#{504be32c-ccf6-4d2c-b73f-6f8b3747e22b} // \\?\SWD#MMDEVAPI#MIDII_60F39FCA.P_0002#{504be32c-ccf6-4d2c-b73f-6f8b3747e22b}
// we extract the device instance ID: SWD\MMDEVAPI\MIDII_60F39FCA.P_0002 // we extract the device instance ID: SWD\MMDEVAPI\MIDII_60F39FCA.P_0002
//
// However the extracted device instance ID represent a "software device"
// provided by Microsoft, which is an interface on top of the hardware for each
// input/output port. Therefore we further locate its parent device, which is
// the actual hardware device, for driver information.
void GetDriverInfoFromDeviceId(const std::string& dev_id, void GetDriverInfoFromDeviceId(const std::string& dev_id,
std::string* out_manufacturer, std::string* out_manufacturer,
std::string* out_driver_version) { std::string* out_driver_version) {
...@@ -292,53 +320,25 @@ void GetDriverInfoFromDeviceId(const std::string& dev_id, ...@@ -292,53 +320,25 @@ void GetDriverInfoFromDeviceId(const std::string& dev_id,
base::UTF8ToWide(dev_id.substr(4, dev_id.size() - 43)); base::UTF8ToWide(dev_id.substr(4, dev_id.size() - 43));
base::ReplaceChars(dev_instance_id, L"#", L"\\", &dev_instance_id); base::ReplaceChars(dev_instance_id, L"#", L"\\", &dev_instance_id);
ScopedDeviceInfoList devinfo_list( DEVINST dev_instance_handle;
SetupDiCreateDeviceInfoList(nullptr, nullptr)); CONFIGRET cr = CM_Locate_DevNode(&dev_instance_handle, &dev_instance_id[0],
if (!devinfo_list.is_valid()) { CM_LOCATE_DEVNODE_NORMAL);
VLOG(1) << "SetupDiCreateDeviceInfoList failed: " if (cr != CR_SUCCESS) {
<< PrintHr(HRESULT_FROM_WIN32(GetLastError())); VLOG(1) << "CM_Locate_DevNode failed: CONFIGRET 0x" << std::hex << cr;
return; return;
} }
SP_DEVINFO_DATA devinfo_data = {0}; DEVINST parent_handle;
devinfo_data.cbSize = sizeof(SP_DEVINFO_DATA); cr = CM_Get_Parent(&parent_handle, dev_instance_handle, 0);
SP_DRVINFO_DATA drvinfo_data = {0}; if (cr != CR_SUCCESS) {
drvinfo_data.cbSize = sizeof(SP_DRVINFO_DATA); VLOG(1) << "CM_Get_Parent failed: CONFIGRET 0x" << std::hex << cr;
if (!SetupDiOpenDeviceInfo(devinfo_list.get(), dev_instance_id.c_str(),
nullptr, 0, &devinfo_data)) {
VLOG(1) << "SetupDiOpenDeviceInfo failed: "
<< PrintHr(HRESULT_FROM_WIN32(GetLastError()));
return;
}
if (!SetupDiBuildDriverInfoList(devinfo_list.get(), &devinfo_data,
SPDIT_COMPATDRIVER)) {
VLOG(1) << "SetupDiBuildDriverInfoList failed: "
<< PrintHr(HRESULT_FROM_WIN32(GetLastError()));
return; return;
} }
// Assume only one entry in driver info list. GetDevPropString(parent_handle, &DEVPKEY_Device_DriverProvider,
if (SetupDiEnumDriverInfo(devinfo_list.get(), &devinfo_data, out_manufacturer);
SPDIT_COMPATDRIVER, 0, &drvinfo_data)) { GetDevPropString(parent_handle, &DEVPKEY_Device_DriverVersion,
*out_manufacturer = base::WideToUTF8(drvinfo_data.ProviderName); out_driver_version);
std::stringstream ss;
ss << (drvinfo_data.DriverVersion >> 48) << "."
<< (drvinfo_data.DriverVersion >> 32 & 0xffff) << "."
<< (drvinfo_data.DriverVersion >> 16 & 0xffff) << "."
<< (drvinfo_data.DriverVersion & 0xffff);
*out_driver_version = ss.str();
} else {
VLOG(1) << "SetupDiEnumDriverInfo failed: "
<< PrintHr(HRESULT_FROM_WIN32(GetLastError()));
}
if (!SetupDiDestroyDriverInfoList(devinfo_list.get(), &devinfo_data,
SPDIT_COMPATDRIVER))
VLOG(1) << "SetupDiDestroyDriverInfoList failed: "
<< PrintHr(HRESULT_FROM_WIN32(GetLastError()));
} }
// Tokens with value = 0 are considered invalid (as in <wrl/event.h>). // Tokens with value = 0 are considered invalid (as in <wrl/event.h>).
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment