Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qbluetoothutils_winrt.cpp
Go to the documentation of this file.
1// Copyright (C) 2018 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
5#include <QtBluetooth/private/qtbluetoothglobal_p.h>
6#include <QtCore/private/qfunctions_winrt_p.h>
7#include <QtCore/qhash.h>
8#include <QtCore/QLoggingCategory>
9#include <QtCore/qmutex.h>
10
11#include <robuffer.h>
12#include <wrl.h>
13#include <winrt/windows.foundation.metadata.h>
14#include <windows.storage.streams.h>
15
16using namespace Microsoft::WRL;
17using namespace Microsoft::WRL::Wrappers;
18using namespace winrt::Windows::Foundation::Metadata;
19using namespace ABI::Windows::Storage::Streams;
20
21QT_BEGIN_NAMESPACE
22
23Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINDOWS)
24
25QByteArray byteArrayFromBuffer(const ComPtr<NativeBuffer> &buffer, bool isWCharString)
26{
27 if (!buffer) {
28 qErrnoWarning("nullptr passed to byteArrayFromBuffer");
29 return QByteArray();
30 }
31 ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteAccess;
32 HRESULT hr = buffer.As(&byteAccess);
33 RETURN_IF_FAILED("Could not cast buffer", return QByteArray())
34 char *data;
35 hr = byteAccess->Buffer(reinterpret_cast<byte **>(&data));
36 RETURN_IF_FAILED("Could not obtain buffer data", return QByteArray())
37 UINT32 size;
38 hr = buffer->get_Length(&size);
39 RETURN_IF_FAILED("Could not obtain buffer size", return QByteArray())
40 if (isWCharString) {
41 QString valueString = QString::fromUtf16(reinterpret_cast<char16_t *>(data)).left(size / 2);
42 return valueString.toUtf8();
43 }
44 return QByteArray(data, qint32(size));
45}
46
47static QHash<void *, QThread *> successfulInits;
49
50void threadCoInit(void* caller)
51{
52 Q_ASSERT(caller);
53
54 if (QMutexLocker locker(&initsMutex); successfulInits.contains(caller)) {
55 qCWarning(QT_BT_WINDOWS) << "Multiple COM inits by the same object";
56 return;
57 }
58
59 // This *may* execute in the main thread which may run Gui, so we request
60 // the apartment-threaded model. However, QtBluetooth does not strictly
61 // require it, so if the thread is already initialized with a different
62 // model, that's also totally fine for us.
63 HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
64 if (!SUCCEEDED(hr)) {
65 // RPC_E_CHANGED_MODE means that the thread is already initialized
66 // in a different mode. Do not warn about it.
67 if (hr != RPC_E_CHANGED_MODE)
68 qCWarning(QT_BT_WINDOWS) << "Unexpected COM initialization result";
69 return;
70 }
71
72 QMutexLocker locker(&initsMutex);
73 successfulInits.insert(caller, QThread::currentThread());
74}
75
76void threadCoUninit(void* caller)
77{
78 Q_ASSERT(caller);
79
80 QThread *thread = nullptr;
81 {
82 QMutexLocker locker(&initsMutex);
83 thread = successfulInits.value(caller, nullptr);
84 }
85 // Valid case: thread could be initialized outside of Qt
86 if (!thread)
87 return;
88
89 if (QThread::currentThread() != thread) {
90 qCWarning(QT_BT_WINDOWS) << "COM uninit tried from another thread";
91 return;
92 }
93
94 CoUninitialize();
95
96 QMutexLocker locker(&initsMutex);
97 successfulInits.remove(caller);
98
99}
100
101QT_END_NAMESPACE
static QBasicMutex initsMutex
void threadCoUninit(void *caller)
void threadCoInit(void *caller)