summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDenis Shienkov <denis.shienkov@gmail.com>2015-10-14 18:49:15 +0300
committerDenis Shienkov <denis.shienkov@gmail.com>2015-10-16 09:53:48 +0000
commit4cb5575e9ce38f74c471bbecde139bf4f83fa22f (patch)
tree683c6e70f7d92049f839d8705f5f4a7d0676d672 /src
parente624e7e63c6ac2b330720fea465b05190c70023b (diff)
Windows: Refactor code related to a services discovering
* We do not need QtConcurrent for a services discovering because they returns from a cache immediately. * We don't need to hold the opened device all the time after connection to it. It is enough to open a device only for a some time to request of services. * Now the windows/qwinlowenergybluetooth_p.h file contains only resolved system LE functions and data types. Change-Id: I248666d78cc9141bf987987dfd5dd9280decf4b8 Reviewed-by: Alex Blasche <alexander.blasche@theqtcompany.com>
Diffstat (limited to 'src')
-rw-r--r--src/bluetooth/qlowenergycontroller_p.h15
-rw-r--r--src/bluetooth/qlowenergycontroller_win.cpp241
-rw-r--r--src/bluetooth/windows/qwinlowenergybluetooth.cpp144
-rw-r--r--src/bluetooth/windows/qwinlowenergybluetooth_p.h77
-rw-r--r--src/bluetooth/windows/windows.pri3
5 files changed, 185 insertions, 295 deletions
diff --git a/src/bluetooth/qlowenergycontroller_p.h b/src/bluetooth/qlowenergycontroller_p.h
index 6d81316d..fde057cf 100644
--- a/src/bluetooth/qlowenergycontroller_p.h
+++ b/src/bluetooth/qlowenergycontroller_p.h
@@ -65,12 +65,6 @@ QT_END_NAMESPACE
#include "android/lowenergynotificationhub_p.h"
#endif
-#if defined(Q_OS_WIN32)
-#include <QtConcurrent>
-#include <QtBluetooth/qbluetoothuuid.h>
-#include "windows/qwinlowenergybluetooth_p.h"
-#endif
-
QT_BEGIN_NAMESPACE
#if defined(QT_BLUEZ_BLUETOOTH) && !defined(QT_BLUEZ_NO_BTLE)
@@ -227,15 +221,8 @@ private slots:
void characteristicChanged(int charHandle, const QByteArray &data);
void serviceError(int attributeHandle, QLowEnergyService::ServiceError errorCode);
#elif defined(Q_OS_WIN32)
-private slots:
- void primaryServicesDiscoveryCompleted();
-
private:
- void startDiscoveryOfPrimaryServices();
- bool isConnected() const;
-
- HANDLE hRemoteDevice;
- QFutureWatcher<WinLowEnergyBluetooth::ServicesDiscoveryResult> *primaryServicesDiscoveryWatcher;
+ QString deviceSystemPath;
#endif
private:
QLowEnergyController *q_ptr;
diff --git a/src/bluetooth/qlowenergycontroller_win.cpp b/src/bluetooth/qlowenergycontroller_win.cpp
index ed33c5c8..0f629a0b 100644
--- a/src/bluetooth/qlowenergycontroller_win.cpp
+++ b/src/bluetooth/qlowenergycontroller_win.cpp
@@ -37,17 +37,80 @@
#include <QtCore/QLoggingCategory>
+#include <windows/qwinlowenergybluetooth_p.h>
+
QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINDOWS)
+Q_GLOBAL_STATIC(QLibrary, bluetoothapis)
+
+static bool gattFunctionsResolved = false;
+
+static HANDLE openSystemDevice(const QString &systemPath, int *systemErrorCode)
+{
+ const DWORD desiredAccess = GENERIC_READ | GENERIC_WRITE;
+ const DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+ const HANDLE serviceHandle = ::CreateFile(
+ reinterpret_cast<const wchar_t *>(systemPath.utf16()),
+ desiredAccess,
+ shareMode,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL);
+
+ *systemErrorCode = (INVALID_HANDLE_VALUE == serviceHandle)
+ ? ::GetLastError() : NO_ERROR;
+ return serviceHandle;
+}
+
+static void closeSystemDevice(HANDLE deviceHandle)
+{
+ if (deviceHandle && deviceHandle != INVALID_HANDLE_VALUE)
+ ::CloseHandle(deviceHandle);
+}
+
+static QVector<BTH_LE_GATT_SERVICE> enumeratePrimaryGattServices(
+ HANDLE deviceHandle, int *systemErrorCode)
+{
+ if (!gattFunctionsResolved) {
+ *systemErrorCode = ERROR_NOT_SUPPORTED;
+ return QVector<BTH_LE_GATT_SERVICE>();
+ }
+
+ QVector<BTH_LE_GATT_SERVICE> foundServices;
+ USHORT servicesCount = 0;
+ forever {
+ const HRESULT hr = ::BluetoothGATTGetServices(
+ deviceHandle,
+ servicesCount,
+ foundServices.isEmpty() ? NULL : &foundServices[0],
+ &servicesCount,
+ BLUETOOTH_GATT_FLAG_NONE);
+
+ if (hr == HRESULT_FROM_WIN32(ERROR_MORE_DATA)) {
+ foundServices.resize(servicesCount);
+ } else if (hr == S_OK) {
+ *systemErrorCode = NO_ERROR;
+ return foundServices;
+ } else {
+ *systemErrorCode = ::GetLastError();
+ return QVector<BTH_LE_GATT_SERVICE>();
+ }
+ }
+}
+
QLowEnergyControllerPrivate::QLowEnergyControllerPrivate()
- : QObject(),
- state(QLowEnergyController::UnconnectedState),
- error(QLowEnergyController::NoError),
- hRemoteDevice(INVALID_HANDLE_VALUE),
- primaryServicesDiscoveryWatcher(0)
+ : QObject()
+ , state(QLowEnergyController::UnconnectedState)
+ , error(QLowEnergyController::NoError)
{
+ gattFunctionsResolved = resolveFunctions(bluetoothapis());
+ if (!gattFunctionsResolved) {
+ qCWarning(QT_BT_WINDOWS) << "LE is not supported on this OS";
+ return;
+ }
}
QLowEnergyControllerPrivate::~QLowEnergyControllerPrivate()
@@ -56,8 +119,6 @@ QLowEnergyControllerPrivate::~QLowEnergyControllerPrivate()
void QLowEnergyControllerPrivate::connectToDevice()
{
- Q_Q(QLowEnergyController);
-
// required to pass unit test on default backend
if (remoteDevice.isNull()) {
qWarning() << "Invalid/null remote device address";
@@ -65,78 +126,97 @@ void QLowEnergyControllerPrivate::connectToDevice()
return;
}
- if (!WinLowEnergyBluetooth::isSupported()) {
- qWarning() << "Low energy is not supported by OS";
- setError(QLowEnergyController::UnknownError);
- return;
- }
-
- if (isConnected()) {
+ if (!deviceSystemPath.isEmpty()) {
qCDebug(QT_BT_WINDOWS) << "Already is connected";
return;
}
setState(QLowEnergyController::ConnectingState);
- const QString deviceSystemPath = QBluetoothDeviceDiscoveryAgentPrivate::discoveredLeDeviceSystemPath(remoteDevice);
-
- const DWORD desiredAccess = GENERIC_READ | GENERIC_WRITE;
- const DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
-
- hRemoteDevice = ::CreateFile(
- reinterpret_cast<const wchar_t *>(deviceSystemPath.utf16()),
- desiredAccess,
- shareMode,
- NULL,
- OPEN_EXISTING,
- 0,
- NULL);
+ deviceSystemPath =
+ QBluetoothDeviceDiscoveryAgentPrivate::discoveredLeDeviceSystemPath(
+ remoteDevice);
- if (hRemoteDevice == INVALID_HANDLE_VALUE) {
- qCWarning(QT_BT_WINDOWS) << qt_error_string(::GetLastError());
- setError(QLowEnergyController::ConnectionError);
+ if (deviceSystemPath.isEmpty()) {
+ qCWarning(QT_BT_WINDOWS) << qt_error_string(ERROR_PATH_NOT_FOUND);
+ setError(QLowEnergyController::UnknownRemoteDeviceError);
setState(QLowEnergyController::UnconnectedState);
return;
}
setState(QLowEnergyController::ConnectedState);
+
+ Q_Q(QLowEnergyController);
emit q->connected();
}
void QLowEnergyControllerPrivate::disconnectFromDevice()
{
- Q_Q(QLowEnergyController);
-
- if (!WinLowEnergyBluetooth::isSupported()) {
- qWarning() << "Low energy is not supported by OS";
- setError(QLowEnergyController::UnknownError);
- return;
- }
-
- if (!isConnected()) {
+ if (deviceSystemPath.isEmpty()) {
qCDebug(QT_BT_WINDOWS) << "Already is disconnected";
return;
}
setState(QLowEnergyController::ClosingState);
-
- if (!::CloseHandle(hRemoteDevice))
- qCWarning(QT_BT_WINDOWS) << qt_error_string(::GetLastError());
-
- hRemoteDevice = INVALID_HANDLE_VALUE;
+ deviceSystemPath.clear();
setState(QLowEnergyController::UnconnectedState);
+
+ Q_Q(QLowEnergyController);
emit q->disconnected();
}
void QLowEnergyControllerPrivate::discoverServices()
{
- if (!WinLowEnergyBluetooth::isSupported()) {
- qWarning() << "Low energy is not supported by OS";
- setError(QLowEnergyController::UnknownError);
+ int systemErrorCode = NO_ERROR;
+
+ const HANDLE deviceHandle = openSystemDevice(deviceSystemPath, &systemErrorCode);
+
+ if (systemErrorCode != NO_ERROR) {
+ qCWarning(QT_BT_WINDOWS) << qt_error_string(systemErrorCode);
+ setError(QLowEnergyController::NetworkError);
+ setState(QLowEnergyController::ConnectedState);
+ return;
+ }
+
+ const QVector<BTH_LE_GATT_SERVICE> foundServices =
+ enumeratePrimaryGattServices(deviceHandle, &systemErrorCode);
+
+ closeSystemDevice(deviceHandle);
+
+ if (systemErrorCode != NO_ERROR) {
+ qCWarning(QT_BT_WINDOWS) << qt_error_string(systemErrorCode);
+ setError(QLowEnergyController::NetworkError);
+ setState(QLowEnergyController::ConnectedState);
return;
}
- startDiscoveryOfPrimaryServices();
+ setState(QLowEnergyController::DiscoveringState);
+
+ Q_Q(QLowEnergyController);
+
+ foreach (const BTH_LE_GATT_SERVICE &service, foundServices) {
+
+ const QBluetoothUuid uuid(
+ service.ServiceUuid.IsShortUuid
+ ? QBluetoothUuid(service.ServiceUuid.Value.ShortUuid)
+ : QBluetoothUuid(service.ServiceUuid.Value.LongUuid));
+
+ qCDebug(QT_BT_WINDOWS) << "Found uuid:" << uuid;
+
+ QLowEnergyServicePrivate *priv = new QLowEnergyServicePrivate();
+ priv->uuid = uuid;
+ priv->type = QLowEnergyService::PrimaryService;
+ priv->startHandle = service.AttributeHandle;
+ priv->setController(this);
+
+ QSharedPointer<QLowEnergyServicePrivate> pointer(priv);
+ serviceList.insert(uuid, pointer);
+
+ emit q->serviceDiscovered(uuid);
+ }
+
+ setState(QLowEnergyController::DiscoveredState);
+ emit q->discoveryFinished();
}
void QLowEnergyControllerPrivate::discoverServiceDetails(
@@ -178,69 +258,4 @@ void QLowEnergyControllerPrivate::writeDescriptor(
}
-void QLowEnergyControllerPrivate::primaryServicesDiscoveryCompleted()
-{
- Q_Q(QLowEnergyController);
-
- const WinLowEnergyBluetooth::ServicesDiscoveryResult result =
- primaryServicesDiscoveryWatcher->result();
-
- if (result.error != NO_ERROR) {
- qCWarning(QT_BT_WINDOWS) << qt_error_string(result.error);
- setError(QLowEnergyController::UnknownError);
- return;
- }
-
- foreach (const WinLowEnergyBluetooth::BTH_LE_GATT_SERVICE &service,
- result.services) {
-
- const QBluetoothUuid uuid(
- service.ServiceUuid.IsShortUuid
- ? QBluetoothUuid(service.ServiceUuid.Value.ShortUuid)
- : QBluetoothUuid(service.ServiceUuid.Value.LongUuid));
-
- qCDebug(QT_BT_WINDOWS) << "Found uuid:" << uuid;
-
- QLowEnergyServicePrivate *priv = new QLowEnergyServicePrivate();
- priv->uuid = uuid;
- priv->type = QLowEnergyService::PrimaryService;
- priv->startHandle = service.AttributeHandle;
- priv->setController(this);
-
- QSharedPointer<QLowEnergyServicePrivate> pointer(priv);
-
- serviceList.insert(uuid, pointer);
- emit q->serviceDiscovered(uuid);
- }
-
- setState(QLowEnergyController::DiscoveredState);
- emit q->discoveryFinished();
-}
-
-void QLowEnergyControllerPrivate::startDiscoveryOfPrimaryServices()
-{
- if (!primaryServicesDiscoveryWatcher) {
- primaryServicesDiscoveryWatcher = new QFutureWatcher<
- WinLowEnergyBluetooth::ServicesDiscoveryResult>(this);
-
- connect(primaryServicesDiscoveryWatcher, &QFutureWatcher<WinLowEnergyBluetooth::ServicesDiscoveryResult>::finished,
- this, &QLowEnergyControllerPrivate::primaryServicesDiscoveryCompleted);
- }
-
- if (primaryServicesDiscoveryWatcher->isRunning())
- return;
-
- const QFuture<WinLowEnergyBluetooth::ServicesDiscoveryResult> future =
- QtConcurrent::run(
- WinLowEnergyBluetooth::startDiscoveryOfPrimaryServices,
- hRemoteDevice);
-
- primaryServicesDiscoveryWatcher->setFuture(future);
-}
-
-bool QLowEnergyControllerPrivate::isConnected() const
-{
- return hRemoteDevice && (hRemoteDevice != INVALID_HANDLE_VALUE);
-}
-
QT_END_NAMESPACE
diff --git a/src/bluetooth/windows/qwinlowenergybluetooth.cpp b/src/bluetooth/windows/qwinlowenergybluetooth.cpp
deleted file mode 100644
index 8033a121..00000000
--- a/src/bluetooth/windows/qwinlowenergybluetooth.cpp
+++ /dev/null
@@ -1,144 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Copyright (C) 2014 Denis Shienkov <denis.shienkov@gmail.com>
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL21$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qwinlowenergybluetooth_p.h"
-
-#include <QtCore/quuid.h>
-#include <QtCore/qlibrary.h>
-#include <QtCore/qglobal.h>
-
-QT_BEGIN_NAMESPACE
-
-namespace WinLowEnergyBluetooth {
-
-#define DEFINEFUNC(ret, func, ...) \
- typedef ret (WINAPI *fp_##func)(__VA_ARGS__); \
- static fp_##func func;
-
-#define RESOLVEFUNC(func) \
- func = (fp_##func)resolveFunction(library, #func); \
- if (!func) \
- return false;
-
-DEFINEFUNC(HRESULT, BluetoothGATTGetServices, HANDLE, USHORT, PBTH_LE_GATT_SERVICE, PUSHORT, ULONG)
-DEFINEFUNC(HRESULT, BluetoothGATTGetIncludedServices, HANDLE, PBTH_LE_GATT_SERVICE, USHORT, PBTH_LE_GATT_SERVICE, PUSHORT, ULONG)
-DEFINEFUNC(HRESULT, BluetoothGATTGetCharacteristics, HANDLE, PBTH_LE_GATT_SERVICE, USHORT, PBTH_LE_GATT_CHARACTERISTIC, PUSHORT, ULONG)
-DEFINEFUNC(HRESULT, BluetoothGATTGetDescriptors, HANDLE, PBTH_LE_GATT_CHARACTERISTIC, USHORT, PBTH_LE_GATT_DESCRIPTOR, PUSHORT, ULONG)
-DEFINEFUNC(HRESULT, BluetoothGATTGetCharacteristicValue, HANDLE, PBTH_LE_GATT_CHARACTERISTIC, ULONG, PBTH_LE_GATT_CHARACTERISTIC_VALUE, PUSHORT, ULONG)
-DEFINEFUNC(HRESULT, BluetoothGATTGetDescriptorValue, HANDLE, PBTH_LE_GATT_DESCRIPTOR, ULONG, PBTH_LE_GATT_DESCRIPTOR_VALUE, PUSHORT, ULONG)
-DEFINEFUNC(HRESULT, BluetoothGATTBeginReliableWrite, HANDLE, PBTH_LE_GATT_RELIABLE_WRITE_CONTEXT, ULONG)
-DEFINEFUNC(HRESULT, BluetoothGATTEndReliableWrite, HANDLE, BTH_LE_GATT_RELIABLE_WRITE_CONTEXT, ULONG)
-DEFINEFUNC(HRESULT, BluetoothGATTAbortReliableWrite, HANDLE, BTH_LE_GATT_RELIABLE_WRITE_CONTEXT, ULONG)
-DEFINEFUNC(HRESULT, BluetoothGATTSetCharacteristicValue, HANDLE, PBTH_LE_GATT_CHARACTERISTIC, PBTH_LE_GATT_CHARACTERISTIC_VALUE, BTH_LE_GATT_RELIABLE_WRITE_CONTEXT, ULONG)
-DEFINEFUNC(HRESULT, BluetoothGATTSetDescriptorValue, HANDLE, PBTH_LE_GATT_DESCRIPTOR, PBTH_LE_GATT_DESCRIPTOR_VALUE, ULONG)
-DEFINEFUNC(HRESULT, BluetoothGATTRegisterEvent, HANDLE, BTH_LE_GATT_EVENT_TYPE, PVOID, PFNBLUETOOTH_GATT_EVENT_CALLBACK, PVOID, PHANDLE, ULONG)
-DEFINEFUNC(HRESULT, BluetoothGATTUnregisterEvent, HANDLE, ULONG)
-
-static inline QFunctionPointer resolveFunction(QLibrary *library, const char *func)
-{
- QFunctionPointer symbolFunctionPointer = library->resolve(func);
- if (!symbolFunctionPointer)
- qWarning("Cannot resolve '%s' in '%s'.", func, qPrintable(library->fileName()));
- return symbolFunctionPointer;
-}
-
-static inline bool resolveFunctions(QLibrary *library)
-{
- if (!library->isLoaded()) {
- library->setFileName(QStringLiteral("bluetoothapis"));
- if (!library->load()) {
- qWarning("Unable to load '%s' library.", qPrintable(library->fileName()));
- return false;
- }
- }
-
- RESOLVEFUNC(BluetoothGATTGetServices)
- RESOLVEFUNC(BluetoothGATTGetIncludedServices)
- RESOLVEFUNC(BluetoothGATTGetCharacteristics)
- RESOLVEFUNC(BluetoothGATTGetDescriptors)
- RESOLVEFUNC(BluetoothGATTGetCharacteristicValue)
- RESOLVEFUNC(BluetoothGATTGetDescriptorValue)
- RESOLVEFUNC(BluetoothGATTBeginReliableWrite)
- RESOLVEFUNC(BluetoothGATTEndReliableWrite)
- RESOLVEFUNC(BluetoothGATTAbortReliableWrite)
- RESOLVEFUNC(BluetoothGATTSetCharacteristicValue)
- RESOLVEFUNC(BluetoothGATTSetDescriptorValue)
- RESOLVEFUNC(BluetoothGATTRegisterEvent)
- RESOLVEFUNC(BluetoothGATTUnregisterEvent)
-
- return true;
-}
-
-Q_GLOBAL_STATIC(QLibrary, bluetoothapis)
-
-ServicesDiscoveryResult::ServicesDiscoveryResult()
- : error(NO_ERROR)
-{
-}
-
-ServicesDiscoveryResult startDiscoveryOfPrimaryServices(
- HANDLE hDevice)
-{
- ServicesDiscoveryResult result;
- USHORT servicesCount = 0;
- forever {
- const HRESULT hr = BluetoothGATTGetServices(
- hDevice,
- result.services.count(),
- result.services.isEmpty() ? NULL : &result.services[0],
- &servicesCount,
- BLUETOOTH_GATT_FLAG_NONE);
-
- if (hr == HRESULT_FROM_WIN32(ERROR_MORE_DATA)) {
- result.services.resize(servicesCount);
- } else if (hr == S_OK) {
- break;
- } else {
- result.error = ::GetLastError();
- result.services.clear();
- break;
- }
- }
- return result;
-}
-
-bool isSupported()
-{
- static bool resolved = resolveFunctions(bluetoothapis());
- return resolved;
-}
-
-} // namespace WinLowEnergyBluetooth
-
-QT_END_NAMESPACE
diff --git a/src/bluetooth/windows/qwinlowenergybluetooth_p.h b/src/bluetooth/windows/qwinlowenergybluetooth_p.h
index c591a93d..c12ea4ae 100644
--- a/src/bluetooth/windows/qwinlowenergybluetooth_p.h
+++ b/src/bluetooth/windows/qwinlowenergybluetooth_p.h
@@ -35,17 +35,9 @@
#ifndef QWINLOWENERGYBLUETOOTH_P_H
#define QWINLOWENERGYBLUETOOTH_P_H
-#include <QtCore/qstringlist.h>
-#include <QtCore/qvector.h>
-
-#include <QtBluetooth/qbluetoothaddress.h>
+#include <QtCore/qlibrary.h>
#include <qt_windows.h>
-#include <setupapi.h>
-
-QT_BEGIN_NAMESPACE
-
-namespace WinLowEnergyBluetooth {
#define BLUETOOTH_GATT_FLAG_NONE 0x00000000
#define BLUETOOTH_GATT_FLAG_CONNECTION_ENCRYPTED 0x00000001
@@ -157,19 +149,62 @@ typedef VOID (CALLBACK *PFNBLUETOOTH_GATT_EVENT_CALLBACK)(
typedef ULONG64 BTH_LE_GATT_RELIABLE_WRITE_CONTEXT, *PBTH_LE_GATT_RELIABLE_WRITE_CONTEXT;
-struct ServicesDiscoveryResult
+#define DEFINEFUNC(ret, func, ...) \
+ typedef ret (WINAPI *fp_##func)(__VA_ARGS__); \
+ static fp_##func func;
+
+#define RESOLVEFUNC(func) \
+ func = (fp_##func)resolveFunction(library, #func); \
+ if (!func) \
+ return false;
+
+DEFINEFUNC(HRESULT, BluetoothGATTGetServices, HANDLE, USHORT, PBTH_LE_GATT_SERVICE, PUSHORT, ULONG)
+DEFINEFUNC(HRESULT, BluetoothGATTGetIncludedServices, HANDLE, PBTH_LE_GATT_SERVICE, USHORT, PBTH_LE_GATT_SERVICE, PUSHORT, ULONG)
+DEFINEFUNC(HRESULT, BluetoothGATTGetCharacteristics, HANDLE, PBTH_LE_GATT_SERVICE, USHORT, PBTH_LE_GATT_CHARACTERISTIC, PUSHORT, ULONG)
+DEFINEFUNC(HRESULT, BluetoothGATTGetDescriptors, HANDLE, PBTH_LE_GATT_CHARACTERISTIC, USHORT, PBTH_LE_GATT_DESCRIPTOR, PUSHORT, ULONG)
+DEFINEFUNC(HRESULT, BluetoothGATTGetCharacteristicValue, HANDLE, PBTH_LE_GATT_CHARACTERISTIC, ULONG, PBTH_LE_GATT_CHARACTERISTIC_VALUE, PUSHORT, ULONG)
+DEFINEFUNC(HRESULT, BluetoothGATTGetDescriptorValue, HANDLE, PBTH_LE_GATT_DESCRIPTOR, ULONG, PBTH_LE_GATT_DESCRIPTOR_VALUE, PUSHORT, ULONG)
+DEFINEFUNC(HRESULT, BluetoothGATTBeginReliableWrite, HANDLE, PBTH_LE_GATT_RELIABLE_WRITE_CONTEXT, ULONG)
+DEFINEFUNC(HRESULT, BluetoothGATTEndReliableWrite, HANDLE, BTH_LE_GATT_RELIABLE_WRITE_CONTEXT, ULONG)
+DEFINEFUNC(HRESULT, BluetoothGATTAbortReliableWrite, HANDLE, BTH_LE_GATT_RELIABLE_WRITE_CONTEXT, ULONG)
+DEFINEFUNC(HRESULT, BluetoothGATTSetCharacteristicValue, HANDLE, PBTH_LE_GATT_CHARACTERISTIC, PBTH_LE_GATT_CHARACTERISTIC_VALUE, BTH_LE_GATT_RELIABLE_WRITE_CONTEXT, ULONG)
+DEFINEFUNC(HRESULT, BluetoothGATTSetDescriptorValue, HANDLE, PBTH_LE_GATT_DESCRIPTOR, PBTH_LE_GATT_DESCRIPTOR_VALUE, ULONG)
+DEFINEFUNC(HRESULT, BluetoothGATTRegisterEvent, HANDLE, BTH_LE_GATT_EVENT_TYPE, PVOID, PFNBLUETOOTH_GATT_EVENT_CALLBACK, PVOID, PHANDLE, ULONG)
+DEFINEFUNC(HRESULT, BluetoothGATTUnregisterEvent, HANDLE, ULONG)
+
+static inline QFunctionPointer resolveFunction(QLibrary *library, const char *func)
{
- ServicesDiscoveryResult();
- QVector<BTH_LE_GATT_SERVICE> services;
- DWORD error;
-};
-
-bool isSupported();
+ QFunctionPointer symbolFunctionPointer = library->resolve(func);
+ if (!symbolFunctionPointer)
+ qWarning("Cannot resolve '%s' in '%s'.", func, qPrintable(library->fileName()));
+ return symbolFunctionPointer;
+}
-ServicesDiscoveryResult startDiscoveryOfPrimaryServices(HANDLE hDevice);
-
-} // namespace WinLowEnergyBluetooth
-
-QT_END_NAMESPACE
+static inline bool resolveFunctions(QLibrary *library)
+{
+ if (!library->isLoaded()) {
+ library->setFileName(QStringLiteral("bluetoothapis"));
+ if (!library->load()) {
+ qWarning("Unable to load '%s' library.", qPrintable(library->fileName()));
+ return false;
+ }
+ }
+
+ RESOLVEFUNC(BluetoothGATTGetServices)
+ RESOLVEFUNC(BluetoothGATTGetIncludedServices)
+ RESOLVEFUNC(BluetoothGATTGetCharacteristics)
+ RESOLVEFUNC(BluetoothGATTGetDescriptors)
+ RESOLVEFUNC(BluetoothGATTGetCharacteristicValue)
+ RESOLVEFUNC(BluetoothGATTGetDescriptorValue)
+ RESOLVEFUNC(BluetoothGATTBeginReliableWrite)
+ RESOLVEFUNC(BluetoothGATTEndReliableWrite)
+ RESOLVEFUNC(BluetoothGATTAbortReliableWrite)
+ RESOLVEFUNC(BluetoothGATTSetCharacteristicValue)
+ RESOLVEFUNC(BluetoothGATTSetDescriptorValue)
+ RESOLVEFUNC(BluetoothGATTRegisterEvent)
+ RESOLVEFUNC(BluetoothGATTUnregisterEvent)
+
+ return true;
+}
#endif // QWINLOWENERGYBLUETOOTH_P_H
diff --git a/src/bluetooth/windows/windows.pri b/src/bluetooth/windows/windows.pri
index 019d67e4..bf35eaa4 100644
--- a/src/bluetooth/windows/windows.pri
+++ b/src/bluetooth/windows/windows.pri
@@ -1,5 +1,2 @@
PRIVATE_HEADERS += \
windows/qwinlowenergybluetooth_p.h
-
-SOURCES += \
- windows/qwinlowenergybluetooth.cpp