summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.qmake.conf4
-rw-r--r--examples/serialport/blockingslave/dialog.cpp3
-rw-r--r--examples/serialport/cenumerator/main.cpp3
-rw-r--r--examples/serialport/enumerator/main.cpp3
-rw-r--r--src/serialport/qserialport.cpp6
-rw-r--r--src/serialport/qserialport.h1
-rw-r--r--src/serialport/qserialport_p.h18
-rw-r--r--src/serialport/qserialport_win.cpp364
-rw-r--r--src/serialport/qserialportinfo.cpp1
-rw-r--r--src/serialport/qtntdll_p.h158
-rw-r--r--src/serialport/qwinoverlappedionotifier_p.h91
-rw-r--r--src/serialport/serialport-lib.pri3
-rw-r--r--tests/auto/qserialport/tst_qserialport.cpp8
13 files changed, 435 insertions, 228 deletions
diff --git a/.qmake.conf b/.qmake.conf
index 1ed62c5..f6895bb 100644
--- a/.qmake.conf
+++ b/.qmake.conf
@@ -1,3 +1,5 @@
load(qt_build_config)
-MODULE_VERSION = 5.13.1
+DEFINES += QT_NO_FOREACH QT_NO_JAVA_STYLE_ITERATORS QT_NO_LINKED_LIST
+
+MODULE_VERSION = 5.14.0
diff --git a/examples/serialport/blockingslave/dialog.cpp b/examples/serialport/blockingslave/dialog.cpp
index 1723086..b95f3e7 100644
--- a/examples/serialport/blockingslave/dialog.cpp
+++ b/examples/serialport/blockingslave/dialog.cpp
@@ -99,8 +99,7 @@ Dialog::Dialog(QWidget *parent) :
connect(m_serialPortComboBox, QOverload<const QString &>::of(&QComboBox::currentIndexChanged),
this, &Dialog::activateRunButton);
- connect(m_waitRequestSpinBox, QOverload<const QString &>::of(&QSpinBox::valueChanged),
- this, &Dialog::activateRunButton);
+ connect(m_waitRequestSpinBox, &QSpinBox::textChanged, this, &Dialog::activateRunButton);
connect(m_responseLineEdit, &QLineEdit::textChanged, this, &Dialog::activateRunButton);
}
diff --git a/examples/serialport/cenumerator/main.cpp b/examples/serialport/cenumerator/main.cpp
index af6d7e4..902a793 100644
--- a/examples/serialport/cenumerator/main.cpp
+++ b/examples/serialport/cenumerator/main.cpp
@@ -80,8 +80,7 @@ int main(int argc, char *argv[])
: blankString) << endl
<< "Product Identifier: " << (serialPortInfo.hasProductIdentifier()
? QByteArray::number(serialPortInfo.productIdentifier(), 16)
- : blankString) << endl
- << "Busy: " << (serialPortInfo.isBusy() ? "Yes" : "No") << endl;
+ : blankString) << endl;
}
return 0;
diff --git a/examples/serialport/enumerator/main.cpp b/examples/serialport/enumerator/main.cpp
index fef1ce0..ee21351 100644
--- a/examples/serialport/enumerator/main.cpp
+++ b/examples/serialport/enumerator/main.cpp
@@ -70,8 +70,7 @@ int main(int argc, char *argv[])
+ QObject::tr("Manufacturer: ") + info.manufacturer() + "\n"
+ QObject::tr("Serial number: ") + info.serialNumber() + "\n"
+ QObject::tr("Vendor Identifier: ") + (info.hasVendorIdentifier() ? QString::number(info.vendorIdentifier(), 16) : QString()) + "\n"
- + QObject::tr("Product Identifier: ") + (info.hasProductIdentifier() ? QString::number(info.productIdentifier(), 16) : QString()) + "\n"
- + QObject::tr("Busy: ") + (info.isBusy() ? QObject::tr("Yes") : QObject::tr("No")) + "\n";
+ + QObject::tr("Product Identifier: ") + (info.hasProductIdentifier() ? QString::number(info.productIdentifier(), 16) : QString()) + "\n";
auto label = new QLabel(s);
layout->addWidget(label);
diff --git a/src/serialport/qserialport.cpp b/src/serialport/qserialport.cpp
index 7732855..44d6cd1 100644
--- a/src/serialport/qserialport.cpp
+++ b/src/serialport/qserialport.cpp
@@ -102,7 +102,9 @@ void QSerialPortPrivate::setError(const QSerialPortErrorInfo &errorInfo)
error = errorInfo.errorCode;
q->setErrorString(errorInfo.errorString);
emit q->errorOccurred(error);
+#if QT_DEPRECATED_SINCE(5, 8)
emit q->error(error);
+#endif
}
/*!
@@ -347,6 +349,7 @@ void QSerialPortPrivate::setError(const QSerialPortErrorInfo &errorInfo)
QSerialPort::requestToSend
*/
+#if QT_DEPRECATED_SINCE(5, 2)
/*!
\enum QSerialPort::DataErrorPolicy
\obsolete
@@ -362,6 +365,7 @@ void QSerialPortPrivate::setError(const QSerialPortErrorInfo &errorInfo)
\sa QSerialPort::dataErrorPolicy
*/
+#endif
/*!
\enum QSerialPort::SerialPortError
@@ -1162,12 +1166,14 @@ void QSerialPort::clearError()
d->setError(QSerialPortErrorInfo(QSerialPort::NoError));
}
+#if QT_DEPRECATED_SINCE(5, 8)
/*!
\fn void QSerialPort::error(SerialPortError error)
\obsolete
Use errorOccurred() instead.
*/
+#endif
/*!
\fn void QSerialPort::errorOccurred(SerialPortError error)
diff --git a/src/serialport/qserialport.h b/src/serialport/qserialport.h
index 9a5c1d0..c4c7367 100644
--- a/src/serialport/qserialport.h
+++ b/src/serialport/qserialport.h
@@ -306,7 +306,6 @@ private:
#if defined(Q_OS_WIN32)
Q_PRIVATE_SLOT(d_func(), bool _q_startAsyncWrite())
- Q_PRIVATE_SLOT(d_func(), void _q_notified(quint32, quint32, OVERLAPPED*))
#endif
};
diff --git a/src/serialport/qserialport_p.h b/src/serialport/qserialport_p.h
index b0955ae..7348aed 100644
--- a/src/serialport/qserialport_p.h
+++ b/src/serialport/qserialport_p.h
@@ -104,7 +104,6 @@ struct serial_struct {
QT_BEGIN_NAMESPACE
-class QWinOverlappedIoNotifier;
class QTimer;
class QSocketNotifier;
@@ -182,7 +181,6 @@ public:
bool setDcb(DCB *dcb);
bool getDcb(DCB *dcb);
- OVERLAPPED *waitForNotified(QDeadlineTimer deadline);
qint64 queuedBytesCount(QSerialPort::Direction direction) const;
@@ -192,10 +190,15 @@ public:
bool startAsyncCommunication();
bool _q_startAsyncWrite();
- void _q_notified(DWORD numberOfBytes, DWORD errorCode, OVERLAPPED *overlapped);
+ void handleNotification(DWORD bytesTransferred, DWORD errorCode,
+ OVERLAPPED *overlapped);
void emitReadyRead();
+ static void CALLBACK ioCompletionRoutine(
+ DWORD errorCode, DWORD bytesTransfered,
+ OVERLAPPED *overlappedBase);
+
DCB restoredDcb;
COMMTIMEOUTS currentCommTimeouts;
COMMTIMEOUTS restoredCommTimeouts;
@@ -205,11 +208,12 @@ public:
bool communicationStarted = false;
bool writeStarted = false;
bool readStarted = false;
- QWinOverlappedIoNotifier *notifier = nullptr;
+ qint64 writeBytesTransferred = 0;
+ qint64 readBytesTransferred = 0;
QTimer *startAsyncWriteTimer = nullptr;
- OVERLAPPED communicationOverlapped;
- OVERLAPPED readCompletionOverlapped;
- OVERLAPPED writeCompletionOverlapped;
+ class Overlapped *communicationCompletionOverlapped = nullptr;
+ class Overlapped *readCompletionOverlapped = nullptr;
+ class Overlapped *writeCompletionOverlapped = nullptr;
DWORD triggeredEventMask = 0;
#elif defined(Q_OS_UNIX)
diff --git a/src/serialport/qserialport_win.cpp b/src/serialport/qserialport_win.cpp
index 85dd8ee..da1e7aa 100644
--- a/src/serialport/qserialport_win.cpp
+++ b/src/serialport/qserialport_win.cpp
@@ -40,45 +40,15 @@
****************************************************************************/
#include "qserialport_p.h"
-#include "qwinoverlappedionotifier_p.h"
+#include "qtntdll_p.h"
#include <QtCore/qcoreevent.h>
#include <QtCore/qelapsedtimer.h>
-#include <QtCore/qvector.h>
+#include <QtCore/qmutex.h>
#include <QtCore/qtimer.h>
+#include <QtCore/qvector.h>
#include <algorithm>
-#ifndef CTL_CODE
-# define CTL_CODE(DeviceType, Function, Method, Access) ( \
- ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \
- )
-#endif
-
-#ifndef FILE_DEVICE_SERIAL_PORT
-# define FILE_DEVICE_SERIAL_PORT 27
-#endif
-
-#ifndef METHOD_BUFFERED
-# define METHOD_BUFFERED 0
-#endif
-
-#ifndef FILE_ANY_ACCESS
-# define FILE_ANY_ACCESS 0x00000000
-#endif
-
-#ifndef IOCTL_SERIAL_GET_DTRRTS
-# define IOCTL_SERIAL_GET_DTRRTS \
- CTL_CODE(FILE_DEVICE_SERIAL_PORT, 30, METHOD_BUFFERED, FILE_ANY_ACCESS)
-#endif
-
-#ifndef SERIAL_DTR_STATE
-# define SERIAL_DTR_STATE 0x00000001
-#endif
-
-#ifndef SERIAL_RTS_STATE
-# define SERIAL_RTS_STATE 0x00000002
-#endif
-
QT_BEGIN_NAMESPACE
static inline void qt_set_common_props(DCB *dcb)
@@ -173,8 +143,117 @@ static inline void qt_set_flowcontrol(DCB *dcb, QSerialPort::FlowControl flowcon
}
}
+// Translate NT-callbacks to Win32 callbacks.
+static VOID WINAPI qt_apc_routine(
+ PVOID context,
+ PIO_STATUS_BLOCK ioStatusBlock,
+ DWORD reserved)
+{
+ Q_UNUSED(reserved);
+
+ const DWORD errorCode = ::RtlNtStatusToDosError(ioStatusBlock->Status);
+ const DWORD bytesTransfered = NT_SUCCESS(ioStatusBlock->Status)
+ ? DWORD(ioStatusBlock->Information) : 0;
+ const LPOVERLAPPED overlapped = CONTAINING_RECORD(ioStatusBlock,
+ OVERLAPPED, Internal);
+
+ (reinterpret_cast<LPOVERLAPPED_COMPLETION_ROUTINE>(context))
+ (errorCode, bytesTransfered, overlapped);
+}
+
+// Alertable analog of DeviceIoControl function.
+static BOOL qt_device_io_control_ex(
+ HANDLE deviceHandle,
+ DWORD ioControlCode,
+ LPVOID inputBuffer,
+ DWORD inputBufferSize,
+ LPVOID outputBuffer,
+ DWORD outputBufferSize,
+ LPOVERLAPPED overlapped,
+ LPOVERLAPPED_COMPLETION_ROUTINE completionRoutine)
+{
+ const auto ioStatusBlock = reinterpret_cast<PIO_STATUS_BLOCK>(
+ &overlapped->Internal);
+ ioStatusBlock->Status = STATUS_PENDING;
+
+ const NTSTATUS status = ::NtDeviceIoControlFile(
+ deviceHandle,
+ nullptr,
+ qt_apc_routine,
+ reinterpret_cast<PVOID>(completionRoutine),
+ ioStatusBlock,
+ ioControlCode,
+ inputBuffer,
+ inputBufferSize,
+ outputBuffer,
+ outputBufferSize);
+
+ if (!NT_SUCCESS(status)) {
+ ::SetLastError(::RtlNtStatusToDosError(status));
+ return false;
+ }
+
+ return true;
+}
+
+// Alertable analog of WaitCommEvent function.
+static BOOL qt_wait_comm_event_ex(
+ HANDLE deviceHandle,
+ LPDWORD eventsMask,
+ LPOVERLAPPED overlapped,
+ LPOVERLAPPED_COMPLETION_ROUTINE completionRoutine)
+{
+ return qt_device_io_control_ex(
+ deviceHandle,
+ IOCTL_SERIAL_WAIT_ON_MASK,
+ nullptr,
+ 0,
+ eventsMask,
+ sizeof(DWORD),
+ overlapped,
+ completionRoutine);
+}
+
+struct RuntimeHelper
+{
+ QLibrary ntLibrary;
+ QBasicMutex mutex;
+};
+
+Q_GLOBAL_STATIC(RuntimeHelper, helper)
+
+class Overlapped final : public OVERLAPPED
+{
+ Q_DISABLE_COPY(Overlapped)
+public:
+ explicit Overlapped(QSerialPortPrivate *d);
+ void clear();
+
+ QSerialPortPrivate *dptr = nullptr;
+};
+
+Overlapped::Overlapped(QSerialPortPrivate *d)
+ : dptr(d)
+{
+}
+
+void Overlapped::clear()
+{
+ ::ZeroMemory(this, sizeof(OVERLAPPED));
+}
+
bool QSerialPortPrivate::open(QIODevice::OpenMode mode)
{
+ {
+ QMutexLocker locker(&helper()->mutex);
+ static bool symbolsResolved = resolveSymbols(&helper()->ntLibrary);
+ if (!symbolsResolved) {
+ setError(QSerialPortErrorInfo(QSerialPort::OpenError,
+ helper()->ntLibrary.errorString()));
+ return false;
+ }
+ }
+
DWORD desiredAccess = 0;
if (mode & QIODevice::ReadOnly)
@@ -199,17 +278,44 @@ bool QSerialPortPrivate::open(QIODevice::OpenMode mode)
void QSerialPortPrivate::close()
{
- ::CancelIo(handle);
-
- delete notifier;
- notifier = nullptr;
-
delete startAsyncWriteTimer;
startAsyncWriteTimer = nullptr;
- communicationStarted = false;
- readStarted = false;
- writeStarted = false;
+ if (communicationStarted) {
+ communicationCompletionOverlapped->dptr = nullptr;
+ ::CancelIoEx(handle, communicationCompletionOverlapped);
+ // The object will be deleted in the I/O callback.
+ communicationCompletionOverlapped = nullptr;
+ communicationStarted = false;
+ } else {
+ delete communicationCompletionOverlapped;
+ communicationCompletionOverlapped = nullptr;
+ }
+
+ if (readStarted) {
+ readCompletionOverlapped->dptr = nullptr;
+ ::CancelIoEx(handle, readCompletionOverlapped);
+ // The object will be deleted in the I/O callback.
+ readCompletionOverlapped = nullptr;
+ readStarted = false;
+ } else {
+ delete readCompletionOverlapped;
+ readCompletionOverlapped = nullptr;
+ };
+
+ if (writeStarted) {
+ writeCompletionOverlapped->dptr = nullptr;
+ ::CancelIoEx(handle, writeCompletionOverlapped);
+ // The object will be deleted in the I/O callback.
+ writeCompletionOverlapped = nullptr;
+ writeStarted = false;
+ } else {
+ delete writeCompletionOverlapped;
+ writeCompletionOverlapped = nullptr;
+ }
+
+ readBytesTransferred = 0;
+ writeBytesTransferred = 0;
writeBuffer.clear();
if (settingsRestoredOnClose) {
@@ -341,30 +447,25 @@ bool QSerialPortPrivate::waitForReadyRead(int msecs)
if (!writeStarted && !_q_startAsyncWrite())
return false;
- const qint64 initialReadBufferSize = buffer.size();
- qint64 currentReadBufferSize = initialReadBufferSize;
-
QDeadlineTimer deadline(msecs);
do {
- const OVERLAPPED *overlapped = waitForNotified(deadline);
- if (!overlapped)
- return false;
-
- if (overlapped == &readCompletionOverlapped) {
- const qint64 readBytesForOneReadOperation = qint64(buffer.size()) - currentReadBufferSize;
- if (readBytesForOneReadOperation == QSERIALPORT_BUFFERSIZE) {
- currentReadBufferSize = buffer.size();
- } else if (readBytesForOneReadOperation == 0) {
- if (initialReadBufferSize != currentReadBufferSize)
- return true;
- } else {
- return true;
- }
+ if (readBytesTransferred <= 0) {
+ const qint64 remaining = deadline.remainingTime();
+ const DWORD result = ::SleepEx(
+ remaining == -1 ? INFINITE : DWORD(remaining),
+ TRUE);
+ if (result != WAIT_IO_COMPLETION)
+ continue;
}
+ if (readBytesTransferred > 0) {
+ readBytesTransferred = 0;
+ return true;
+ }
} while (!deadline.hasExpired());
+ setError(getSystemError(WAIT_TIMEOUT));
return false;
}
@@ -378,15 +479,23 @@ bool QSerialPortPrivate::waitForBytesWritten(int msecs)
QDeadlineTimer deadline(msecs);
- for (;;) {
- const OVERLAPPED *overlapped = waitForNotified(deadline);
- if (!overlapped)
- return false;
+ do {
+ if (writeBytesTransferred <= 0) {
+ const qint64 remaining = deadline.remainingTime();
+ const DWORD result = ::SleepEx(
+ remaining == -1 ? INFINITE : DWORD(remaining),
+ TRUE);
+ if (result != WAIT_IO_COMPLETION)
+ continue;
+ }
- if (overlapped == &writeCompletionOverlapped)
+ if (writeBytesTransferred > 0) {
+ writeBytesTransferred = 0;
return true;
- }
+ }
+ } while (!deadline.hasExpired());
+ setError(getSystemError(WAIT_TIMEOUT));
return false;
}
@@ -467,6 +576,10 @@ bool QSerialPortPrivate::completeAsyncCommunication(qint64 bytesTransferred)
bool QSerialPortPrivate::completeAsyncRead(qint64 bytesTransferred)
{
+ // Store the number of transferred bytes which are
+ // required only in waitForReadyRead() method.
+ readBytesTransferred = bytesTransferred;
+
if (bytesTransferred == qint64(-1)) {
readStarted = false;
return false;
@@ -494,6 +607,10 @@ bool QSerialPortPrivate::completeAsyncWrite(qint64 bytesTransferred)
{
Q_Q(QSerialPort);
+ // Store the number of transferred bytes which are
+ // required only in waitForBytesWritten() method.
+ writeBytesTransferred = bytesTransferred;
+
if (writeStarted) {
if (bytesTransferred == qint64(-1)) {
writeChunkBuffer.clear();
@@ -514,8 +631,16 @@ bool QSerialPortPrivate::startAsyncCommunication()
if (communicationStarted)
return true;
- ::ZeroMemory(&communicationOverlapped, sizeof(communicationOverlapped));
- if (!::WaitCommEvent(handle, &triggeredEventMask, &communicationOverlapped)) {
+ if (!communicationCompletionOverlapped)
+ communicationCompletionOverlapped = new Overlapped(this);
+
+ communicationCompletionOverlapped->clear();
+ communicationStarted = true;
+ if (!::qt_wait_comm_event_ex(handle,
+ &triggeredEventMask,
+ communicationCompletionOverlapped,
+ ioCompletionRoutine)) {
+ communicationStarted = false;
QSerialPortErrorInfo error = getSystemError();
if (error.errorCode != QSerialPort::NoError) {
if (error.errorCode == QSerialPort::PermissionError)
@@ -524,7 +649,6 @@ bool QSerialPortPrivate::startAsyncCommunication()
return false;
}
}
- communicationStarted = true;
return true;
}
@@ -546,23 +670,27 @@ bool QSerialPortPrivate::startAsyncRead()
Q_ASSERT(int(bytesToRead) <= readChunkBuffer.size());
- ::ZeroMemory(&readCompletionOverlapped, sizeof(readCompletionOverlapped));
- if (::ReadFile(handle, readChunkBuffer.data(), bytesToRead, nullptr, &readCompletionOverlapped)) {
- readStarted = true;
- return true;
- }
-
- QSerialPortErrorInfo error = getSystemError();
- if (error.errorCode != QSerialPort::NoError) {
- if (error.errorCode == QSerialPort::PermissionError)
- error.errorCode = QSerialPort::ResourceError;
- if (error.errorCode != QSerialPort::ResourceError)
- error.errorCode = QSerialPort::ReadError;
- setError(error);
- return false;
- }
+ if (!readCompletionOverlapped)
+ readCompletionOverlapped = new Overlapped(this);
+ readCompletionOverlapped->clear();
readStarted = true;
+ if (!::ReadFileEx(handle,
+ readChunkBuffer.data(),
+ bytesToRead,
+ readCompletionOverlapped,
+ ioCompletionRoutine)) {
+ readStarted = false;
+ QSerialPortErrorInfo error = getSystemError();
+ if (error.errorCode != QSerialPort::NoError) {
+ if (error.errorCode == QSerialPort::PermissionError)
+ error.errorCode = QSerialPort::ResourceError;
+ if (error.errorCode != QSerialPort::ResourceError)
+ error.errorCode = QSerialPort::ReadError;
+ setError(error);
+ return false;
+ }
+ }
return true;
}
@@ -572,10 +700,18 @@ bool QSerialPortPrivate::_q_startAsyncWrite()
return true;
writeChunkBuffer = writeBuffer.read();
- ::ZeroMemory(&writeCompletionOverlapped, sizeof(writeCompletionOverlapped));
- if (!::WriteFile(handle, writeChunkBuffer.constData(),
- writeChunkBuffer.size(), nullptr, &writeCompletionOverlapped)) {
+ if (!writeCompletionOverlapped)
+ writeCompletionOverlapped = new Overlapped(this);
+
+ writeCompletionOverlapped->clear();
+ writeStarted = true;
+ if (!::WriteFileEx(handle,
+ writeChunkBuffer.constData(),
+ writeChunkBuffer.size(),
+ writeCompletionOverlapped,
+ ioCompletionRoutine)) {
+ writeStarted = false;
QSerialPortErrorInfo error = getSystemError();
if (error.errorCode != QSerialPort::NoError) {
if (error.errorCode != QSerialPort::ResourceError)
@@ -584,25 +720,29 @@ bool QSerialPortPrivate::_q_startAsyncWrite()
return false;
}
}
-
- writeStarted = true;
return true;
}
-void QSerialPortPrivate::_q_notified(DWORD numberOfBytes, DWORD errorCode, OVERLAPPED *overlapped)
+void QSerialPortPrivate::handleNotification(DWORD bytesTransferred, DWORD errorCode,
+ OVERLAPPED *overlapped)
{
+ // This occurred e.g. after calling the CloseHandle() function,
+ // just skip handling at all.
+ if (handle == INVALID_HANDLE_VALUE)
+ return;
+
const QSerialPortErrorInfo error = getSystemError(errorCode);
if (error.errorCode != QSerialPort::NoError) {
setError(error);
return;
}
- if (overlapped == &communicationOverlapped)
- completeAsyncCommunication(numberOfBytes);
- else if (overlapped == &readCompletionOverlapped)
- completeAsyncRead(numberOfBytes);
- else if (overlapped == &writeCompletionOverlapped)
- completeAsyncWrite(numberOfBytes);
+ if (overlapped == communicationCompletionOverlapped)
+ completeAsyncCommunication(bytesTransferred);
+ else if (overlapped == readCompletionOverlapped)
+ completeAsyncRead(bytesTransferred);
+ else if (overlapped == writeCompletionOverlapped)
+ completeAsyncWrite(bytesTransferred);
else
Q_ASSERT(!"Unknown OVERLAPPED activated");
}
@@ -632,16 +772,6 @@ qint64 QSerialPortPrivate::writeData(const char *data, qint64 maxSize)
return maxSize;
}
-OVERLAPPED *QSerialPortPrivate::waitForNotified(QDeadlineTimer deadline)
-{
- OVERLAPPED *overlapped = notifier->waitForAnyNotified(deadline);
- if (!overlapped) {
- setError(getSystemError(WAIT_TIMEOUT));
- return nullptr;
- }
- return overlapped;
-}
-
qint64 QSerialPortPrivate::queuedBytesCount(QSerialPort::Direction direction) const
{
COMSTAT comstat;
@@ -654,8 +784,6 @@ qint64 QSerialPortPrivate::queuedBytesCount(QSerialPort::Direction direction) co
inline bool QSerialPortPrivate::initialize(QIODevice::OpenMode mode)
{
- Q_Q(QSerialPort);
-
DCB dcb;
if (!getDcb(&dcb))
return false;
@@ -691,17 +819,8 @@ inline bool QSerialPortPrivate::initialize(QIODevice::OpenMode mode)
return false;
}
- notifier = new QWinOverlappedIoNotifier(q);
- QObjectPrivate::connect(notifier, &QWinOverlappedIoNotifier::notified,
- this, &QSerialPortPrivate::_q_notified);
- notifier->setHandle(handle);
- notifier->setEnabled(true);
-
- if ((eventMask & EV_RXCHAR) && !startAsyncCommunication()) {
- delete notifier;
- notifier = nullptr;
+ if ((eventMask & EV_RXCHAR) && !startAsyncCommunication())
return false;
- }
return true;
}
@@ -801,4 +920,17 @@ QSerialPort::Handle QSerialPort::handle() const
return d->handle;
}
+void QSerialPortPrivate::ioCompletionRoutine(
+ DWORD errorCode, DWORD bytesTransfered,
+ OVERLAPPED *overlappedBase)
+{
+ const auto overlapped = static_cast<Overlapped *>(overlappedBase);
+ if (overlapped->dptr) {
+ overlapped->dptr->handleNotification(bytesTransfered, errorCode,
+ overlappedBase);
+ } else {
+ delete overlapped;
+ }
+}
+
QT_END_NAMESPACE
diff --git a/src/serialport/qserialportinfo.cpp b/src/serialport/qserialportinfo.cpp
index f49051d..3bfa56c 100644
--- a/src/serialport/qserialportinfo.cpp
+++ b/src/serialport/qserialportinfo.cpp
@@ -262,6 +262,7 @@ bool QSerialPortInfo::hasProductIdentifier() const
#if QT_DEPRECATED_SINCE(5, 6)
/*!
\fn bool QSerialPortInfo::isBusy() const
+ \obsolete
Returns \c true if serial port is busy;
otherwise returns \c false.
diff --git a/src/serialport/qtntdll_p.h b/src/serialport/qtntdll_p.h
new file mode 100644
index 0000000..a8cdaf6
--- /dev/null
+++ b/src/serialport/qtntdll_p.h
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtSerialPort module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTNTDLL_P_H
+#define QTNTDLL_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qlibrary.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qdebug.h>
+
+#include <qt_windows.h>
+
+// Internal control codes.
+
+#ifndef CTL_CODE
+# define CTL_CODE(DeviceType, Function, Method, Access) ( \
+ ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \
+ )
+#endif
+
+#ifndef FILE_DEVICE_SERIAL_PORT
+# define FILE_DEVICE_SERIAL_PORT 27
+#endif
+
+#ifndef METHOD_BUFFERED
+# define METHOD_BUFFERED 0
+#endif
+
+#ifndef FILE_ANY_ACCESS
+# define FILE_ANY_ACCESS 0x00000000
+#endif
+
+#ifndef IOCTL_SERIAL_GET_DTRRTS
+# define IOCTL_SERIAL_GET_DTRRTS \
+ CTL_CODE(FILE_DEVICE_SERIAL_PORT, 30, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#endif
+
+#ifndef SERIAL_DTR_STATE
+# define SERIAL_DTR_STATE 0x00000001
+#endif
+
+#ifndef SERIAL_RTS_STATE
+# define SERIAL_RTS_STATE 0x00000002
+#endif
+
+#ifndef IOCTL_SERIAL_WAIT_ON_MASK
+# define IOCTL_SERIAL_WAIT_ON_MASK \
+ CTL_CODE(FILE_DEVICE_SERIAL_PORT, 18, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#endif
+
+// Internal NT-based data types.
+
+#ifndef NT_SUCCESS
+#define NT_SUCCESS(status) (((NTSTATUS)(status)) >= 0)
+#endif
+
+typedef struct _IO_STATUS_BLOCK {
+ union {
+ NTSTATUS Status;
+ PVOID Pointer;
+ } DUMMYUNIONNAME;
+
+ ULONG_PTR Information;
+} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
+
+typedef VOID (WINAPI *PIO_APC_ROUTINE) (
+ PVOID ApcContext,
+ PIO_STATUS_BLOCK IoStatusBlock,
+ ULONG Reserved
+ );
+
+// Resolving macros.
+
+#define GENERATE_SYMBOL_VARIABLE(returnType, symbolName, ...) \
+ typedef returnType (WINAPI *fp_##symbolName)(__VA_ARGS__); \
+ static fp_##symbolName symbolName;
+
+#define RESOLVE_SYMBOL(symbolName) \
+ symbolName = reinterpret_cast<fp_##symbolName>(resolveSymbol(ntLibrary, #symbolName)); \
+ if (!symbolName) \
+ return false;
+
+GENERATE_SYMBOL_VARIABLE(ULONG, RtlNtStatusToDosError, NTSTATUS)
+GENERATE_SYMBOL_VARIABLE(NTSTATUS, NtDeviceIoControlFile, HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, PIO_STATUS_BLOCK, ULONG, PVOID, ULONG, PVOID, ULONG)
+
+inline QFunctionPointer resolveSymbol(QLibrary *ntLibrary, const char *symbolName)
+{
+ QFunctionPointer symbolFunctionPointer = ntLibrary->resolve(symbolName);
+ if (!symbolFunctionPointer)
+ qWarning("Failed to resolve the symbol: %s", symbolName);
+
+ return symbolFunctionPointer;
+}
+
+inline bool resolveSymbols(QLibrary *ntLibrary)
+{
+ if (!ntLibrary->isLoaded()) {
+ ntLibrary->setFileName(QStringLiteral("ntdll"));
+ if (!ntLibrary->load()) {
+ qWarning("Failed to load the library: %s", qPrintable(ntLibrary->fileName()));
+ return false;
+ }
+ }
+
+ RESOLVE_SYMBOL(RtlNtStatusToDosError)
+ RESOLVE_SYMBOL(NtDeviceIoControlFile)
+
+ return true;
+}
+
+#endif // QTNTDLL_P_H
diff --git a/src/serialport/qwinoverlappedionotifier_p.h b/src/serialport/qwinoverlappedionotifier_p.h
deleted file mode 100644
index 9ee998b..0000000
--- a/src/serialport/qwinoverlappedionotifier_p.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** 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 https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://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 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QWINOVERLAPPEDIONOTIFIER_P_H
-#define QWINOVERLAPPEDIONOTIFIER_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtCore/private/qglobal_p.h>
-#include <qobject.h>
-#include <qdeadlinetimer.h>
-
-typedef struct _OVERLAPPED OVERLAPPED;
-
-QT_BEGIN_NAMESPACE
-
-class QWinOverlappedIoNotifierPrivate;
-
-class QWinOverlappedIoNotifier : public QObject
-{
- Q_OBJECT
- Q_DISABLE_COPY(QWinOverlappedIoNotifier)
- Q_DECLARE_PRIVATE(QWinOverlappedIoNotifier)
- Q_PRIVATE_SLOT(d_func(), void _q_notified())
- friend class QWinIoCompletionPort;
-public:
- QWinOverlappedIoNotifier(QObject *parent = 0);
- ~QWinOverlappedIoNotifier();
-
- void setHandle(Qt::HANDLE h);
- Qt::HANDLE handle() const;
-
- void setEnabled(bool enabled);
- OVERLAPPED *waitForAnyNotified(QDeadlineTimer deadline);
- bool waitForNotified(QDeadlineTimer deadline, OVERLAPPED *overlapped);
-
-Q_SIGNALS:
- void notified(quint32 numberOfBytes, quint32 errorCode, OVERLAPPED *overlapped);
-#if !defined(Q_QDOC)
- void _q_notify();
-#endif
-};
-
-QT_END_NAMESPACE
-
-#endif // QWINOVERLAPPEDIONOTIFIER_P_H
diff --git a/src/serialport/serialport-lib.pri b/src/serialport/serialport-lib.pri
index ddd31f2..b9b3c83 100644
--- a/src/serialport/serialport-lib.pri
+++ b/src/serialport/serialport-lib.pri
@@ -23,10 +23,9 @@ win32 {
SOURCES += \
$$PWD/qserialport_win.cpp \
$$PWD/qserialportinfo_win.cpp \
- $$PWD/qwinoverlappedionotifier.cpp
PRIVATE_HEADERS += \
- $$PWD/qwinoverlappedionotifier_p.h
+ $$PWD/qtntdll_p.h
LIBS_PRIVATE += -lsetupapi -ladvapi32
}
diff --git a/tests/auto/qserialport/tst_qserialport.cpp b/tests/auto/qserialport/tst_qserialport.cpp
index 94eaaa5..f55dac7 100644
--- a/tests/auto/qserialport/tst_qserialport.cpp
+++ b/tests/auto/qserialport/tst_qserialport.cpp
@@ -272,7 +272,7 @@ void tst_QSerialPort::openExisting()
for (const QString &serialPortName : qAsConst(m_availablePortNames)) {
QSerialPort serialPort(serialPortName);
- QSignalSpy errorSpy(&serialPort, static_cast<void (QSerialPort::*)(QSerialPort::SerialPortError)>(&QSerialPort::error));
+ QSignalSpy errorSpy(&serialPort, &QSerialPort::errorOccurred);
QVERIFY(errorSpy.isValid());
QCOMPARE(serialPort.portName(), serialPortName);
@@ -304,7 +304,7 @@ void tst_QSerialPort::openNotExisting()
QSerialPort serialPort(serialPortName);
- QSignalSpy errorSpy(&serialPort, static_cast<void (QSerialPort::*)(QSerialPort::SerialPortError)>(&QSerialPort::error));
+ QSignalSpy errorSpy(&serialPort, &QSerialPort::errorOccurred);
QVERIFY(errorSpy.isValid());
QCOMPARE(serialPort.portName(), serialPortName);
@@ -477,7 +477,7 @@ void tst_QSerialPort::rts()
{
QSerialPort serialPort(m_senderPortName);
- QSignalSpy errorSpy(&serialPort, static_cast<void (QSerialPort::*)(QSerialPort::SerialPortError)>(&QSerialPort::error));
+ QSignalSpy errorSpy(&serialPort, &QSerialPort::errorOccurred);
QVERIFY(errorSpy.isValid());
QSignalSpy rtsSpy(&serialPort, &QSerialPort::requestToSendChanged);
QVERIFY(rtsSpy.isValid());
@@ -516,7 +516,7 @@ void tst_QSerialPort::dtr()
{
QSerialPort serialPort(m_senderPortName);
- QSignalSpy errorSpy(&serialPort, static_cast<void (QSerialPort::*)(QSerialPort::SerialPortError)>(&QSerialPort::error));
+ QSignalSpy errorSpy(&serialPort, &QSerialPort::errorOccurred);
QVERIFY(errorSpy.isValid());
QSignalSpy dtrSpy(&serialPort, &QSerialPort::dataTerminalReadyChanged);
QVERIFY(dtrSpy.isValid());