From eea2684433fc8a52ecc232b1b53bb2e06be04840 Mon Sep 17 00:00:00 2001 From: Vitaly Petrov Date: Wed, 20 Mar 2019 22:35:16 +0300 Subject: [PATCH] Remove old ConPty stuff, fix Windows build, update submodule --- .appveyor.yml | 7 +- CMakeLists.txt | 29 +- core/CMakeLists.txt | 7 +- core/conptyanonymouspipeprocess.h | 72 ----- core/conptynamedpipeprocess.cpp | 274 ------------------ core/conptynamedpipeprocess.h | 28 -- ...ymouspipeprocess.cpp => conptyprocess.cpp} | 28 +- core/{conpty_shared.h => conptyprocess.h} | 72 ++++- core/iptyprocess.h | 35 +-- core/ptyqt.cpp | 12 +- core/winptyprocess.cpp | 17 +- core/winptyprocess.h | 9 +- tests/ptyqt_tests.cpp | 1 - 13 files changed, 130 insertions(+), 461 deletions(-) delete mode 100644 core/conptyanonymouspipeprocess.h delete mode 100644 core/conptynamedpipeprocess.cpp delete mode 100644 core/conptynamedpipeprocess.h rename core/{conptyanonymouspipeprocess.cpp => conptyprocess.cpp} (89%) rename core/{conpty_shared.h => conptyprocess.h} (60%) diff --git a/.appveyor.yml b/.appveyor.yml index 7a3296d..71a86cc 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -13,6 +13,8 @@ environment: matrix: - PLATFORM: x64 QT_DIR: C:\Qt\5.12.1\msvc2017_64 + - PLATFORM: x86 + QT_DIR: C:\Qt\5.12.1\msvc2017 matrix: fast_finish: true @@ -36,5 +38,6 @@ build_script: - cmake.exe --build . - dir thirdparty\winpty\src\winpty -#test_script: -# - ctest -C %CONFIGURATION% --output-on-failure +test_script: + - set PATH=%PATH%;%QT_DIR% + - ctest -C %CONFIGURATION% --output-on-failure diff --git a/CMakeLists.txt b/CMakeLists.txt index e46c892..5e2eaa8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,6 +11,10 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOMOC ON) #params +#available params: +# - NO_BUILD_TESTS=1 +# - NO_BUILD_EXAMPLES=1 +# - WINPTY_ROOT_DIR= - if you set this parameter, winpty doesn't be auto-downloaded like dependency IF(CMAKE_BUILD_TYPE MATCHES Debug) set(PTYQT_DEBUG TRUE) add_definitions(-DPTYQT_DEBUG) @@ -64,22 +68,9 @@ enable_testing() #sub projects add_subdirectory(core) -add_subdirectory(tests) -add_subdirectory(examples) - -#add_executable(${PROJECT_NAME} "main.cpp") - -#target_link_libraries(${PROJECT_NAME} Qt5::Core) - -#Ubuntu package generator -set(CPACK_PACKAGE_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}") -set(CPACK_PACKAGE_VERSION_MINOR "${PROJECT_VERSION_MINOR}") -set(CPACK_PACKAGE_VERSION_PATCH "${PROJECT_VERSION_PATCH}") - -set(CPACK_PACKAGE_CONTACT v31337@gmail.com) - -set(CPACK_GENERATOR DEB) - -set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) - -include (CPack) +if (NOT "${NO_BUILD_TESTS}" STREQUAL "1") + add_subdirectory(tests) +endif() +if (NOT "${NO_BUILD_EXAMPLES}" STREQUAL "1") + add_subdirectory(examples) +endif() diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 2fecf4d..101f18b 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -11,11 +11,8 @@ if (MSVC) ${SOURCE_FILES} winptyprocess.h winptyprocess.cpp - #conptynamedpipeprocess.h - #conptynamedpipeprocess.cpp - conptyanonymouspipeprocess.h - conptyanonymouspipeprocess.cpp - conpty_shared.h + conptyprocess.h + conptyprocess.cpp ) else() set(SOURCE_FILES diff --git a/core/conptyanonymouspipeprocess.h b/core/conptyanonymouspipeprocess.h deleted file mode 100644 index b8f707e..0000000 --- a/core/conptyanonymouspipeprocess.h +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef CONPTYANONYMOUSPIPEPROCESS_H -#define CONPTYANONYMOUSPIPEPROCESS_H - -#include "conpty_shared.h" -#include -#include -#include - -class PtyBuffer : public QIODevice -{ - friend class ConPtyAnonymousPipeProcess; - Q_OBJECT -public: - - PtyBuffer() { } - ~PtyBuffer() { } - - //just empty realization, we need only 'readyRead' signal of this class - qint64 readData(char *data, qint64 maxlen) { return 0; } - qint64 writeData(const char *data, qint64 len) { return 0; } - - bool isSequential() { return true; } - qint64 bytesAvailable() { return m_readBuffer.size(); } - qint64 size() { return m_readBuffer.size(); } - - void emitReadyRead() - { - //for emit signal from PtyBuffer own thread - QTimer::singleShot(1, this, [this]() - { - emit readyRead(); - }); - } - -private: - QByteArray m_readBuffer; -}; - -class ConPtyAnonymousPipeProcess : public IPtyProcess -{ -public: - ConPtyAnonymousPipeProcess(); - ~ConPtyAnonymousPipeProcess(); - - bool startProcess(const QString &shellPath, QStringList environment, qint16 cols, qint16 rows); - bool resize(qint16 cols, qint16 rows); - bool kill(); - PtyType type(); -#ifdef PTYQT_DEBUG - QString dumpDebugInfo(); -#endif - virtual QIODevice *notifier(); - virtual QByteArray readAll(); - virtual qint64 write(const QByteArray &byteArray); - bool isAvailable(); - -private: - HRESULT createPseudoConsoleAndPipes(HPCON* phPC, HANDLE* phPipeIn, HANDLE* phPipeOut, qint16 cols, qint16 rows); - HRESULT initializeStartupInfoAttachedToPseudoConsole(STARTUPINFOEX* pStartupInfo, HPCON hPC); - -private: - WindowsContext m_winContext; - HPCON m_ptyHandler; - HANDLE m_hPipeIn, m_hPipeOut; - - QThread *m_readThread; - QMutex m_bufferMutex; - PtyBuffer m_buffer; - -}; - -#endif // CONPTYANONYMOUSPIPEPROCESS_H diff --git a/core/conptynamedpipeprocess.cpp b/core/conptynamedpipeprocess.cpp deleted file mode 100644 index b4ce476..0000000 --- a/core/conptynamedpipeprocess.cpp +++ /dev/null @@ -1,274 +0,0 @@ -#include "conptynamedpipeprocess.h" -#include -#include -#include -#include -#include -#include -#include -#include - -ConPtyNamedPipeProcess::ConPtyNamedPipeProcess() - : IWindowsPtyProcess() - , m_ptyHandler(INVALID_HANDLE_VALUE) - , m_hShell(INVALID_HANDLE_VALUE) -{ - -} - -ConPtyNamedPipeProcess::~ConPtyNamedPipeProcess() -{ - kill(); -} - -bool ConPtyNamedPipeProcess::startProcess(const QString &shellPath, QStringList environment, qint16 cols, qint16 rows) -{ - //shared between all objects in all threads - static QMutex pipeNameCounterMutex; - static qint64 pipeNameCounter = 0; - - if (!isAvailable()) - { - m_lastError = m_winContext.lastError(); - return false; - } - - //already running - if (m_ptyHandler != INVALID_HANDLE_VALUE) - return false; - - QFileInfo fi(shellPath); - if (fi.isRelative() || !QFile::exists(shellPath)) - { - //todo add auto-find executable in PATH env var - m_lastError = QString("WinPty Error: shell file path must be absolute"); - return false; - } - - m_shellPath = shellPath; - m_size = QPair(cols, rows); - - auto createNamedPipe = [] (bool writeChannel, - HANDLE *hNamedPipe, - QString &resultName, - const QString &pipeName) -> bool - { - *hNamedPipe = INVALID_HANDLE_VALUE; - resultName = "\\\\.\\pipe\\" + pipeName; - - const DWORD winOpenMode = PIPE_ACCESS_INBOUND | PIPE_ACCESS_OUTBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE/* | FILE_FLAG_OVERLAPPED */; - - SECURITY_ATTRIBUTES sa = {}; - sa.nLength = sizeof(sa); - - *hNamedPipe = CreateNamedPipeW( - resultName.toStdWString().c_str(), - /*dwOpenMode=*/winOpenMode, - /*dwPipeMode=*/PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, - /*nMaxInstances=*/1, - /*nOutBufferSize=*/0, - /*nInBufferSize=*/0, - /*nDefaultTimeOut=*/30000, - &sa); - - return *hNamedPipe != INVALID_HANDLE_VALUE; - }; - - //shared between all objects in all threads - qint64 pipeCounterValue = 0; - { - QMutexLocker locker(&pipeNameCounterMutex); - pipeCounterValue = pipeNameCounter; - pipeNameCounter++; - } - // - - QByteArray randPart = QCryptographicHash::hash(QByteArray::number(qrand()) + QByteArray::number(pipeCounterValue) + QUuid::createUuid().toByteArray(), QCryptographicHash::Sha256).left(16); - bool createPipeRes = createNamedPipe(true, &m_inPipeShellSide, m_conInName, QString("conpty-conin-%1-%2").arg(pipeCounterValue).arg(QString::fromLatin1(randPart.toHex()))); - if (!createPipeRes) - { - m_lastError = QString("ConPty Error: Unable to create IN pipe -> %1").arg(GetLastError()); - return false; - } - - randPart = QCryptographicHash::hash(QByteArray::number(qrand()) + QByteArray::number(pipeCounterValue) + QUuid::createUuid().toByteArray(), QCryptographicHash::Sha256).left(16); - createPipeRes = createNamedPipe(false, &m_outPipeShellSide, m_conOutName, QString("conpty-conout-%1-%2").arg(pipeCounterValue).arg(QString::fromLatin1(randPart.toHex()))); - if (!createPipeRes) - { - m_lastError = QString("ConPty Error: Unable to create OUT pipe -> %1").arg(GetLastError()); - return false; - } - - HRESULT result = m_winContext.createPseudoConsole({cols, rows}, m_inPipeShellSide, m_outPipeShellSide, 0, &m_ptyHandler); - - if (result != S_OK) - { - //error can be E_HANDLE - m_lastError = QString("ConPty Error: Unable to launch ConPty -> %1").arg(QString::number(result, 16)); - return false; - } - - //console created - - //env - std::wstringstream envBlock; - foreach (QString line, environment) - { - envBlock << line.toStdWString() << L'\0'; - } - envBlock << L'\0'; - std::wstring env = envBlock.str(); - auto envV = vectorFromString(env); - LPWSTR envArg = envV.empty() ? nullptr : envV.data(); - LPWSTR cmdArg = (LPWSTR)m_shellPath.utf16(); - - //this code runned in separate thread, because current thread will stops on API call 'ConnectNamedPipe' - QThread *thread = QThread::create([this]() - { - QThread::msleep(10); - m_inSocket.connectToServer(m_conInName, QIODevice::WriteOnly); - m_inSocket.waitForConnected(); - m_outSocket.connectToServer(m_conOutName, QIODevice::ReadOnly); - m_outSocket.waitForConnected(); - - if (m_inSocket.state() != QLocalSocket::ConnectedState || m_outSocket.state() != QLocalSocket::ConnectedState) - { - m_lastError = QString("ConPty Error: Unable to connect local sockets -> %1 / %2").arg(m_inSocket.errorString()).arg(m_outSocket.errorString()); - } - - //qDebug() << "socketDescriptors" << m_inSocket.fullServerName() << m_inSocket.socketDescriptor() << m_outSocket.socketDescriptor() << m_inSocket.errorString() << m_outSocket.errorString(); - QThread::currentThread()->deleteLater(); - }); - //connect to Pty - thread->start(); - - bool connected = ConnectNamedPipe(m_inPipeShellSide, nullptr) && ConnectNamedPipe(m_outPipeShellSide, nullptr); - - if (!connected) - { - m_lastError = QString("ConPty Error: Unable to connect named pipes"); - return false; - } - - //attach the pseudoconsole to the client application we're creating - STARTUPINFOEXW pStartupInfo{0}; - pStartupInfo.StartupInfo.cb = sizeof(STARTUPINFOEXW); - - //get the size of the thread attribute list. - size_t size; - InitializeProcThreadAttributeList(NULL, 1, 0, reinterpret_cast(&size)); - pStartupInfo.lpAttributeList = reinterpret_cast(malloc(size)); - - bool fSuccess = InitializeProcThreadAttributeList(pStartupInfo.lpAttributeList, 1, 0, reinterpret_cast(&size)); - if (!fSuccess) - { - m_lastError = QString("ConPty Error: InitializeProcThreadAttributeList failed"); - return false; - } - fSuccess = UpdateProcThreadAttribute(pStartupInfo.lpAttributeList, - 0, - PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, - m_ptyHandler, - sizeof(HPCON), - NULL, - NULL); - - if (!fSuccess) - { - m_lastError = QString("ConPty Error: UpdateProcThreadAttribute failed"); - return false; - } - - //create process - PROCESS_INFORMATION piClient{}; - fSuccess = !!CreateProcessW( - nullptr, - cmdArg, - nullptr, // lpProcessAttributes - nullptr, // lpThreadAttributes - false, // bInheritHandles VERY IMPORTANT that this is false - EXTENDED_STARTUPINFO_PRESENT | CREATE_UNICODE_ENVIRONMENT, // dwCreationFlags - envArg, // lpEnvironment - nullptr, // lpCurrentDirectory - &pStartupInfo.StartupInfo, // lpStartupInfo - &piClient // lpProcessInformation - ); - - if (!fSuccess) - { - m_lastError = QString("ConPty Error: Cannot create process -> %1").arg(QString::number(GetLastError(), 10)); - return false; - } - - // Update handle - m_hShell = piClient.hProcess; - m_pid = piClient.dwProcessId; - - return true; -} - -bool ConPtyNamedPipeProcess::resize(qint16 cols, qint16 rows) -{ - if (m_ptyHandler == nullptr) - { - return false; - } - - bool res = SUCCEEDED(m_winContext.resizePseudoConsole(m_ptyHandler, {cols, rows})); - - if (res) - { - m_size = QPair(cols, rows); - } - - return res; -} - -bool ConPtyNamedPipeProcess::kill() -{ - bool exitCode = false; - if (m_hShell != 0 && m_ptyHandler != 0) - { - m_inSocket.disconnectFromServer(); - m_outSocket.disconnectFromServer(); - - m_winContext.closePseudoConsole(m_ptyHandler); - exitCode = CloseHandle(m_hShell); - - m_hShell = INVALID_HANDLE_VALUE; - m_ptyHandler = INVALID_HANDLE_VALUE; - m_conInName = QString(); - m_conOutName = QString(); - m_inPipeShellSide = INVALID_HANDLE_VALUE; - m_outPipeShellSide = INVALID_HANDLE_VALUE; - m_pid = 0; - } - return exitCode; -} - -IPtyProcess::PtyType ConPtyNamedPipeProcess::type() -{ - return PtyType::ConPtyNamedPipe; -} - -#ifdef PTYQT_DEBUG -QString ConPtyNamedPipeProcess::dumpDebugInfo() -{ - return QString("PID: %1, ConIn: %2, ConOut: %3, Type: %4, Cols: %5, Rows: %6, IsRunning: %7, Shell: %8") - .arg(m_pid).arg(m_conInName).arg(m_conOutName).arg(type()) - .arg(m_size.first).arg(m_size.second).arg(m_ptyHandler != nullptr) - .arg(m_shellPath); -} -#endif - -bool ConPtyNamedPipeProcess::isAvailable() -{ -#ifdef TOO_OLD_WINSDK - return false; //very importnant! ConPty can be built, but it doesn't work if built with old sdk and Win10 < 1903 -#endif - - qint32 buildNumber = QSysInfo::kernelVersion().split(".").last().toInt(); - if (buildNumber < CONPTY_MINIMAL_WINDOWS_VERSION) - return false; - return m_winContext.init(); -} diff --git a/core/conptynamedpipeprocess.h b/core/conptynamedpipeprocess.h deleted file mode 100644 index 94fd6f8..0000000 --- a/core/conptynamedpipeprocess.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef CONPTYNAMEDPIPEPROCESS_H -#define CONPTYNAMEDPIPEPROCESS_H - -#include "conpty_shared.h" - -class ConPtyNamedPipeProcess : public IWindowsPtyProcess -{ -public: - ConPtyNamedPipeProcess(); - ~ConPtyNamedPipeProcess(); - - bool startProcess(const QString &shellPath, QStringList environment, qint16 cols, qint16 rows); - bool resize(qint16 cols, qint16 rows); - bool kill(); - PtyType type(); -#ifdef PTYQT_DEBUG - QString dumpDebugInfo(); -#endif - bool isAvailable(); - -private: - WindowsContext m_winContext; - HPCON m_ptyHandler; - HANDLE m_hShell; - HANDLE m_inPipeShellSide, m_outPipeShellSide; -}; - -#endif // CONPTYNAMEDPIPEPROCESS_H diff --git a/core/conptyanonymouspipeprocess.cpp b/core/conptyprocess.cpp similarity index 89% rename from core/conptyanonymouspipeprocess.cpp rename to core/conptyprocess.cpp index 041d51e..97a5cd6 100644 --- a/core/conptyanonymouspipeprocess.cpp +++ b/core/conptyprocess.cpp @@ -1,4 +1,4 @@ -#include "conptyanonymouspipeprocess.h" +#include "conptyprocess.h" #include #include #include @@ -9,7 +9,7 @@ #define READ_INTERVAL_MSEC 500 -HRESULT ConPtyAnonymousPipeProcess::createPseudoConsoleAndPipes(HPCON* phPC, HANDLE* phPipeIn, HANDLE* phPipeOut, qint16 cols, qint16 rows) +HRESULT ConPtyProcess::createPseudoConsoleAndPipes(HPCON* phPC, HANDLE* phPipeIn, HANDLE* phPipeOut, qint16 cols, qint16 rows) { HRESULT hr{ E_UNEXPECTED }; HANDLE hPipePTYIn{ INVALID_HANDLE_VALUE }; @@ -34,7 +34,7 @@ HRESULT ConPtyAnonymousPipeProcess::createPseudoConsoleAndPipes(HPCON* phPC, HAN // Initializes the specified startup info struct with the required properties and // updates its thread attribute list with the specified ConPTY handle -HRESULT ConPtyAnonymousPipeProcess::initializeStartupInfoAttachedToPseudoConsole(STARTUPINFOEX* pStartupInfo, HPCON hPC) +HRESULT ConPtyProcess::initializeStartupInfoAttachedToPseudoConsole(STARTUPINFOEX* pStartupInfo, HPCON hPC) { HRESULT hr{ E_UNEXPECTED }; @@ -75,7 +75,7 @@ HRESULT ConPtyAnonymousPipeProcess::initializeStartupInfoAttachedToPseudoConsole return hr; } -ConPtyAnonymousPipeProcess::ConPtyAnonymousPipeProcess() +ConPtyProcess::ConPtyProcess() : IPtyProcess() , m_ptyHandler { INVALID_HANDLE_VALUE } , m_hPipeIn { INVALID_HANDLE_VALUE } @@ -85,12 +85,12 @@ ConPtyAnonymousPipeProcess::ConPtyAnonymousPipeProcess() } -ConPtyAnonymousPipeProcess::~ConPtyAnonymousPipeProcess() +ConPtyProcess::~ConPtyProcess() { kill(); } -bool ConPtyAnonymousPipeProcess::startProcess(const QString &shellPath, QStringList environment, qint16 cols, qint16 rows) +bool ConPtyProcess::startProcess(const QString &shellPath, QStringList environment, qint16 cols, qint16 rows) { if (!isAvailable()) { @@ -213,7 +213,7 @@ bool ConPtyAnonymousPipeProcess::startProcess(const QString &shellPath, QStringL return true; } -bool ConPtyAnonymousPipeProcess::resize(qint16 cols, qint16 rows) +bool ConPtyProcess::resize(qint16 cols, qint16 rows) { if (m_ptyHandler == nullptr) { @@ -232,7 +232,7 @@ bool ConPtyAnonymousPipeProcess::resize(qint16 cols, qint16 rows) return true; } -bool ConPtyAnonymousPipeProcess::kill() +bool ConPtyProcess::kill() { bool exitCode = false; @@ -261,13 +261,13 @@ bool ConPtyAnonymousPipeProcess::kill() return exitCode; } -IPtyProcess::PtyType ConPtyAnonymousPipeProcess::type() +IPtyProcess::PtyType ConPtyProcess::type() { return PtyType::ConPty; } #ifdef PTYQT_DEBUG -QString ConPtyAnonymousPipeProcess::dumpDebugInfo() +QString ConPtyProcess::dumpDebugInfo() { return QString("PID: %1, Type: %2, Cols: %3, Rows: %4") .arg(m_pid).arg(type()) @@ -275,25 +275,25 @@ QString ConPtyAnonymousPipeProcess::dumpDebugInfo() } #endif -QIODevice *ConPtyAnonymousPipeProcess::notifier() +QIODevice *ConPtyProcess::notifier() { return &m_buffer; } -QByteArray ConPtyAnonymousPipeProcess::readAll() +QByteArray ConPtyProcess::readAll() { QMutexLocker locker(&m_bufferMutex); return m_buffer.m_readBuffer; } -qint64 ConPtyAnonymousPipeProcess::write(const QByteArray &byteArray) +qint64 ConPtyProcess::write(const QByteArray &byteArray) { DWORD dwBytesWritten{}; WriteFile(m_hPipeOut, byteArray.data(), byteArray.size(), &dwBytesWritten, NULL); return dwBytesWritten; } -bool ConPtyAnonymousPipeProcess::isAvailable() +bool ConPtyProcess::isAvailable() { #ifdef TOO_OLD_WINSDK return false; //very importnant! ConPty can be built, but it doesn't work if built with old sdk and Win10 < 1903 diff --git a/core/conpty_shared.h b/core/conptyprocess.h similarity index 60% rename from core/conpty_shared.h rename to core/conptyprocess.h index e6fe536..2872f4a 100644 --- a/core/conpty_shared.h +++ b/core/conptyprocess.h @@ -1,11 +1,14 @@ -#ifndef CONPTY_SHARED_H -#define CONPTY_SHARED_H +#ifndef CONPTYPROCESS_H +#define CONPTYPROCESS_H #include "iptyprocess.h" #include #include #include #include +#include +#include +#include //Taken from the RS5 Windows SDK, but redefined here in case we're targeting <= 17733 //Just for compile, ConPty doesn't work with Windows SDK < 17733 @@ -92,4 +95,67 @@ private: QString m_lastError; }; -#endif // CONPTY_SHARED_H +class PtyBuffer : public QIODevice +{ + friend class ConPtyProcess; + Q_OBJECT +public: + + PtyBuffer() { } + ~PtyBuffer() { } + + //just empty realization, we need only 'readyRead' signal of this class + qint64 readData(char *data, qint64 maxlen) { return 0; } + qint64 writeData(const char *data, qint64 len) { return 0; } + + bool isSequential() { return true; } + qint64 bytesAvailable() { return m_readBuffer.size(); } + qint64 size() { return m_readBuffer.size(); } + + void emitReadyRead() + { + //for emit signal from PtyBuffer own thread + QTimer::singleShot(1, this, [this]() + { + emit readyRead(); + }); + } + +private: + QByteArray m_readBuffer; +}; + +class ConPtyProcess : public IPtyProcess +{ +public: + ConPtyProcess(); + ~ConPtyProcess(); + + bool startProcess(const QString &shellPath, QStringList environment, qint16 cols, qint16 rows); + bool resize(qint16 cols, qint16 rows); + bool kill(); + PtyType type(); +#ifdef PTYQT_DEBUG + QString dumpDebugInfo(); +#endif + virtual QIODevice *notifier(); + virtual QByteArray readAll(); + virtual qint64 write(const QByteArray &byteArray); + bool isAvailable(); + +private: + HRESULT createPseudoConsoleAndPipes(HPCON* phPC, HANDLE* phPipeIn, HANDLE* phPipeOut, qint16 cols, qint16 rows); + HRESULT initializeStartupInfoAttachedToPseudoConsole(STARTUPINFOEX* pStartupInfo, HPCON hPC); + +private: + WindowsContext m_winContext; + HPCON m_ptyHandler; + HANDLE m_hPipeIn, m_hPipeOut; + + QThread *m_readThread; + QMutex m_bufferMutex; + PtyBuffer m_buffer; + +}; + +#endif // CONPTYPROCESS_H diff --git a/core/iptyprocess.h b/core/iptyprocess.h index dab576c..648e551 100644 --- a/core/iptyprocess.h +++ b/core/iptyprocess.h @@ -17,9 +17,8 @@ public: { UnixPty = 0, WinPty = 1, - //ConPtyNamedPipe = 2, - ConPty = 3, - AutoPty = 4 + ConPty = 2, + AutoPty = 3 }; IPtyProcess() @@ -49,34 +48,4 @@ protected: QPair m_size; //cols / rows }; -#ifdef Q_OS_WIN -class IWindowsPtyProcess : public IPtyProcess -{ -protected: - IWindowsPtyProcess() - : IPtyProcess() - { } - - QIODevice *notifier() - { - return &m_outSocket; - } - - QByteArray readAll() - { - return m_outSocket.readAll(); - } - - qint64 write(const QByteArray &byteArray) - { - return m_inSocket.write(byteArray); - } -protected: - QString m_conInName; - QString m_conOutName; - QLocalSocket m_inSocket; - QLocalSocket m_outSocket; -}; -#endif - #endif // IPTYPROCESS_H diff --git a/core/ptyqt.cpp b/core/ptyqt.cpp index 4461eba..3ea2581 100644 --- a/core/ptyqt.cpp +++ b/core/ptyqt.cpp @@ -3,8 +3,7 @@ #ifdef Q_OS_WIN #include "winptyprocess.h" -//#include "conptynamedpipeprocess.h" -#include "conptyanonymouspipeprocess.h" +#include "conptyprocess.h" #endif #ifdef Q_OS_UNIX @@ -19,11 +18,8 @@ IPtyProcess *PtyQt::createPtyProcess(IPtyProcess::PtyType ptyType) case IPtyProcess::PtyType::WinPty: return new WinPtyProcess(); break; -// case IPtyProcess::PtyType::ConPtyNamedPipe: -// return new ConPtyNamedPipeProcess(); -// break; case IPtyProcess::PtyType::ConPty: - return new ConPtyAnonymousPipeProcess(); + return new ConPtyProcess(); break; #endif #ifdef Q_OS_UNIX @@ -37,8 +33,8 @@ IPtyProcess *PtyQt::createPtyProcess(IPtyProcess::PtyType ptyType) } #ifdef Q_OS_WIN - if (ConPtyAnonymousPipeProcess().isAvailable()) - return new ConPtyAnonymousPipeProcess(); + if (ConPtyProcess().isAvailable()) + return new ConPtyProcess(); else return new WinPtyProcess(); #endif diff --git a/core/winptyprocess.cpp b/core/winptyprocess.cpp index c6f3099..7062efb 100644 --- a/core/winptyprocess.cpp +++ b/core/winptyprocess.cpp @@ -16,7 +16,7 @@ QString castErrorToString(winpty_error_ptr_t error_ptr) } WinPtyProcess::WinPtyProcess() - : IWindowsPtyProcess() + : IPtyProcess() , m_ptyHandler(nullptr) , m_innerHandle(nullptr) { @@ -189,6 +189,21 @@ QString WinPtyProcess::dumpDebugInfo() .arg(m_size.first).arg(m_size.second).arg(m_ptyHandler != nullptr) .arg(m_shellPath); } + +QIODevice *WinPtyProcess::notifier() +{ + return &m_outSocket; +} + +QByteArray WinPtyProcess::readAll() +{ + return m_outSocket.readAll(); +} + +qint64 WinPtyProcess::write(const QByteArray &byteArray) +{ + return m_inSocket.write(byteArray); +} #endif bool WinPtyProcess::isAvailable() diff --git a/core/winptyprocess.h b/core/winptyprocess.h index 43eef23..4b4a1c1 100644 --- a/core/winptyprocess.h +++ b/core/winptyprocess.h @@ -4,7 +4,7 @@ #include "iptyprocess.h" #include "winpty.h" -class WinPtyProcess : public IWindowsPtyProcess +class WinPtyProcess : public IPtyProcess { public: WinPtyProcess(); @@ -17,11 +17,18 @@ public: #ifdef PTYQT_DEBUG QString dumpDebugInfo(); #endif + QIODevice *notifier(); + QByteArray readAll(); + qint64 write(const QByteArray &byteArray); bool isAvailable(); private: winpty_t *m_ptyHandler; HANDLE m_innerHandle; + QString m_conInName; + QString m_conOutName; + QLocalSocket m_inSocket; + QLocalSocket m_outSocket; }; #endif // WINPTYPROCESS_H diff --git a/tests/ptyqt_tests.cpp b/tests/ptyqt_tests.cpp index 1240e32..b6d834b 100644 --- a/tests/ptyqt_tests.cpp +++ b/tests/ptyqt_tests.cpp @@ -193,7 +193,6 @@ private slots: { qDebug() << "Test" << shellPath; IPtyProcess::PtyType ptyType = IPtyProcess::ConPty; - //ptyType = IPtyProcess::ConPtyNamedPipe; QScopedPointer conPty(PtyQt::createPtyProcess(ptyType)); QCOMPARE(conPty->type(), ptyType); QVERIFY(conPty->isAvailable());