9#include <QtCore/QLoggingCategory>
10#include <QtCore/private/qfunctions_winrt_p.h>
14#include <windows.devices.enumeration.h>
15#include <windows.devices.bluetooth.h>
16#include <windows.foundation.collections.h>
17#include <windows.networking.h>
18#include <windows.storage.streams.h>
21using namespace Microsoft::WRL;
22using namespace Microsoft::WRL::Wrappers;
23using namespace ABI::Windows::Foundation;
24using namespace ABI::Windows::Foundation::Collections;
25using namespace ABI::Windows::Devices;
26using namespace ABI::Windows::Devices::Bluetooth;
27using namespace ABI::Windows::Devices::Bluetooth::Rfcomm;
28using namespace ABI::Windows::Devices::Enumeration;
42#define TYPE_SHORT_UUID 25
43#define TYPE_LONG_UUID 28
45#define TYPE_SEQUENCE 53
50 for (size_t i = length; i > length/2; i--)
51 std::swap(data[length - i], data[i - 1]);
69 HRESULT onBluetoothDeviceFoundAsync(IAsyncOperation<BluetoothDevice *> *op, AsyncStatus status);
71 void processServiceSearchResult(quint64 address, ComPtr<IVectorView<RfcommDeviceService*>> services);
75 quint64 m_targetAddress;
80 QBluetoothServiceDiscoveryAgent::DiscoveryMode mode)
81 : m_targetAddress(targetAddress)
92 ComPtr<IBluetoothDeviceStatics> deviceStatics;
93 HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Bluetooth_BluetoothDevice).Get(), &deviceStatics);
94 Q_ASSERT_SUCCEEDED(hr);
95 ComPtr<IAsyncOperation<BluetoothDevice *>> deviceFromAddressOperation;
96 hr = deviceStatics->FromBluetoothAddressAsync(m_targetAddress, &deviceFromAddressOperation);
97 Q_ASSERT_SUCCEEDED(hr);
98 hr = deviceFromAddressOperation->put_Completed(Callback<IAsyncOperationCompletedHandler<BluetoothDevice *>>
99 (
this, &QWinRTBluetoothServiceDiscoveryWorker::onBluetoothDeviceFoundAsync).Get());
100 Q_ASSERT_SUCCEEDED(hr);
105 if (status != Completed) {
106 qCDebug(QT_BT_WINDOWS) <<
"Could not find device";
111 ComPtr<IBluetoothDevice> device;
113 hr = op->GetResults(&device);
114 Q_ASSERT_SUCCEEDED(hr);
116 device->get_BluetoothAddress(&address);
118 ComPtr<IBluetoothDevice3> device3;
119 hr = device.As(&device3);
120 Q_ASSERT_SUCCEEDED(hr);
121 ComPtr<IAsyncOperation<RfcommDeviceServicesResult *>> serviceOp;
122 const BluetoothCacheMode cacheMode = m_mode == QBluetoothServiceDiscoveryAgent::MinimalDiscovery
123 ? BluetoothCacheMode_Cached : BluetoothCacheMode_Uncached;
124 hr = device3->GetRfcommServicesWithCacheModeAsync(cacheMode, &serviceOp);
125 Q_ASSERT_SUCCEEDED(hr);
126 hr = serviceOp->put_Completed(Callback<IAsyncOperationCompletedHandler<RfcommDeviceServicesResult *>>
127 ([address,
this](IAsyncOperation<RfcommDeviceServicesResult *> *op, AsyncStatus status)
129 if (status != Completed) {
130 qCDebug(QT_BT_WINDOWS) <<
"Could not obtain service list";
135 ComPtr<IRfcommDeviceServicesResult> result;
136 HRESULT hr = op->GetResults(&result);
137 Q_ASSERT_SUCCEEDED(hr);
138 ComPtr<IVectorView<RfcommDeviceService*>> commServices;
139 hr = result->get_Services(&commServices);
140 Q_ASSERT_SUCCEEDED(hr);
141 processServiceSearchResult(address, commServices);
144 Q_ASSERT_SUCCEEDED(hr);
153 hr = services->get_Size(&size);
154 Q_ASSERT_SUCCEEDED(hr);
155 for (quint32 i = 0; i < size; ++i) {
156 ComPtr<IRfcommDeviceService> service;
157 hr = services->GetAt(i, &service);
158 Q_ASSERT_SUCCEEDED(hr);
160 hr = service->get_ConnectionServiceName(name.GetAddressOf());
161 Q_ASSERT_SUCCEEDED(hr);
162 const QString serviceName = QString::fromWCharArray(WindowsGetStringRawBuffer(name.Get(),
nullptr));
163 ComPtr<ABI::Windows::Networking::IHostName> host;
164 hr = service->get_ConnectionHostName(host.GetAddressOf());
165 Q_ASSERT_SUCCEEDED(hr);
167 hr = host->get_RawName(hostName.GetAddressOf());
168 Q_ASSERT_SUCCEEDED(hr);
169 const QString qHostName = QString::fromWCharArray(WindowsGetStringRawBuffer(hostName.Get(),
171 ComPtr<IRfcommServiceId> id;
172 hr = service->get_ServiceId(&id);
173 Q_ASSERT_SUCCEEDED(hr);
175 hr = id->get_Uuid(&guid);
176 const QBluetoothUuid uuid(guid);
177 Q_ASSERT_SUCCEEDED(hr);
180 info.setAttribute(0xBEEF, QVariant(qHostName));
181 info.setAttribute(0xBEF0, QVariant(serviceName));
182 info.setServiceName(serviceName);
183 info.setServiceUuid(uuid);
184 ComPtr<IAsyncOperation<IMapView<UINT32, IBuffer *> *>> op;
185 hr = service->GetSdpRawAttributesAsync(op.GetAddressOf());
188 qCDebug(QT_BT_WINDOWS) <<
"Check manifest capabilities";
191 ComPtr<IMapView<UINT32, IBuffer *>> mapView;
192 hr = QWinRTFunctions::await(op, mapView.GetAddressOf());
193 Q_ASSERT_SUCCEEDED(hr);
195 ComPtr<ValueIterable> iterable;
196 ComPtr<ValueIterator> iterator;
198 hr = mapView.As(&iterable);
202 boolean current =
false;
203 hr = iterable->First(&iterator);
206 hr = iterator->get_HasCurrent(¤t);
210 while (SUCCEEDED(hr) && current) {
211 ComPtr<ValueItem> item;
212 hr = iterator->get_Current(&item);
217 hr = item->get_Key(&key);
221 ComPtr<IBuffer> buffer;
222 hr = item->get_Value(&buffer);
223 Q_ASSERT_SUCCEEDED(hr);
225 ComPtr<IDataReader> dataReader;
226 ComPtr<IDataReaderStatics> dataReaderStatics;
227 hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_DataReader).Get(), &dataReaderStatics);
228 Q_ASSERT_SUCCEEDED(hr);
229 hr = dataReaderStatics->FromBuffer(buffer.Get(), dataReader.GetAddressOf());
230 Q_ASSERT_SUCCEEDED(hr);
232 hr = dataReader->ReadByte(&type);
233 Q_ASSERT_SUCCEEDED(hr);
236 hr = dataReader->ReadByte(&value);
237 Q_ASSERT_SUCCEEDED(hr);
238 info.setAttribute(key, value);
239 qCDebug(QT_BT_WINDOWS) <<
"UUID" << uuid <<
"KEY" << Qt::hex << key <<
"TYPE" << Qt::dec << type <<
"UINT8" << Qt::hex << value;
242 hr = dataReader->ReadUInt16(&value);
243 Q_ASSERT_SUCCEEDED(hr);
244 info.setAttribute(key, value);
245 qCDebug(QT_BT_WINDOWS) <<
"UUID" << uuid <<
"KEY" << Qt::hex << key <<
"TYPE" << Qt::dec << type <<
"UINT16" << Qt::hex << value;
248 hr = dataReader->ReadUInt32(&value);
249 Q_ASSERT_SUCCEEDED(hr);
250 info.setAttribute(key, value);
251 qCDebug(QT_BT_WINDOWS) <<
"UUID" << uuid <<
"KEY" << Qt::hex << key <<
"TYPE" << Qt::dec << type <<
"UINT32" << Qt::hex << value;
254 hr = dataReader->ReadUInt16(&value);
255 Q_ASSERT_SUCCEEDED(hr);
256 const QBluetoothUuid uuid(value);
257 info.setAttribute(key, uuid);
258 qCDebug(QT_BT_WINDOWS) <<
"UUID" << uuid <<
"KEY" << Qt::hex << key <<
"TYPE" << Qt::dec << type <<
"UUID" << Qt::hex << uuid;
261 hr = dataReader->ReadGuid(&value);
262 Q_ASSERT_SUCCEEDED(hr);
264 reverseArray(value.Data4,
sizeof(value.Data4)/
sizeof(value.Data4[0]));
265 const QBluetoothUuid uuid(value);
266 info.setAttribute(key, uuid);
267 qCDebug(QT_BT_WINDOWS) <<
"UUID" << uuid <<
"KEY" << Qt::hex << key <<
"TYPE" << Qt::dec << type <<
"UUID" << Qt::hex << uuid;
270 hr = dataReader->ReadByte(&length);
271 Q_ASSERT_SUCCEEDED(hr);
273 hr = dataReader->ReadString(length, value.GetAddressOf());
274 Q_ASSERT_SUCCEEDED(hr);
275 const QString str = QString::fromWCharArray(WindowsGetStringRawBuffer(value.Get(),
nullptr));
276 info.setAttribute(key, str);
277 qCDebug(QT_BT_WINDOWS) <<
"UUID" << uuid <<
"KEY" << Qt::hex << key <<
"TYPE" << Qt::dec << type <<
"STRING" << str;
280 QBluetoothServiceInfo::Sequence sequence = readSequence(dataReader, &ok,
nullptr);
282 info.setAttribute(key, sequence);
283 qCDebug(QT_BT_WINDOWS) <<
"UUID" << uuid <<
"KEY" << Qt::hex << key <<
"TYPE" << Qt::dec << type <<
"SEQUENCE" << sequence;
285 qCDebug(QT_BT_WINDOWS) <<
"UUID" << uuid <<
"KEY" << Qt::hex << key <<
"TYPE" << Qt::dec << type <<
"SEQUENCE ERROR";
288 qCDebug(QT_BT_WINDOWS) <<
"UUID" << uuid <<
"KEY" << Qt::hex << key <<
"TYPE" << Qt::dec << type;
290 hr = iterator->MoveNext(¤t);
295 if (info.protocolDescriptor(QBluetoothUuid::ProtocolUuid::Rfcomm).isEmpty()) {
296 QBluetoothServiceInfo::Sequence protocolDescriptorList;
297 QBluetoothServiceInfo::Sequence protocol;
298 protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ProtocolUuid::Rfcomm))
299 << QVariant::fromValue(0);
300 protocolDescriptorList.append(QVariant::fromValue(protocol));
301 info.setAttribute(QBluetoothServiceInfo::ProtocolDescriptorList, protocolDescriptorList);
303 emit serviceFound(address, info);
305 emit scanFinished(address);
315 QBluetoothServiceInfo::Sequence result;
319 quint8 remainingLength;
320 HRESULT hr = dataReader->ReadByte(&remainingLength);
321 Q_ASSERT_SUCCEEDED(hr);
325 hr = dataReader->ReadByte(&type);
326 remainingLength -= 1;
329 Q_ASSERT_SUCCEEDED(hr);
334 hr = dataReader->ReadByte(&value);
335 Q_ASSERT_SUCCEEDED(hr);
336 result.append(QVariant::fromValue(value));
337 remainingLength -= 1;
344 hr = dataReader->ReadUInt16(&value);
345 Q_ASSERT_SUCCEEDED(hr);
346 result.append(QVariant::fromValue(value));
347 remainingLength -= 2;
354 hr = dataReader->ReadUInt32(&value);
355 Q_ASSERT_SUCCEEDED(hr);
356 result.append(QVariant::fromValue(value));
357 remainingLength -= 4;
364 hr = dataReader->ReadUInt16(&b);
365 Q_ASSERT_SUCCEEDED(hr);
367 const QBluetoothUuid uuid(b);
368 result.append(QVariant::fromValue(uuid));
369 remainingLength -= 2;
376 hr = dataReader->ReadGuid(&b);
377 Q_ASSERT_SUCCEEDED(hr);
379 reverseArray(b.Data4,
sizeof(b.Data4)/
sizeof(b.Data4[0]));
380 const QBluetoothUuid uuid(b);
381 result.append(QVariant::fromValue(uuid));
382 remainingLength -=
sizeof(GUID);
384 *bytesRead +=
sizeof(GUID);
389 hr = dataReader->ReadByte(&length);
390 Q_ASSERT_SUCCEEDED(hr);
391 remainingLength -= 1;
395 hr = dataReader->ReadString(length, value.GetAddressOf());
396 Q_ASSERT_SUCCEEDED(hr);
398 const QString str = QString::fromWCharArray(WindowsGetStringRawBuffer(value.Get(),
nullptr));
399 result.append(QVariant::fromValue(str));
400 remainingLength -= length;
402 *bytesRead += length;
407 const QBluetoothServiceInfo::Sequence sequence = readSequence(dataReader, ok, &bytesR);
409 result.append(QVariant::fromValue(sequence));
412 remainingLength -= bytesR;
414 *bytesRead += bytesR;
418 qCDebug(QT_BT_WINDOWS) <<
"SEQUENCE ERROR" << type;
422 if (remainingLength == 0)
425 hr = dataReader->ReadByte(&type);
426 Q_ASSERT_SUCCEEDED(hr);
427 remainingLength -= 1;
438 QBluetoothServiceDiscoveryAgent *qp,
const QBluetoothAddress &deviceAdapter)
447 Q_UNUSED(deviceAdapter);
461 worker =
new QWinRTBluetoothServiceDiscoveryWorker(address.toUInt64(), mode);
463 connect(worker, &QWinRTBluetoothServiceDiscoveryWorker::serviceFound,
464 this, &QBluetoothServiceDiscoveryAgentPrivate::processFoundService, Qt::QueuedConnection);
465 connect(worker, &QWinRTBluetoothServiceDiscoveryWorker::scanFinished,
466 this, &QBluetoothServiceDiscoveryAgentPrivate::onScanFinished, Qt::QueuedConnection);
467 connect(worker, &QWinRTBluetoothServiceDiscoveryWorker::errorOccured,
468 this, &QBluetoothServiceDiscoveryAgentPrivate::onError, Qt::QueuedConnection);
475 Q_Q(QBluetoothServiceDiscoveryAgent);
481 Q_Q(QBluetoothServiceDiscoveryAgent);
483 if (!uuidFilter.isEmpty()) {
484 bool serviceNameMatched = uuidFilter.contains(info.serviceUuid());
485 bool serviceClassMatched =
false;
486 const QList<QBluetoothUuid> serviceClassUuids
487 = info.serviceClassUuids();
488 for (
const QBluetoothUuid &id : serviceClassUuids) {
489 if (uuidFilter.contains(id)) {
490 serviceClassMatched =
true;
495 if (!serviceNameMatched && !serviceClassMatched)
504 for (
const QBluetoothDeviceInfo &deviceInfo : std::as_const(discoveredDevices)) {
505 if (deviceInfo.address().toUInt64() == deviceAddress) {
507 returnInfo.setDevice(deviceInfo);
511 Q_ASSERT(deviceFound);
513 if (!isDuplicatedService(returnInfo)) {
514 discoveredServices.append(returnInfo);
515 qCDebug(QT_BT_WINDOWS) <<
"Discovered services" << discoveredDevices.at(0).address().toString()
516 << returnInfo.serviceName() << returnInfo.serviceUuid()
517 <<
">>>" << returnInfo.serviceClassUuids();
519 emit q->serviceDiscovered(returnInfo);
535 Q_Q(QBluetoothServiceDiscoveryAgent);
536 discoveredDevices.clear();
537 error = QBluetoothServiceDiscoveryAgent::InputOutputError;
538 errorString = QStringLiteral(
"errorDescription");
539 emit q->errorOccurred(error);
547 disconnect(worker, &QWinRTBluetoothServiceDiscoveryWorker::serviceFound,
548 this, &QBluetoothServiceDiscoveryAgentPrivate::processFoundService);
549 disconnect(worker, &QWinRTBluetoothServiceDiscoveryWorker::scanFinished,
550 this, &QBluetoothServiceDiscoveryAgentPrivate::onScanFinished);
551 disconnect(worker, &QWinRTBluetoothServiceDiscoveryWorker::errorOccured,
552 this, &QBluetoothServiceDiscoveryAgentPrivate::onError);
559#include <qbluetoothservicediscoveryagent_winrt.moc>
~QBluetoothServiceDiscoveryAgentPrivate()
void _q_serviceDiscoveryFinished()
QBluetoothServiceDiscoveryAgentPrivate(QBluetoothServiceDiscoveryAgent *qp, const QBluetoothAddress &deviceAdapter)
~QWinRTBluetoothServiceDiscoveryWorker()
void scanFinished(quint64 deviceAddress)
Collections::IIterator< ValueItem * > ValueIterator
Collections::IKeyValuePair< UINT32, IBuffer * > ValueItem
static void reverseArray(uchar data[], size_t length)
Collections::IIterable< ValueItem * > ValueIterable
void mainThreadCoInit(void *caller)
void mainThreadCoUninit(void *caller)
QT_BEGIN_NAMESPACE Q_DECLARE_LOGGING_CATEGORY(lcEventDispatcher)