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 |