| 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/bluetooth/bluetooth_low_energy_win.h" | 5 #include "device/bluetooth/bluetooth_low_energy_win.h" |
| 6 | 6 |
| 7 #include <cfg.h> | |
| 8 #define INITGUID // For DEVPKEY_Xxxx guid/pid pairs | |
| 9 #include <devpkey.h> | |
| 10 | |
| 11 #include "base/logging.h" | 7 #include "base/logging.h" |
| 12 #include "base/strings/sys_string_conversions.h" | 8 #include "base/strings/sys_string_conversions.h" |
| 13 #include "base/win/windows_version.h" | 9 #include "base/win/windows_version.h" |
| 14 | 10 |
| 15 namespace { | 11 namespace { |
| 16 | 12 |
| 17 using device::win::DeviceRegistryPropertyValue; | 13 using device::win::DeviceRegistryPropertyValue; |
| 18 using device::win::DevicePropertyValue; | |
| 19 | 14 |
| 20 const char kPlatformNotSupported[] = | 15 const char kPlatformNotSupported[] = |
| 21 "Bluetooth Low energy is only supported on Windows 8 and later."; | 16 "Bluetooth Low energy is only supported on Windows 8 and later."; |
| 22 const char kDeviceEnumError[] = "Error enumerating Bluetooth LE devices."; | 17 const char kDeviceEnumError[] = "Error enumerating Bluetooth LE devices."; |
| 23 const char kDeviceInfoError[] = | 18 const char kDeviceInfoError[] = |
| 24 "Error retrieving Bluetooth LE device information."; | 19 "Error retrieving Bluetooth LE device information."; |
| 25 const char kDeviceAddressError[] = | 20 const char kDeviceAddressError[] = |
| 26 "Device instance ID value does not seem to contain a Bluetooth Adapter " | 21 "Device instance ID value does not seem to contain a Bluetooth Adapter " |
| 27 "address."; | 22 "address."; |
| 28 const char kDeviceFriendlyNameError[] = "Device name is not valid."; | 23 const char kDeviceFriendlyNameError[] = "Device name is not valid."; |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 123 const char* message, | 118 const char* message, |
| 124 std::string* error) { | 119 std::string* error) { |
| 125 if (actual_length != expected_length) { | 120 if (actual_length != expected_length) { |
| 126 *error = FormatBluetoothError(message, E_FAIL); | 121 *error = FormatBluetoothError(message, E_FAIL); |
| 127 return false; | 122 return false; |
| 128 } | 123 } |
| 129 | 124 |
| 130 return true; | 125 return true; |
| 131 } | 126 } |
| 132 | 127 |
| 133 bool CollectBluetoothLowEnergyDeviceProperty( | |
| 134 const ScopedDeviceInfoSetHandle& device_info_handle, | |
| 135 PSP_DEVINFO_DATA device_info_data, | |
| 136 const DEVPROPKEY& key, | |
| 137 scoped_ptr<DevicePropertyValue>* value, | |
| 138 std::string* error) { | |
| 139 DWORD required_length; | |
| 140 DEVPROPTYPE prop_type; | |
| 141 BOOL success = SetupDiGetDeviceProperty(device_info_handle, | |
| 142 device_info_data, | |
| 143 &key, | |
| 144 &prop_type, | |
| 145 NULL, | |
| 146 0, | |
| 147 &required_length, | |
| 148 0); | |
| 149 if (!CheckInsufficientBuffer(!!success, kDeviceInfoError, error)) | |
| 150 return false; | |
| 151 | |
| 152 scoped_ptr<uint8_t[]> prop_value(new uint8_t[required_length]); | |
| 153 DWORD actual_length = required_length; | |
| 154 success = SetupDiGetDeviceProperty(device_info_handle, | |
| 155 device_info_data, | |
| 156 &key, | |
| 157 &prop_type, | |
| 158 prop_value.get(), | |
| 159 actual_length, | |
| 160 &required_length, | |
| 161 0); | |
| 162 if (!CheckSuccess(!!success, kDeviceInfoError, error)) | |
| 163 return false; | |
| 164 if (!CheckExpectedLength( | |
| 165 actual_length, required_length, kDeviceInfoError, error)) { | |
| 166 return false; | |
| 167 } | |
| 168 | |
| 169 (*value) = scoped_ptr<DevicePropertyValue>( | |
| 170 new DevicePropertyValue(prop_type, prop_value.Pass(), actual_length)); | |
| 171 return true; | |
| 172 } | |
| 173 | |
| 174 bool CollectBluetoothLowEnergyDeviceRegistryProperty( | 128 bool CollectBluetoothLowEnergyDeviceRegistryProperty( |
| 175 const ScopedDeviceInfoSetHandle& device_info_handle, | 129 const ScopedDeviceInfoSetHandle& device_info_handle, |
| 176 PSP_DEVINFO_DATA device_info_data, | 130 PSP_DEVINFO_DATA device_info_data, |
| 177 DWORD property_id, | 131 DWORD property_id, |
| 178 scoped_ptr<DeviceRegistryPropertyValue>* value, | 132 scoped_ptr<DeviceRegistryPropertyValue>* value, |
| 179 std::string* error) { | 133 std::string* error) { |
| 180 ULONG required_length = 0; | 134 ULONG required_length = 0; |
| 181 BOOL success = SetupDiGetDeviceRegistryProperty(device_info_handle, | 135 BOOL success = SetupDiGetDeviceRegistryProperty(device_info_handle, |
| 182 device_info_data, | 136 device_info_data, |
| 183 property_id, | 137 property_id, |
| 184 NULL, | 138 NULL, |
| 185 NULL, | 139 NULL, |
| 186 0, | 140 0, |
| 187 &required_length); | 141 &required_length); |
| 188 if (!CheckInsufficientBuffer(!!success, kDeviceInfoError, error)) | 142 if (!CheckInsufficientBuffer(!!success, kDeviceInfoError, error)) |
| 189 return false; | 143 return false; |
| 190 | 144 |
| 191 scoped_ptr<uint8_t[]> property_value(new uint8_t[required_length]); | 145 scoped_ptr<UINT8[]> property_value(new UINT8[required_length]); |
| 192 ULONG actual_length = required_length; | 146 ULONG actual_length = required_length; |
| 193 DWORD property_type; | 147 DWORD property_type; |
| 194 success = SetupDiGetDeviceRegistryProperty(device_info_handle, | 148 success = SetupDiGetDeviceRegistryProperty(device_info_handle, |
| 195 device_info_data, | 149 device_info_data, |
| 196 property_id, | 150 property_id, |
| 197 &property_type, | 151 &property_type, |
| 198 property_value.get(), | 152 property_value.get(), |
| 199 actual_length, | 153 actual_length, |
| 200 &required_length); | 154 &required_length); |
| 201 if (!CheckSuccess(!!success, kDeviceInfoError, error)) | 155 if (!CheckSuccess(!!success, kDeviceInfoError, error)) |
| 202 return false; | 156 return false; |
| 203 if (!CheckExpectedLength( | 157 if (!CheckExpectedLength( |
| 204 actual_length, required_length, kDeviceInfoError, error)) { | 158 actual_length, required_length, kDeviceInfoError, error)) |
| 205 return false; | 159 return false; |
| 206 } | |
| 207 | 160 |
| 208 (*value) = DeviceRegistryPropertyValue::Create( | 161 (*value) = DeviceRegistryPropertyValue::Create( |
| 209 property_type, property_value.Pass(), actual_length).Pass(); | 162 property_type, property_value.Pass(), actual_length).Pass(); |
| 210 return true; | 163 return true; |
| 211 } | 164 } |
| 212 | 165 |
| 213 bool CollectBluetoothLowEnergyDeviceInstanceId( | 166 bool CollectBluetoothLowEnergyDeviceInstanceId( |
| 214 const ScopedDeviceInfoSetHandle& device_info_handle, | 167 const ScopedDeviceInfoSetHandle& device_info_handle, |
| 215 PSP_DEVINFO_DATA device_info_data, | 168 PSP_DEVINFO_DATA device_info_data, |
| 216 scoped_ptr<device::win::BluetoothLowEnergyDeviceInfo>& device_info, | 169 scoped_ptr<device::win::BluetoothLowEnergyDeviceInfo>& device_info, |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 295 std::string* error) { | 248 std::string* error) { |
| 296 // TODO(rpaquay): We exctract the bluetooth device address from the device | 249 // TODO(rpaquay): We exctract the bluetooth device address from the device |
| 297 // instance ID string, as we did not find a more formal API for retrieving the | 250 // instance ID string, as we did not find a more formal API for retrieving the |
| 298 // bluetooth address of a Bluetooth Low Energy device. | 251 // bluetooth address of a Bluetooth Low Energy device. |
| 299 // An Bluetooth device instance ID has the following format (under Win8+): | 252 // An Bluetooth device instance ID has the following format (under Win8+): |
| 300 // BTHLE\DEV_BC6A29AB5FB0\8&31038925&0&BC6A29AB5FB0 | 253 // BTHLE\DEV_BC6A29AB5FB0\8&31038925&0&BC6A29AB5FB0 |
| 301 return ExtractBluetoothAddressFromDeviceInstanceId( | 254 return ExtractBluetoothAddressFromDeviceInstanceId( |
| 302 device_info->id, &device_info->address, error); | 255 device_info->id, &device_info->address, error); |
| 303 } | 256 } |
| 304 | 257 |
| 305 bool CollectBluetoothLowEnergyDeviceStatus( | |
| 306 const ScopedDeviceInfoSetHandle& device_info_handle, | |
| 307 PSP_DEVINFO_DATA device_info_data, | |
| 308 scoped_ptr<device::win::BluetoothLowEnergyDeviceInfo>& device_info, | |
| 309 std::string* error) { | |
| 310 scoped_ptr<DevicePropertyValue> value; | |
| 311 if (!CollectBluetoothLowEnergyDeviceProperty(device_info_handle, | |
| 312 device_info_data, | |
| 313 DEVPKEY_Device_DevNodeStatus, | |
| 314 &value, | |
| 315 error)) { | |
| 316 return false; | |
| 317 } | |
| 318 | |
| 319 if (value->property_type() != DEVPROP_TYPE_UINT32) { | |
| 320 *error = kDeviceInfoError; | |
| 321 return false; | |
| 322 } | |
| 323 | |
| 324 device_info->connected = !(value->AsUint32() & DN_DEVICE_DISCONNECTED); | |
| 325 return true; | |
| 326 } | |
| 327 | |
| 328 bool CollectBluetoothLowEnergyDeviceInfo( | 258 bool CollectBluetoothLowEnergyDeviceInfo( |
| 329 const ScopedDeviceInfoSetHandle& device_info_handle, | 259 const ScopedDeviceInfoSetHandle& device_info_handle, |
| 330 PSP_DEVICE_INTERFACE_DATA device_interface_data, | 260 PSP_DEVICE_INTERFACE_DATA device_interface_data, |
| 331 scoped_ptr<device::win::BluetoothLowEnergyDeviceInfo>* device_info, | 261 scoped_ptr<device::win::BluetoothLowEnergyDeviceInfo>* device_info, |
| 332 std::string* error) { | 262 std::string* error) { |
| 333 // Retrieve required # of bytes for interface details | 263 // Retrieve required # of bytes for interface details |
| 334 ULONG required_length = 0; | 264 ULONG required_length = 0; |
| 335 BOOL success = SetupDiGetDeviceInterfaceDetail(device_info_handle, | 265 BOOL success = SetupDiGetDeviceInterfaceDetail(device_info_handle, |
| 336 device_interface_data, | 266 device_interface_data, |
| 337 NULL, | 267 NULL, |
| 338 0, | 268 0, |
| 339 &required_length, | 269 &required_length, |
| 340 NULL); | 270 NULL); |
| 341 if (!CheckInsufficientBuffer(!!success, kDeviceInfoError, error)) | 271 if (!CheckInsufficientBuffer(!!success, kDeviceInfoError, error)) |
| 342 return false; | 272 return false; |
| 343 | 273 |
| 344 scoped_ptr<uint8_t[]> interface_data(new uint8_t[required_length]); | 274 scoped_ptr<UINT8[]> interface_data(new UINT8[required_length]); |
| 345 ZeroMemory(interface_data.get(), required_length); | 275 ZeroMemory(interface_data.get(), required_length); |
| 346 | 276 |
| 347 PSP_DEVICE_INTERFACE_DETAIL_DATA device_interface_detail_data = | 277 PSP_DEVICE_INTERFACE_DETAIL_DATA device_interface_detail_data = |
| 348 reinterpret_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA>(interface_data.get()); | 278 reinterpret_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA>(interface_data.get()); |
| 349 device_interface_detail_data->cbSize = | 279 device_interface_detail_data->cbSize = |
| 350 sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); | 280 sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); |
| 351 | 281 |
| 352 SP_DEVINFO_DATA device_info_data = {0}; | 282 SP_DEVINFO_DATA device_info_data = {0}; |
| 353 device_info_data.cbSize = sizeof(SP_DEVINFO_DATA); | 283 device_info_data.cbSize = sizeof(SP_DEVINFO_DATA); |
| 354 | 284 |
| 355 ULONG actual_length = required_length; | 285 ULONG actual_length = required_length; |
| 356 success = SetupDiGetDeviceInterfaceDetail(device_info_handle, | 286 success = SetupDiGetDeviceInterfaceDetail(device_info_handle, |
| 357 device_interface_data, | 287 device_interface_data, |
| 358 device_interface_detail_data, | 288 device_interface_detail_data, |
| 359 actual_length, | 289 actual_length, |
| 360 &required_length, | 290 &required_length, |
| 361 &device_info_data); | 291 &device_info_data); |
| 362 if (!CheckSuccess(!!success, kDeviceInfoError, error)) | 292 if (!CheckSuccess(!!success, kDeviceInfoError, error)) |
| 363 return false; | 293 return false; |
| 364 if (!CheckExpectedLength( | 294 if (!CheckExpectedLength( |
| 365 actual_length, required_length, kDeviceInfoError, error)) { | 295 actual_length, required_length, kDeviceInfoError, error)) |
| 366 return false; | 296 return false; |
| 367 } | |
| 368 | 297 |
| 369 scoped_ptr<device::win::BluetoothLowEnergyDeviceInfo> result( | 298 scoped_ptr<device::win::BluetoothLowEnergyDeviceInfo> result( |
| 370 new device::win::BluetoothLowEnergyDeviceInfo()); | 299 new device::win::BluetoothLowEnergyDeviceInfo()); |
| 371 result->path = | 300 result->path = |
| 372 base::FilePath(std::wstring(device_interface_detail_data->DevicePath)); | 301 base::FilePath(std::wstring(device_interface_detail_data->DevicePath)); |
| 373 if (!CollectBluetoothLowEnergyDeviceInstanceId( | 302 if (!CollectBluetoothLowEnergyDeviceInstanceId( |
| 374 device_info_handle, &device_info_data, result, error)) { | 303 device_info_handle, &device_info_data, result, error)) { |
| 375 return false; | 304 return false; |
| 376 } | 305 } |
| 377 if (!CollectDeviceFriendlyName( | 306 if (!CollectDeviceFriendlyName( |
| 378 device_info_handle, &device_info_data, result, error)) { | 307 device_info_handle, &device_info_data, result, error)) { |
| 379 return false; | 308 return false; |
| 380 } | 309 } |
| 381 if (!CollectBluetoothLowEnergyDeviceAddress( | 310 if (!CollectBluetoothLowEnergyDeviceAddress( |
| 382 device_info_handle, &device_info_data, result, error)) { | 311 device_info_handle, &device_info_data, result, error)) { |
| 383 return false; | 312 return false; |
| 384 } | 313 } |
| 385 if (!CollectBluetoothLowEnergyDeviceStatus( | |
| 386 device_info_handle, &device_info_data, result, error)) { | |
| 387 return false; | |
| 388 } | |
| 389 (*device_info) = result.Pass(); | 314 (*device_info) = result.Pass(); |
| 390 return true; | 315 return true; |
| 391 } | 316 } |
| 392 | 317 |
| 393 enum DeviceInfoResult { kOk, kError, kNoMoreDevices }; | 318 enum DeviceInfoResult { kOk, kError, kNoMoreDevices }; |
| 394 | 319 |
| 395 DeviceInfoResult EnumerateSingleBluetoothLowEnergyDevice( | 320 DeviceInfoResult EnumerateSingleBluetoothLowEnergyDevice( |
| 396 const ScopedDeviceInfoSetHandle& device_info_handle, | 321 const ScopedDeviceInfoSetHandle& device_info_handle, |
| 397 DWORD device_index, | 322 DWORD device_index, |
| 398 scoped_ptr<device::win::BluetoothLowEnergyDeviceInfo>* device_info, | 323 scoped_ptr<device::win::BluetoothLowEnergyDeviceInfo>* device_info, |
| 399 std::string* error) { | 324 std::string* error) { |
| 400 // Enumerate device of BLUETOOTHLE_DEVICE interface class | 325 // Enumerate device of LE_DEVICE interface class |
| 401 GUID BluetoothInterfaceGUID = GUID_BLUETOOTHLE_DEVICE_INTERFACE; | 326 GUID BluetoothInterfaceGUID = GUID_BLUETOOTHLE_DEVICE_INTERFACE; |
| 402 SP_DEVICE_INTERFACE_DATA device_interface_data = {0}; | 327 SP_DEVICE_INTERFACE_DATA device_interface_data = {0}; |
| 403 device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); | 328 device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); |
| 404 BOOL success = ::SetupDiEnumDeviceInterfaces(device_info_handle, | 329 BOOL success = ::SetupDiEnumDeviceInterfaces(device_info_handle, |
| 405 NULL, | 330 NULL, |
| 406 &BluetoothInterfaceGUID, | 331 &BluetoothInterfaceGUID, |
| 407 device_index, | 332 device_index, |
| 408 &device_interface_data); | 333 &device_interface_data); |
| 409 if (!success) { | 334 if (!success) { |
| 410 HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); | 335 HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); |
| 411 if (hr == HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS)) { | 336 if (hr == HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS)) { |
| 412 return kNoMoreDevices; | 337 return kNoMoreDevices; |
| 413 } | 338 } |
| 414 *error = FormatBluetoothError(kDeviceInfoError, hr); | 339 *error = FormatBluetoothError(kDeviceInfoError, hr); |
| 415 return kError; | 340 return kError; |
| 416 } | 341 } |
| 417 | 342 |
| 418 if (!CollectBluetoothLowEnergyDeviceInfo( | 343 if (!CollectBluetoothLowEnergyDeviceInfo( |
| 419 device_info_handle, &device_interface_data, device_info, error)) { | 344 device_info_handle, &device_interface_data, device_info, error)) |
| 420 return kError; | 345 return kError; |
| 421 } | |
| 422 | 346 |
| 423 return kOk; | 347 return kOk; |
| 424 } | 348 } |
| 425 | 349 |
| 426 // Opens a Device Info Set that can be used to enumerate Bluetooth LE devices | 350 // Opens a Device Info Set that can be used to enumerate Bluetooth LE devices |
| 427 // present on the machine. | 351 // present on the machine. |
| 428 HRESULT OpenBluetoothLowEnergyDevices(ScopedDeviceInfoSetHandle* handle) { | 352 HRESULT OpenBluetoothLowEnergyDevices(ScopedDeviceInfoSetHandle* handle) { |
| 429 GUID BluetoothClassGUID = GUID_BLUETOOTHLE_DEVICE_INTERFACE; | 353 GUID BluetoothClassGUID = GUID_BLUETOOTHLE_DEVICE_INTERFACE; |
| 430 ScopedDeviceInfoSetHandle result(SetupDiGetClassDevs( | 354 ScopedDeviceInfoSetHandle result(SetupDiGetClassDevs( |
| 431 &BluetoothClassGUID, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE)); | 355 &BluetoothClassGUID, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE)); |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 497 WCHAR* value_string = reinterpret_cast<WCHAR*>(value_.get()); | 421 WCHAR* value_string = reinterpret_cast<WCHAR*>(value_.get()); |
| 498 return base::SysWideToUTF8(value_string); | 422 return base::SysWideToUTF8(value_string); |
| 499 } | 423 } |
| 500 | 424 |
| 501 DWORD DeviceRegistryPropertyValue::AsDWORD() const { | 425 DWORD DeviceRegistryPropertyValue::AsDWORD() const { |
| 502 CHECK_EQ(property_type_, static_cast<DWORD>(REG_DWORD)); | 426 CHECK_EQ(property_type_, static_cast<DWORD>(REG_DWORD)); |
| 503 DWORD* value = reinterpret_cast<DWORD*>(value_.get()); | 427 DWORD* value = reinterpret_cast<DWORD*>(value_.get()); |
| 504 return *value; | 428 return *value; |
| 505 } | 429 } |
| 506 | 430 |
| 507 DevicePropertyValue::DevicePropertyValue(DEVPROPTYPE property_type, | |
| 508 scoped_ptr<uint8_t[]> value, | |
| 509 size_t value_size) | |
| 510 : property_type_(property_type), | |
| 511 value_(value.Pass()), | |
| 512 value_size_(value_size) { | |
| 513 } | |
| 514 | |
| 515 uint32_t DevicePropertyValue::AsUint32() const { | |
| 516 CHECK_EQ(property_type_, static_cast<DEVPROPTYPE>(DEVPROP_TYPE_UINT32)); | |
| 517 CHECK_EQ(value_size_, sizeof(uint32_t)); | |
| 518 return *reinterpret_cast<uint32_t*>(value_.get()); | |
| 519 } | |
| 520 | |
| 521 BluetoothLowEnergyDeviceInfo::BluetoothLowEnergyDeviceInfo() | |
| 522 : connected(false) { | |
| 523 address.ullLong = BLUETOOTH_NULL_ADDRESS; | |
| 524 } | |
| 525 | |
| 526 BluetoothLowEnergyDeviceInfo::~BluetoothLowEnergyDeviceInfo() { | |
| 527 } | |
| 528 | |
| 529 bool IsBluetoothLowEnergySupported() { | 431 bool IsBluetoothLowEnergySupported() { |
| 530 return base::win::GetVersion() >= base::win::VERSION_WIN8; | 432 return base::win::GetVersion() >= base::win::VERSION_WIN8; |
| 531 } | 433 } |
| 532 | 434 |
| 533 bool EnumerateKnownBluetoothLowEnergyDevices( | 435 bool EnumerateKnownBluetoothLowEnergyDevices( |
| 534 ScopedVector<BluetoothLowEnergyDeviceInfo>* devices, | 436 ScopedVector<BluetoothLowEnergyDeviceInfo>* devices, |
| 535 std::string* error) { | 437 std::string* error) { |
| 536 if (!IsBluetoothLowEnergySupported()) { | 438 if (!IsBluetoothLowEnergySupported()) { |
| 537 *error = kPlatformNotSupported; | 439 *error = kPlatformNotSupported; |
| 538 return false; | 440 return false; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 562 | 464 |
| 563 bool ExtractBluetoothAddressFromDeviceInstanceIdForTesting( | 465 bool ExtractBluetoothAddressFromDeviceInstanceIdForTesting( |
| 564 const std::string& instance_id, | 466 const std::string& instance_id, |
| 565 BLUETOOTH_ADDRESS* btha, | 467 BLUETOOTH_ADDRESS* btha, |
| 566 std::string* error) { | 468 std::string* error) { |
| 567 return ExtractBluetoothAddressFromDeviceInstanceId(instance_id, btha, error); | 469 return ExtractBluetoothAddressFromDeviceInstanceId(instance_id, btha, error); |
| 568 } | 470 } |
| 569 | 471 |
| 570 } // namespace win | 472 } // namespace win |
| 571 } // namespace device | 473 } // namespace device |
| OLD | NEW |