Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qbluetoothservicediscoveryagent_winrt.cpp
Go to the documentation of this file.
1// Copyright (C) 2017 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
7
8#include <QtCore/QLoggingCategory>
9#include <QtCore/private/qfunctions_winrt_p.h>
10
11#include <functional>
12#include <robuffer.h>
13#include <windows.devices.enumeration.h>
14#include <windows.devices.bluetooth.h>
15#include <windows.foundation.collections.h>
16#include <windows.networking.h>
17#include <windows.storage.streams.h>
18#include <wrl.h>
19
20using namespace Microsoft::WRL;
21using namespace Microsoft::WRL::Wrappers;
22using namespace ABI::Windows::Foundation;
23using namespace ABI::Windows::Foundation::Collections;
24using namespace ABI::Windows::Devices;
26using namespace ABI::Windows::Devices::Bluetooth::Rfcomm;
27using namespace ABI::Windows::Devices::Enumeration;
28using namespace ABI::Windows::Storage::Streams;
29
30typedef Collections::IKeyValuePair<UINT32, IBuffer *> ValueItem;
31typedef Collections::IIterable<ValueItem *> ValueIterable;
32typedef Collections::IIterator<ValueItem *> ValueIterator;
33
35
36Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINDOWS)
37
38#define TYPE_UINT8 8
39#define TYPE_UINT16 9
40#define TYPE_UINT32 10
41#define TYPE_SHORT_UUID 25
42#define TYPE_LONG_UUID 28
43#define TYPE_STRING 37
44#define TYPE_SEQUENCE 53
45
46// Helper to reverse given uchar array
47static void reverseArray(uchar data[], size_t length)
48{
49 for (size_t i = length; i > length/2; i--)
50 std::swap(data[length - i], data[i - 1]);
51}
52
54{
56public:
60 void start();
61
63 void serviceFound(quint64 deviceAddress, const QBluetoothServiceInfo &info);
64 void scanFinished(quint64 deviceAddress);
66
67private:
68 HRESULT onBluetoothDeviceFoundAsync(IAsyncOperation<BluetoothDevice *> *op, AsyncStatus status);
69
70 void processServiceSearchResult(quint64 address, ComPtr<IVectorView<RfcommDeviceService*>> services);
71 QBluetoothServiceInfo::Sequence readSequence(ComPtr<IDataReader> dataReader, bool *ok, quint8 *bytesRead);
72
73private:
74 quint64 m_targetAddress;
76};
77
84
88
90{
91 ComPtr<IBluetoothDeviceStatics> deviceStatics;
92 HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Bluetooth_BluetoothDevice).Get(), &deviceStatics);
93 Q_ASSERT_SUCCEEDED(hr);
94 ComPtr<IAsyncOperation<BluetoothDevice *>> deviceFromAddressOperation;
95 hr = deviceStatics->FromBluetoothAddressAsync(m_targetAddress, &deviceFromAddressOperation);
96 Q_ASSERT_SUCCEEDED(hr);
97 hr = deviceFromAddressOperation->put_Completed(Callback<IAsyncOperationCompletedHandler<BluetoothDevice *>>
98 (this, &QWinRTBluetoothServiceDiscoveryWorker::onBluetoothDeviceFoundAsync).Get());
99 Q_ASSERT_SUCCEEDED(hr);
100}
101
102HRESULT QWinRTBluetoothServiceDiscoveryWorker::onBluetoothDeviceFoundAsync(IAsyncOperation<BluetoothDevice *> *op, AsyncStatus status)
103{
104 if (status != Completed) {
105 qCDebug(QT_BT_WINDOWS) << "Could not find device";
107 return S_OK;
108 }
109
110 ComPtr<IBluetoothDevice> device;
111 HRESULT hr;
112 hr = op->GetResults(&device);
113 Q_ASSERT_SUCCEEDED(hr);
115 device->get_BluetoothAddress(&address);
116
117 ComPtr<IBluetoothDevice3> device3;
118 hr = device.As(&device3);
119 Q_ASSERT_SUCCEEDED(hr);
120 ComPtr<IAsyncOperation<RfcommDeviceServicesResult *>> serviceOp;
121 const BluetoothCacheMode cacheMode = m_mode == QBluetoothServiceDiscoveryAgent::MinimalDiscovery
122 ? BluetoothCacheMode_Cached : BluetoothCacheMode_Uncached;
123 hr = device3->GetRfcommServicesWithCacheModeAsync(cacheMode, &serviceOp);
124 Q_ASSERT_SUCCEEDED(hr);
125 hr = serviceOp->put_Completed(Callback<IAsyncOperationCompletedHandler<RfcommDeviceServicesResult *>>
126 ([address, this](IAsyncOperation<RfcommDeviceServicesResult *> *op, AsyncStatus status)
127 {
128 if (status != Completed) {
129 qCDebug(QT_BT_WINDOWS) << "Could not obtain service list";
131 return S_OK;
132 }
133
134 ComPtr<IRfcommDeviceServicesResult> result;
135 HRESULT hr = op->GetResults(&result);
136 Q_ASSERT_SUCCEEDED(hr);
137 ComPtr<IVectorView<RfcommDeviceService*>> commServices;
138 hr = result->get_Services(&commServices);
139 Q_ASSERT_SUCCEEDED(hr);
140 processServiceSearchResult(address, commServices);
141 return S_OK;
142 }).Get());
143 Q_ASSERT_SUCCEEDED(hr);
144
145 return S_OK;
146}
147
148void QWinRTBluetoothServiceDiscoveryWorker::processServiceSearchResult(quint64 address, ComPtr<IVectorView<RfcommDeviceService*>> services)
149{
151 HRESULT hr;
152 hr = services->get_Size(&size);
153 Q_ASSERT_SUCCEEDED(hr);
154 for (quint32 i = 0; i < size; ++i) {
155 ComPtr<IRfcommDeviceService> service;
156 hr = services->GetAt(i, &service);
157 Q_ASSERT_SUCCEEDED(hr);
158 HString name;
159 hr = service->get_ConnectionServiceName(name.GetAddressOf());
160 Q_ASSERT_SUCCEEDED(hr);
161 const QString serviceName = QString::fromWCharArray(WindowsGetStringRawBuffer(name.Get(), nullptr));
162 ComPtr<ABI::Windows::Networking::IHostName> host;
163 hr = service->get_ConnectionHostName(host.GetAddressOf());
164 Q_ASSERT_SUCCEEDED(hr);
165 HString hostName;
166 hr = host->get_RawName(hostName.GetAddressOf());
167 Q_ASSERT_SUCCEEDED(hr);
168 const QString qHostName = QString::fromWCharArray(WindowsGetStringRawBuffer(hostName.Get(),
169 nullptr));
170 ComPtr<IRfcommServiceId> id;
171 hr = service->get_ServiceId(&id);
172 Q_ASSERT_SUCCEEDED(hr);
173 GUID guid;
174 hr = id->get_Uuid(&guid);
175 const QBluetoothUuid uuid(guid);
176 Q_ASSERT_SUCCEEDED(hr);
177
179 info.setAttribute(0xBEEF, QVariant(qHostName));
180 info.setAttribute(0xBEF0, QVariant(serviceName));
181 info.setServiceName(serviceName);
182 info.setServiceUuid(uuid);
183 ComPtr<IAsyncOperation<IMapView<UINT32, IBuffer *> *>> op;
184 hr = service->GetSdpRawAttributesAsync(op.GetAddressOf());
185 if (FAILED(hr)) {
187 qCDebug(QT_BT_WINDOWS) << "Check manifest capabilities";
188 continue;
189 }
190 ComPtr<IMapView<UINT32, IBuffer *>> mapView;
191 hr = QWinRTFunctions::await(op, mapView.GetAddressOf());
192 Q_ASSERT_SUCCEEDED(hr);
193 // TODO timeout
194 ComPtr<ValueIterable> iterable;
195 ComPtr<ValueIterator> iterator;
196
197 hr = mapView.As(&iterable);
198 if (FAILED(hr))
199 continue;
200
201 boolean current = false;
202 hr = iterable->First(&iterator);
203 if (FAILED(hr))
204 continue;
205 hr = iterator->get_HasCurrent(&current);
206 if (FAILED(hr))
207 continue;
208
209 while (SUCCEEDED(hr) && current) {
210 ComPtr<ValueItem> item;
211 hr = iterator->get_Current(&item);
212 if (FAILED(hr))
213 continue;
214
215 UINT32 key;
216 hr = item->get_Key(&key);
217 if (FAILED(hr))
218 continue;
219
220 ComPtr<IBuffer> buffer;
221 hr = item->get_Value(&buffer);
222 Q_ASSERT_SUCCEEDED(hr);
223
224 ComPtr<IDataReader> dataReader;
225 ComPtr<IDataReaderStatics> dataReaderStatics;
226 hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_DataReader).Get(), &dataReaderStatics);
227 Q_ASSERT_SUCCEEDED(hr);
228 hr = dataReaderStatics->FromBuffer(buffer.Get(), dataReader.GetAddressOf());
229 Q_ASSERT_SUCCEEDED(hr);
230 BYTE type;
231 hr = dataReader->ReadByte(&type);
232 Q_ASSERT_SUCCEEDED(hr);
233 if (type == TYPE_UINT8) {
235 hr = dataReader->ReadByte(&value);
236 Q_ASSERT_SUCCEEDED(hr);
237 info.setAttribute(key, value);
238 qCDebug(QT_BT_WINDOWS) << "UUID" << uuid << "KEY" << Qt::hex << key << "TYPE" << Qt::dec << type << "UINT8" << Qt::hex << value;
239 } else if (type == TYPE_UINT16) {
241 hr = dataReader->ReadUInt16(&value);
242 Q_ASSERT_SUCCEEDED(hr);
243 info.setAttribute(key, value);
244 qCDebug(QT_BT_WINDOWS) << "UUID" << uuid << "KEY" << Qt::hex << key << "TYPE" << Qt::dec << type << "UINT16" << Qt::hex << value;
245 } else if (type == TYPE_UINT32) {
247 hr = dataReader->ReadUInt32(&value);
248 Q_ASSERT_SUCCEEDED(hr);
249 info.setAttribute(key, value);
250 qCDebug(QT_BT_WINDOWS) << "UUID" << uuid << "KEY" << Qt::hex << key << "TYPE" << Qt::dec << type << "UINT32" << Qt::hex << value;
251 } else if (type == TYPE_SHORT_UUID) {
253 hr = dataReader->ReadUInt16(&value);
254 Q_ASSERT_SUCCEEDED(hr);
255 const QBluetoothUuid uuid(value);
256 info.setAttribute(key, uuid);
257 qCDebug(QT_BT_WINDOWS) << "UUID" << uuid << "KEY" << Qt::hex << key << "TYPE" << Qt::dec << type << "UUID" << Qt::hex << uuid;
258 } else if (type == TYPE_LONG_UUID) {
259 GUID value;
260 hr = dataReader->ReadGuid(&value);
261 Q_ASSERT_SUCCEEDED(hr);
262 // The latter 8 bytes are in reverse order
263 reverseArray(value.Data4, sizeof(value.Data4)/sizeof(value.Data4[0]));
264 const QBluetoothUuid uuid(value);
265 info.setAttribute(key, uuid);
266 qCDebug(QT_BT_WINDOWS) << "UUID" << uuid << "KEY" << Qt::hex << key << "TYPE" << Qt::dec << type << "UUID" << Qt::hex << uuid;
267 } else if (type == TYPE_STRING) {
268 BYTE length;
269 hr = dataReader->ReadByte(&length);
270 Q_ASSERT_SUCCEEDED(hr);
271 HString value;
272 hr = dataReader->ReadString(length, value.GetAddressOf());
273 Q_ASSERT_SUCCEEDED(hr);
274 const QString str = QString::fromWCharArray(WindowsGetStringRawBuffer(value.Get(), nullptr));
275 info.setAttribute(key, str);
276 qCDebug(QT_BT_WINDOWS) << "UUID" << uuid << "KEY" << Qt::hex << key << "TYPE" << Qt::dec << type << "STRING" << str;
277 } else if (type == TYPE_SEQUENCE) {
278 bool ok;
279 QBluetoothServiceInfo::Sequence sequence = readSequence(dataReader, &ok, nullptr);
280 if (ok) {
281 info.setAttribute(key, sequence);
282 qCDebug(QT_BT_WINDOWS) << "UUID" << uuid << "KEY" << Qt::hex << key << "TYPE" << Qt::dec << type << "SEQUENCE" << sequence;
283 } else {
284 qCDebug(QT_BT_WINDOWS) << "UUID" << uuid << "KEY" << Qt::hex << key << "TYPE" << Qt::dec << type << "SEQUENCE ERROR";
285 }
286 } else {
287 qCDebug(QT_BT_WINDOWS) << "UUID" << uuid << "KEY" << Qt::hex << key << "TYPE" << Qt::dec << type;
288 }
289 hr = iterator->MoveNext(&current);
290 }
291 // Windows is only able to discover Rfcomm services but the according protocolDescriptor is
292 // not always set in the raw attribute map. If we encounter a service like that we should
293 // fill the protocol descriptor ourselves.
294 if (info.protocolDescriptor(QBluetoothUuid::ProtocolUuid::Rfcomm).isEmpty()) {
295 QBluetoothServiceInfo::Sequence protocolDescriptorList;
299 protocolDescriptorList.append(QVariant::fromValue(protocol));
300 info.setAttribute(QBluetoothServiceInfo::ProtocolDescriptorList, protocolDescriptorList);
301 }
303 }
305 deleteLater();
306}
307
308QBluetoothServiceInfo::Sequence QWinRTBluetoothServiceDiscoveryWorker::readSequence(ComPtr<IDataReader> dataReader, bool *ok, quint8 *bytesRead)
309{
310 if (ok)
311 *ok = false;
312 if (bytesRead)
313 *bytesRead = 0;
315 if (!dataReader)
316 return result;
317
318 quint8 remainingLength;
319 HRESULT hr = dataReader->ReadByte(&remainingLength);
320 Q_ASSERT_SUCCEEDED(hr);
321 if (bytesRead)
322 *bytesRead += 1;
323 BYTE type;
324 hr = dataReader->ReadByte(&type);
325 remainingLength -= 1;
326 if (bytesRead)
327 *bytesRead += 1;
328 Q_ASSERT_SUCCEEDED(hr);
329 while (true) {
330 switch (type) {
331 case TYPE_UINT8: {
333 hr = dataReader->ReadByte(&value);
334 Q_ASSERT_SUCCEEDED(hr);
336 remainingLength -= 1;
337 if (bytesRead)
338 *bytesRead += 1;
339 break;
340 }
341 case TYPE_UINT16: {
343 hr = dataReader->ReadUInt16(&value);
344 Q_ASSERT_SUCCEEDED(hr);
346 remainingLength -= 2;
347 if (bytesRead)
348 *bytesRead += 2;
349 break;
350 }
351 case TYPE_UINT32: {
353 hr = dataReader->ReadUInt32(&value);
354 Q_ASSERT_SUCCEEDED(hr);
356 remainingLength -= 4;
357 if (bytesRead)
358 *bytesRead += 4;
359 break;
360 }
361 case TYPE_SHORT_UUID: {
362 quint16 b;
363 hr = dataReader->ReadUInt16(&b);
364 Q_ASSERT_SUCCEEDED(hr);
365
366 const QBluetoothUuid uuid(b);
367 result.append(QVariant::fromValue(uuid));
368 remainingLength -= 2;
369 if (bytesRead)
370 *bytesRead += 2;
371 break;
372 }
373 case TYPE_LONG_UUID: {
374 GUID b;
375 hr = dataReader->ReadGuid(&b);
376 Q_ASSERT_SUCCEEDED(hr);
377 // The latter 8 bytes are in reverse order
378 reverseArray(b.Data4, sizeof(b.Data4)/sizeof(b.Data4[0]));
379 const QBluetoothUuid uuid(b);
380 result.append(QVariant::fromValue(uuid));
381 remainingLength -= sizeof(GUID);
382 if (bytesRead)
383 *bytesRead += sizeof(GUID);
384 break;
385 }
386 case TYPE_STRING: {
387 BYTE length;
388 hr = dataReader->ReadByte(&length);
389 Q_ASSERT_SUCCEEDED(hr);
390 remainingLength -= 1;
391 if (bytesRead)
392 *bytesRead += 1;
393 HString value;
394 hr = dataReader->ReadString(length, value.GetAddressOf());
395 Q_ASSERT_SUCCEEDED(hr);
396
397 const QString str = QString::fromWCharArray(WindowsGetStringRawBuffer(value.Get(), nullptr));
399 remainingLength -= length;
400 if (bytesRead)
401 *bytesRead += length;
402 break;
403 }
404 case TYPE_SEQUENCE: {
405 quint8 bytesR;
406 const QBluetoothServiceInfo::Sequence sequence = readSequence(dataReader, ok, &bytesR);
407 if (*ok)
408 result.append(QVariant::fromValue(sequence));
409 else
410 return result;
411 remainingLength -= bytesR;
412 if (bytesRead)
413 *bytesRead += bytesR;
414 break;
415 }
416 default:
417 qCDebug(QT_BT_WINDOWS) << "SEQUENCE ERROR" << type;
418 result.clear();
419 return result;
420 }
421 if (remainingLength == 0)
422 break;
423
424 hr = dataReader->ReadByte(&type);
425 Q_ASSERT_SUCCEEDED(hr);
426 remainingLength -= 1;
427 if (bytesRead)
428 *bytesRead += 1;
429 }
430
431 if (ok)
432 *ok = true;
433 return result;
434}
435
437 QBluetoothServiceDiscoveryAgent *qp, const QBluetoothAddress &deviceAdapter)
439 state(Inactive),
440 mode(QBluetoothServiceDiscoveryAgent::MinimalDiscovery),
441 singleDevice(false),
442 q_ptr(qp)
443{
444 mainThreadCoInit(this);
445 // TODO: use local adapter for discovery. Possible?
446 Q_UNUSED(deviceAdapter);
447}
448
450{
451 releaseWorker();
452 mainThreadCoUninit(this);
453}
454
455void QBluetoothServiceDiscoveryAgentPrivate::start(const QBluetoothAddress &address)
456{
457 if (worker)
458 return;
459
460 worker = new QWinRTBluetoothServiceDiscoveryWorker(address.toUInt64(), mode);
461
463 this, &QBluetoothServiceDiscoveryAgentPrivate::processFoundService, Qt::QueuedConnection);
465 this, &QBluetoothServiceDiscoveryAgentPrivate::onScanFinished, Qt::QueuedConnection);
467 this, &QBluetoothServiceDiscoveryAgentPrivate::onError, Qt::QueuedConnection);
468 worker->start();
469}
470
471void QBluetoothServiceDiscoveryAgentPrivate::stop()
472{
473 releaseWorker();
475 emit q->canceled();
476}
477
478void QBluetoothServiceDiscoveryAgentPrivate::processFoundService(quint64 deviceAddress, const QBluetoothServiceInfo &info)
479{
481 //apply uuidFilter
482 if (!uuidFilter.isEmpty()) {
483 bool serviceNameMatched = uuidFilter.contains(info.serviceUuid());
484 bool serviceClassMatched = false;
485 const QList<QBluetoothUuid> serviceClassUuids
486 = info.serviceClassUuids();
487 for (const QBluetoothUuid &id : serviceClassUuids) {
488 if (uuidFilter.contains(id)) {
489 serviceClassMatched = true;
490 break;
491 }
492 }
493
494 if (!serviceNameMatched && !serviceClassMatched)
495 return;
496 }
497
498 if (!info.isValid())
499 return;
500
501 QBluetoothServiceInfo returnInfo(info);
502 bool deviceFound;
503 for (const QBluetoothDeviceInfo &deviceInfo : std::as_const(discoveredDevices)) {
504 if (deviceInfo.address().toUInt64() == deviceAddress) {
505 deviceFound = true;
506 returnInfo.setDevice(deviceInfo);
507 break;
508 }
509 }
510 Q_ASSERT(deviceFound);
511
512 if (!isDuplicatedService(returnInfo)) {
513 discoveredServices.append(returnInfo);
514 qCDebug(QT_BT_WINDOWS) << "Discovered services" << discoveredDevices.at(0).address().toString()
515 << returnInfo.serviceName() << returnInfo.serviceUuid()
516 << ">>>" << returnInfo.serviceClassUuids();
517
518 emit q->serviceDiscovered(returnInfo);
519 }
520}
521
522void QBluetoothServiceDiscoveryAgentPrivate::onScanFinished(quint64 deviceAddress)
523{
524 // The scan for a device's services has finished. Disconnect the
525 // worker and call the baseclass function which starts the scan for
526 // the next device if there are any unscanned devices left (or finishes
527 // the scan if none left)
528 releaseWorker();
530}
531
532void QBluetoothServiceDiscoveryAgentPrivate::onError()
533{
537 errorString = QStringLiteral("errorDescription");
538 emit q->errorOccurred(error);
539}
540
541void QBluetoothServiceDiscoveryAgentPrivate::releaseWorker()
542{
543 if (!worker)
544 return;
545
547 this, &QBluetoothServiceDiscoveryAgentPrivate::processFoundService);
549 this, &QBluetoothServiceDiscoveryAgentPrivate::onScanFinished);
551 this, &QBluetoothServiceDiscoveryAgentPrivate::onError);
552 // mWorker will delete itself as soon as it is done with its discovery
553 worker = nullptr;
554}
555
557
558#include <qbluetoothservicediscoveryagent_winrt.moc>
IOBluetoothDevice * device
std::vector< ObjCStrongReference< CBMutableService > > services
\inmodule QtBluetooth
\inmodule QtBluetooth
QBluetoothAddress address() const
Returns the address of the device.
QBluetoothServiceDiscoveryAgentPrivate(QBluetoothServiceDiscoveryAgent *qp, const QBluetoothAddress &deviceAdapter)
DiscoveryMode
This enum describes the service discovery mode.
\inmodule QtBluetooth
\inmodule QtBluetooth
bool isEmpty() const noexcept
Definition qlist.h:401
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
void append(parameter_type t)
Definition qlist.h:458
void clear()
Definition qlist.h:434
\inmodule QtCore
Definition qobject.h:103
void deleteLater()
\threadsafe
Definition qobject.cpp:2435
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString fromWCharArray(const wchar_t *string, qsizetype size=-1)
Definition qstring.h:1309
\inmodule QtCore
Definition qvariant.h:65
static auto fromValue(T &&value) noexcept(std::is_nothrow_copy_constructible_v< T > &&Private::CanUseInternalSpace< T >) -> std::enable_if_t< std::conjunction_v< std::is_copy_constructible< T >, std::is_destructible< T > >, QVariant >
Definition qvariant.h:536
QWinRTBluetoothServiceDiscoveryWorker(quint64 targetAddress, QBluetoothServiceDiscoveryAgent::DiscoveryMode mode)
void scanFinished(quint64 deviceAddress)
void serviceFound(quint64 deviceAddress, const QBluetoothServiceInfo &info)
QString str
[2]
else opt state
[0]
typename C::iterator iterator
Combined button and popup list for selecting options.
Q_CORE_EXPORT QtJniTypes::Service service()
QTextStream & hex(QTextStream &stream)
Calls QTextStream::setIntegerBase(16) on stream and returns stream.
QTextStream & dec(QTextStream &stream)
Calls QTextStream::setIntegerBase(10) on stream and returns stream.
@ QueuedConnection
Collections::IKeyValuePair< UINT32, IBuffer * > ValueItem
Collections::IIterable< ValueItem * > ValueIterable
Collections::IIterator< ValueItem * > ValueIterator
static void reverseArray(uchar data[], size_t length)
void mainThreadCoInit(void *caller)
void mainThreadCoUninit(void *caller)
DBusConnection const char DBusError * error
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define qCDebug(category,...)
#define Q_DECLARE_LOGGING_CATEGORY(name)
GLboolean GLboolean GLboolean b
GLenum mode
GLuint64 key
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum GLuint GLenum GLsizei length
GLenum GLuint id
[7]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLuint buffer
GLenum type
GLuint name
GLuint GLuint64EXT address
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLuint64EXT * result
[6]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define QStringLiteral(str)
@ NoError
Definition main.cpp:34
#define Q_OBJECT
#define Q_SIGNALS
#define emit
#define Q_UNUSED(x)
unsigned int quint32
Definition qtypes.h:50
unsigned char uchar
Definition qtypes.h:32
unsigned short quint16
Definition qtypes.h:48
unsigned long long quint64
Definition qtypes.h:61
unsigned char quint8
Definition qtypes.h:46
long HRESULT
connect(quitButton, &QPushButton::clicked, &app, &QCoreApplication::quit, Qt::QueuedConnection)
myObject disconnect()
[26]
QGraphicsItem * item
QHostInfo info
[0]
bool contains(const AT &t) const noexcept
Definition qlist.h:45