| Index: device/serial/serial_device_enumerator_win.cc
|
| diff --git a/device/serial/serial_device_enumerator_win.cc b/device/serial/serial_device_enumerator_win.cc
|
| index 124c6b720466909d811e86384d65f2c616de8596..0d1e8f1831f1616929d2bb01b06888084443a0ab 100644
|
| --- a/device/serial/serial_device_enumerator_win.cc
|
| +++ b/device/serial/serial_device_enumerator_win.cc
|
| @@ -6,14 +6,75 @@
|
|
|
| #include <windows.h>
|
|
|
| +#include <ntddser.h>
|
| +#include <setupapi.h>
|
| +
|
| #include "base/memory/scoped_ptr.h"
|
| -#include "base/strings/string_util.h"
|
| -#include "base/strings/stringprintf.h"
|
| +#include "base/strings/string_number_conversions.h"
|
| #include "base/strings/utf_string_conversions.h"
|
| -#include "base/win/registry.h"
|
| +#include "third_party/re2/re2/re2.h"
|
|
|
| namespace device {
|
|
|
| +namespace {
|
| +
|
| +// Searches the specified device info for a property with the specified key,
|
| +// assigns the result to value, and returns whether the operation was
|
| +// successful.
|
| +bool GetProperty(HDEVINFO dev_info,
|
| + SP_DEVINFO_DATA dev_info_data,
|
| + const int key,
|
| + std::string* value) {
|
| + // We don't know how much space the property's value will take up, so we call
|
| + // the property retrieval function once to fetch the size of the required
|
| + // value buffer, then again once we've allocated a sufficiently large buffer.
|
| + DWORD buffer_size = 0;
|
| + SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data, key, nullptr,
|
| + nullptr, buffer_size, &buffer_size);
|
| + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
| + return false;
|
| +
|
| + scoped_ptr<wchar_t[]> buffer(new wchar_t[buffer_size]);
|
| + if (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data, key, nullptr,
|
| + reinterpret_cast<PBYTE>(buffer.get()),
|
| + buffer_size, nullptr))
|
| + return false;
|
| +
|
| + *value = base::WideToUTF8(buffer.get());
|
| + return true;
|
| +}
|
| +
|
| +// Searches for the COM port in the device's friendly name, assigns its value to
|
| +// com_port, and returns whether the operation was successful.
|
| +bool GetCOMPort(const std::string friendly_name, std::string* com_port) {
|
| + return RE2::PartialMatch(friendly_name, ".* \\((COM[0-9]+)\\)", com_port);
|
| +}
|
| +
|
| +// Searches for the display name in the device's friendly name, assigns its
|
| +// value to display_name, and returns whether the operation was successful.
|
| +bool GetDisplayName(const std::string friendly_name,
|
| + std::string* display_name) {
|
| + return RE2::PartialMatch(friendly_name, "(.*) \\(COM[0-9]+\\)", display_name);
|
| +}
|
| +
|
| +// Searches for the vendor ID in the device's hardware ID, assigns its value to
|
| +// vendor_id, and returns whether the operation was successful.
|
| +bool GetVendorID(const std::string hardware_id, uint32_t* vendor_id) {
|
| + std::string vendor_id_str;
|
| + return RE2::PartialMatch(hardware_id, "VID_([0-9]+)", &vendor_id_str) &&
|
| + base::HexStringToUInt(vendor_id_str, vendor_id);
|
| +}
|
| +
|
| +// Searches for the product ID in the device's product ID, assigns its value to
|
| +// product_id, and returns whether the operation was successful.
|
| +bool GetProductID(const std::string hardware_id, uint32_t* product_id) {
|
| + std::string product_id_str;
|
| + return RE2::PartialMatch(hardware_id, "PID_([0-9]+)", &product_id_str) &&
|
| + base::HexStringToUInt(product_id_str, product_id);
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| // static
|
| scoped_ptr<SerialDeviceEnumerator> SerialDeviceEnumerator::Create() {
|
| return scoped_ptr<SerialDeviceEnumerator>(new SerialDeviceEnumeratorWin());
|
| @@ -23,18 +84,53 @@ SerialDeviceEnumeratorWin::SerialDeviceEnumeratorWin() {}
|
|
|
| SerialDeviceEnumeratorWin::~SerialDeviceEnumeratorWin() {}
|
|
|
| -// TODO(rockot): Query the system for more information than just device paths.
|
| -// This may or may not require using a different strategy than scanning the
|
| -// registry location below.
|
| mojo::Array<serial::DeviceInfoPtr> SerialDeviceEnumeratorWin::GetDevices() {
|
| - base::win::RegistryValueIterator iter_key(
|
| - HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\SERIALCOMM\\");
|
| mojo::Array<serial::DeviceInfoPtr> devices(0);
|
| - for (; iter_key.Valid(); ++iter_key) {
|
| +
|
| + // Make a device interface query to find all serial devices.
|
| + HDEVINFO dev_info =
|
| + SetupDiGetClassDevs(&GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR, 0, 0,
|
| + DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
|
| + if (dev_info == INVALID_HANDLE_VALUE)
|
| + return devices.Pass();
|
| +
|
| + 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++) {
|
| + std::string friendly_name, com_port;
|
| + // SPDRP_FRIENDLYNAME looks like "USB_SERIAL_PORT (COM3)".
|
| + if (!GetProperty(dev_info, dev_info_data, SPDRP_FRIENDLYNAME,
|
| + &friendly_name) ||
|
| + !GetCOMPort(friendly_name, &com_port))
|
| + // In Windows, the COM port is the path used to uniquely identify the
|
| + // serial device. If the COM can't be found, ignore the device.
|
| + continue;
|
| +
|
| serial::DeviceInfoPtr info(serial::DeviceInfo::New());
|
| - info->path = base::UTF16ToASCII(iter_key.Value());
|
| + info->path = com_port;
|
| +
|
| + std::string display_name;
|
| + if (GetDisplayName(friendly_name, &display_name))
|
| + info->display_name = display_name;
|
| +
|
| + std::string hardware_id;
|
| + // SPDRP_HARDWAREID looks like "FTDIBUS\COMPORT&VID_0403&PID_6001".
|
| + if (GetProperty(dev_info, dev_info_data, SPDRP_HARDWAREID, &hardware_id)) {
|
| + uint32_t vendor_id, product_id;
|
| + if (GetVendorID(hardware_id, &vendor_id)) {
|
| + info->has_vendor_id = true;
|
| + info->vendor_id = vendor_id;
|
| + }
|
| + if (GetProductID(hardware_id, &product_id)) {
|
| + info->has_product_id = true;
|
| + info->product_id = product_id;
|
| + }
|
| + }
|
| +
|
| devices.push_back(info.Pass());
|
| }
|
| +
|
| + SetupDiDestroyDeviceInfoList(dev_info);
|
| return devices.Pass();
|
| }
|
|
|
|
|