diff options
-rw-r--r-- | .qmake.conf | 4 | ||||
-rw-r--r-- | src/serialport/qserialport.h | 1 | ||||
-rw-r--r-- | src/serialport/qserialport_p.h | 18 | ||||
-rw-r--r-- | src/serialport/qserialport_win.cpp | 364 | ||||
-rw-r--r-- | src/serialport/qtntdll_p.h | 158 | ||||
-rw-r--r-- | src/serialport/qwinoverlappedionotifier_p.h | 91 | ||||
-rw-r--r-- | src/serialport/serialport-lib.pri | 3 |
7 files changed, 421 insertions, 218 deletions
diff --git a/.qmake.conf b/.qmake.conf index 1ed62c5a..f6895bb0 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/src/serialport/qserialport.h b/src/serialport/qserialport.h index 9a5c1d03..c4c7367a 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 b0955aef..7348aed6 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 85dd8ee2..da1e7aae 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/qtntdll_p.h b/src/serialport/qtntdll_p.h new file mode 100644 index 00000000..a8cdaf6a --- /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 9ee998bd..00000000 --- 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 ddd31f2b..b9b3c83b 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 } |