diff options
author | Karsten Heimrich <karsten.heimrich@qt.io> | 2021-06-21 16:00:07 +0200 |
---|---|---|
committer | Karsten Heimrich <karsten.heimrich@qt.io> | 2021-10-19 10:14:24 +0200 |
commit | 4ff9993d9f2e991f2da1885a694d4f3a61c9af73 (patch) | |
tree | 8d78943470ac8e93913c118bb6dbeac716b0f303 | |
parent | 2b90577da89a3b63714b6f560646db9724515f56 (diff) | |
download | qtserialport-4ff9993d9f2e991f2da1885a694d4f3a61c9af73.tar.gz |
Revert "QSerialPort: Port to alertable I/O functions on Windows"
This reverts commit a0faf986fccdce1d36f3308dc520cdac001f5264.
Part of chain revert to go back to QWinOverlappedIoNotifier.
Fixes: QTBUG-93865
Change-Id: Id4b6516282f35ccb3e81f20893872b4d1bcd3e05
Reviewed-by: Joerg Bornemann <joerg.bornemann@qt.io>
-rw-r--r-- | src/serialport/CMakeLists.txt | 3 | ||||
-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 | 361 | ||||
-rw-r--r-- | src/serialport/qtntdll_p.h | 158 | ||||
-rw-r--r-- | src/serialport/qwinoverlappedionotifier_p.h | 91 |
6 files changed, 216 insertions, 416 deletions
diff --git a/src/serialport/CMakeLists.txt b/src/serialport/CMakeLists.txt index 25558ea..8c7863a 100644 --- a/src/serialport/CMakeLists.txt +++ b/src/serialport/CMakeLists.txt @@ -38,7 +38,8 @@ qt_internal_extend_target(SerialPort CONDITION WIN32 SOURCES qserialport_win.cpp qserialportinfo_win.cpp - qtntdll_p.h + qwinoverlappedionotifier.cpp + qwinoverlappedionotifier_p.h LIBRARIES advapi32 setupapi diff --git a/src/serialport/qserialport.h b/src/serialport/qserialport.h index 8ef0f6b..0170c28 100644 --- a/src/serialport/qserialport.h +++ b/src/serialport/qserialport.h @@ -244,6 +244,7 @@ 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 a9c08e9..a24ed0b 100644 --- a/src/serialport/qserialport_p.h +++ b/src/serialport/qserialport_p.h @@ -106,6 +106,7 @@ struct serial_struct { QT_BEGIN_NAMESPACE +class QWinOverlappedIoNotifier; class QTimer; class QSocketNotifier; @@ -209,6 +210,7 @@ public: bool setDcb(DCB *dcb); bool getDcb(DCB *dcb); + OVERLAPPED *waitForNotified(QDeadlineTimer deadline); qint64 queuedBytesCount(QSerialPort::Direction direction) const; @@ -218,15 +220,10 @@ public: bool startAsyncCommunication(); bool _q_startAsyncWrite(); - void handleNotification(DWORD bytesTransferred, DWORD errorCode, - OVERLAPPED *overlapped); + void _q_notified(DWORD numberOfBytes, DWORD errorCode, OVERLAPPED *overlapped); void emitReadyRead(); - static void CALLBACK ioCompletionRoutine( - DWORD errorCode, DWORD bytesTransfered, - OVERLAPPED *overlappedBase); - DCB restoredDcb; COMMTIMEOUTS currentCommTimeouts; COMMTIMEOUTS restoredCommTimeouts; @@ -236,12 +233,11 @@ public: bool communicationStarted = false; bool writeStarted = false; bool readStarted = false; - qint64 writeBytesTransferred = 0; - qint64 readBytesTransferred = 0; + QWinOverlappedIoNotifier *notifier = nullptr; QTimer *startAsyncWriteTimer = nullptr; - class Overlapped *communicationCompletionOverlapped = nullptr; - class Overlapped *readCompletionOverlapped = nullptr; - class Overlapped *writeCompletionOverlapped = nullptr; + OVERLAPPED communicationOverlapped; + OVERLAPPED readCompletionOverlapped; + OVERLAPPED writeCompletionOverlapped; DWORD triggeredEventMask = 0; #elif defined(Q_OS_UNIX) diff --git a/src/serialport/qserialport_win.cpp b/src/serialport/qserialport_win.cpp index 387c4f0..ad3a113 100644 --- a/src/serialport/qserialport_win.cpp +++ b/src/serialport/qserialport_win.cpp @@ -40,7 +40,7 @@ ****************************************************************************/ #include "qserialport_p.h" -#include "qtntdll_p.h" +#include "qwinoverlappedionotifier_p.h" #include <QtCore/qcoreevent.h> #include <QtCore/qelapsedtimer.h> @@ -49,6 +49,37 @@ #include <QtCore/qtimer.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) @@ -143,117 +174,8 @@ 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) @@ -278,44 +200,17 @@ bool QSerialPortPrivate::open(QIODevice::OpenMode mode) void QSerialPortPrivate::close() { - delete startAsyncWriteTimer; - startAsyncWriteTimer = nullptr; + ::CancelIo(handle); - 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; - } + delete notifier; + notifier = 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; - } + delete startAsyncWriteTimer; + startAsyncWriteTimer = nullptr; - readBytesTransferred = 0; - writeBytesTransferred = 0; + communicationStarted = false; + readStarted = false; + writeStarted = false; writeBuffer.clear(); if (settingsRestoredOnClose) { @@ -447,25 +342,30 @@ bool QSerialPortPrivate::waitForReadyRead(int msecs) if (!writeStarted && !_q_startAsyncWrite()) return false; + const qint64 initialReadBufferSize = buffer.size(); + qint64 currentReadBufferSize = initialReadBufferSize; + QDeadlineTimer deadline(msecs); do { - if (readBytesTransferred <= 0) { - const qint64 remaining = deadline.remainingTime(); - const DWORD result = ::SleepEx( - remaining == -1 ? INFINITE : DWORD(remaining), - TRUE); - if (result != WAIT_IO_COMPLETION) - continue; - } + const OVERLAPPED *overlapped = waitForNotified(deadline); + if (!overlapped) + return false; - if (readBytesTransferred > 0) { - readBytesTransferred = 0; - return true; + 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; + } } + } while (!deadline.hasExpired()); - setError(getSystemError(WAIT_TIMEOUT)); return false; } @@ -479,23 +379,15 @@ bool QSerialPortPrivate::waitForBytesWritten(int msecs) QDeadlineTimer deadline(msecs); - 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; - } + for (;;) { + const OVERLAPPED *overlapped = waitForNotified(deadline); + if (!overlapped) + return false; - if (writeBytesTransferred > 0) { - writeBytesTransferred = 0; + if (overlapped == &writeCompletionOverlapped) return true; - } - } while (!deadline.hasExpired()); + } - setError(getSystemError(WAIT_TIMEOUT)); return false; } @@ -576,10 +468,6 @@ 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; @@ -607,10 +495,6 @@ 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(); @@ -631,16 +515,8 @@ bool QSerialPortPrivate::startAsyncCommunication() if (communicationStarted) return true; - if (!communicationCompletionOverlapped) - communicationCompletionOverlapped = new Overlapped(this); - - communicationCompletionOverlapped->clear(); - communicationStarted = true; - if (!::qt_wait_comm_event_ex(handle, - &triggeredEventMask, - communicationCompletionOverlapped, - ioCompletionRoutine)) { - communicationStarted = false; + ::ZeroMemory(&communicationOverlapped, sizeof(communicationOverlapped)); + if (!::WaitCommEvent(handle, &triggeredEventMask, &communicationOverlapped)) { QSerialPortErrorInfo error = getSystemError(); if (error.errorCode != QSerialPort::NoError) { if (error.errorCode == QSerialPort::PermissionError) @@ -649,6 +525,7 @@ bool QSerialPortPrivate::startAsyncCommunication() return false; } } + communicationStarted = true; return true; } @@ -670,27 +547,23 @@ bool QSerialPortPrivate::startAsyncRead() Q_ASSERT(int(bytesToRead) <= readChunkBuffer.size()); - if (!readCompletionOverlapped) - readCompletionOverlapped = new Overlapped(this); + ::ZeroMemory(&readCompletionOverlapped, sizeof(readCompletionOverlapped)); + if (::ReadFile(handle, readChunkBuffer.data(), bytesToRead, nullptr, &readCompletionOverlapped)) { + readStarted = true; + return true; + } - 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; - } + 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; } + + readStarted = true; return true; } @@ -700,18 +573,10 @@ 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) @@ -720,29 +585,25 @@ bool QSerialPortPrivate::_q_startAsyncWrite() return false; } } + + writeStarted = true; return true; } -void QSerialPortPrivate::handleNotification(DWORD bytesTransferred, DWORD errorCode, - OVERLAPPED *overlapped) +void QSerialPortPrivate::_q_notified(DWORD numberOfBytes, 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 == communicationCompletionOverlapped) - completeAsyncCommunication(bytesTransferred); - else if (overlapped == readCompletionOverlapped) - completeAsyncRead(bytesTransferred); - else if (overlapped == writeCompletionOverlapped) - completeAsyncWrite(bytesTransferred); + if (overlapped == &communicationOverlapped) + completeAsyncCommunication(numberOfBytes); + else if (overlapped == &readCompletionOverlapped) + completeAsyncRead(numberOfBytes); + else if (overlapped == &writeCompletionOverlapped) + completeAsyncWrite(numberOfBytes); else Q_ASSERT(!"Unknown OVERLAPPED activated"); } @@ -772,6 +633,16 @@ 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; @@ -784,6 +655,8 @@ qint64 QSerialPortPrivate::queuedBytesCount(QSerialPort::Direction direction) co inline bool QSerialPortPrivate::initialize(QIODevice::OpenMode mode) { + Q_Q(QSerialPort); + DCB dcb; if (!getDcb(&dcb)) return false; @@ -819,8 +692,17 @@ inline bool QSerialPortPrivate::initialize(QIODevice::OpenMode mode) return false; } - if ((eventMask & EV_RXCHAR) && !startAsyncCommunication()) + 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; return false; + } return true; } @@ -920,17 +802,4 @@ 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 deleted file mode 100644 index a8cdaf6..0000000 --- a/src/serialport/qtntdll_p.h +++ /dev/null @@ -1,158 +0,0 @@ -/**************************************************************************** -** -** 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 new file mode 100644 index 0000000..9ee998b --- /dev/null +++ b/src/serialport/qwinoverlappedionotifier_p.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** 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 |