Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "device/serial/serial_device_enumerator_win.h" | 5 #include "device/serial/serial_device_enumerator_win.h" |
| 6 | 6 |
| 7 // This has to be included before windows.h. | |
| 8 #include "third_party/re2/re2/re2.h" | |
| 9 | |
| 7 #include <windows.h> | 10 #include <windows.h> |
| 11 #include <ntddser.h> | |
| 12 #include <setupapi.h> | |
| 8 | 13 |
| 9 #include "base/memory/scoped_ptr.h" | 14 #include "base/memory/scoped_ptr.h" |
| 10 #include "base/strings/string_util.h" | 15 #include "base/strings/string_number_conversions.h" |
| 11 #include "base/strings/stringprintf.h" | |
| 12 #include "base/strings/utf_string_conversions.h" | 16 #include "base/strings/utf_string_conversions.h" |
| 13 #include "base/win/registry.h" | |
| 14 | 17 |
| 15 namespace device { | 18 namespace device { |
| 16 | 19 |
| 20 namespace { | |
| 21 | |
| 22 // Searches the specified device info for a property with the specified key, | |
| 23 // assigns the result to value, and returns whether the operation was | |
| 24 // successful. | |
| 25 bool GetProperty(HDEVINFO dev_info, | |
| 26 SP_DEVINFO_DATA dev_info_data, | |
| 27 const int key, | |
| 28 std::string* value) { | |
| 29 // We don't know how much space the property's value will take up, so we call | |
| 30 // the property retrieval function once to fetch the size of the required | |
| 31 // value buffer, then again once we've allocated a sufficiently large buffer. | |
| 32 scoped_ptr<wchar_t[]> buffer; | |
| 33 DWORD buffer_size = 0; | |
| 34 while (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data, key, NULL, | |
| 35 (PBYTE)buffer.get(), buffer_size, | |
|
Ken Rockot(use gerrit already)
2015/09/23 17:30:18
buffer.get() is always nullptr here. Why not just
charliea (OOO until 10-5)
2015/09/28 13:22:53
Yea, the way that this was written with the while
| |
| 36 &buffer_size)) { | |
| 37 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) | |
| 38 buffer.reset(new wchar_t[buffer_size]); | |
| 39 else | |
| 40 return false; | |
| 41 } | |
| 42 | |
| 43 *value = base::WideToUTF8(buffer.get()); | |
| 44 return true; | |
| 45 } | |
| 46 | |
| 47 // Searches for the COM port in the device's friendly name, assigns its value to | |
| 48 // com_port, and returns whether the operation was successful. | |
| 49 bool GetCOMPort(const std::string friendly_name, std::string* com_port) { | |
| 50 return RE2::PartialMatch(friendly_name, ".* \\((COM[0-9]+)\\)", com_port); | |
| 51 } | |
| 52 | |
| 53 // Searches for the display name in the device's friendly name, assigns its | |
| 54 // value to display_name, and returns whether the operation was successful. | |
| 55 bool GetDisplayName(const std::string friendly_name, | |
| 56 std::string* display_name) { | |
| 57 return RE2::PartialMatch(friendly_name, "(.*) \\(COM[0-9]+\\)", display_name); | |
| 58 } | |
| 59 | |
| 60 // Searches for the vendor ID in the device's hardware ID, assigns its value to | |
| 61 // vendor_id, and returns whether the operation was successful. | |
| 62 bool GetVendorID(const std::string hardware_id, uint32_t* vendor_id) { | |
| 63 std::string vendor_id_str; | |
| 64 return RE2::PartialMatch(hardware_id, "VID_([0-9]+)", &vendor_id_str) && | |
| 65 base::HexStringToUInt(vendor_id_str, vendor_id); | |
| 66 } | |
| 67 | |
| 68 // Searches for the product ID in the device's product ID, assigns its value to | |
| 69 // product_id, and returns whether the operation was successful. | |
| 70 bool GetProductID(const std::string hardware_id, uint32_t* product_id) { | |
| 71 std::string product_id_str; | |
| 72 return RE2::PartialMatch(hardware_id, "PID_([0-9]+)", &product_id_str) && | |
| 73 base::HexStringToUInt(product_id_str, product_id); | |
| 74 } | |
| 75 | |
| 76 } // namespace | |
| 77 | |
| 17 // static | 78 // static |
| 18 scoped_ptr<SerialDeviceEnumerator> SerialDeviceEnumerator::Create() { | 79 scoped_ptr<SerialDeviceEnumerator> SerialDeviceEnumerator::Create() { |
| 19 return scoped_ptr<SerialDeviceEnumerator>(new SerialDeviceEnumeratorWin()); | 80 return scoped_ptr<SerialDeviceEnumerator>(new SerialDeviceEnumeratorWin()); |
| 20 } | 81 } |
| 21 | 82 |
| 22 SerialDeviceEnumeratorWin::SerialDeviceEnumeratorWin() {} | 83 SerialDeviceEnumeratorWin::SerialDeviceEnumeratorWin() {} |
| 23 | 84 |
| 24 SerialDeviceEnumeratorWin::~SerialDeviceEnumeratorWin() {} | 85 SerialDeviceEnumeratorWin::~SerialDeviceEnumeratorWin() {} |
| 25 | 86 |
| 26 // TODO(rockot): Query the system for more information than just device paths. | |
| 27 // This may or may not require using a different strategy than scanning the | |
| 28 // registry location below. | |
| 29 mojo::Array<serial::DeviceInfoPtr> SerialDeviceEnumeratorWin::GetDevices() { | 87 mojo::Array<serial::DeviceInfoPtr> SerialDeviceEnumeratorWin::GetDevices() { |
| 30 base::win::RegistryValueIterator iter_key( | |
| 31 HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\SERIALCOMM\\"); | |
| 32 mojo::Array<serial::DeviceInfoPtr> devices(0); | 88 mojo::Array<serial::DeviceInfoPtr> devices(0); |
| 33 for (; iter_key.Valid(); ++iter_key) { | 89 |
| 90 // Make a device interface query to find all serial devices. | |
| 91 HDEVINFO dev_info = | |
| 92 SetupDiGetClassDevs(&GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR, 0, 0, | |
| 93 DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); | |
| 94 if (dev_info == INVALID_HANDLE_VALUE) | |
| 95 return devices.Pass(); | |
| 96 | |
| 97 SP_DEVINFO_DATA dev_info_data; | |
| 98 dev_info_data.cbSize = sizeof(SP_DEVINFO_DATA); | |
| 99 for (DWORD i = 0; SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data); i++) { | |
| 100 std::string friendly_name, com_port; | |
| 101 // SPDRP_FRIENDLYNAME looks like "USB_SERIAL_PORT (COM3)". | |
| 102 if (!GetProperty(dev_info, dev_info_data, SPDRP_FRIENDLYNAME, | |
| 103 &friendly_name) || | |
| 104 !GetCOMPort(friendly_name, &com_port)) | |
| 105 // In Windows, the COM port is the path used to uniquely identify the | |
| 106 // serial device. If the COM can't be found, ignore the device. | |
| 107 continue; | |
| 108 | |
| 34 serial::DeviceInfoPtr info(serial::DeviceInfo::New()); | 109 serial::DeviceInfoPtr info(serial::DeviceInfo::New()); |
| 35 info->path = base::UTF16ToASCII(iter_key.Value()); | 110 info->path = com_port; |
| 111 | |
| 112 std::string display_name; | |
| 113 if (GetDisplayName(friendly_name, &display_name)) | |
| 114 info->display_name = display_name; | |
| 115 | |
| 116 std::string hardware_id; | |
| 117 // SPDRP_HARDWAREID looks like "FTDIBUS\COMPORT&VID_0403&PID_6001". | |
| 118 if (GetProperty(dev_info, dev_info_data, SPDRP_HARDWAREID, &hardware_id)) { | |
| 119 uint32_t vendor_id, product_id; | |
| 120 if (GetVendorID(hardware_id, &vendor_id)) { | |
| 121 info->has_vendor_id = true; | |
| 122 info->vendor_id = vendor_id; | |
| 123 } | |
| 124 if (GetProductID(hardware_id, &product_id)) { | |
| 125 info->has_product_id = true; | |
| 126 info->product_id = product_id; | |
| 127 } | |
| 128 } | |
| 129 | |
| 36 devices.push_back(info.Pass()); | 130 devices.push_back(info.Pass()); |
| 37 } | 131 } |
| 132 | |
| 133 SetupDiDestroyDeviceInfoList(dev_info); | |
| 38 return devices.Pass(); | 134 return devices.Pass(); |
| 39 } | 135 } |
| 40 | 136 |
| 41 } // namespace device | 137 } // namespace device |
| OLD | NEW |