/************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** 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-3.0.html. ** ** $QT_END_LICENSE$ ** **************************************************************************/ #include "qprocesswrapper.h" #include "protocol.h" #include "utils.h" #include namespace QInstaller { QProcessWrapper::QProcessWrapper(QObject *parent) : RemoteObject(QLatin1String(Protocol::QProcess), parent) { qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); m_timer.start(250); connect(&m_timer, &QTimer::timeout, this, &QProcessWrapper::processSignals); connect(&process, &QIODevice::bytesWritten, this, &QProcessWrapper::bytesWritten); connect(&process, &QIODevice::aboutToClose, this, &QProcessWrapper::aboutToClose); connect(&process, &QIODevice::readChannelFinished, this, &QProcessWrapper::readChannelFinished); connect(&process, SIGNAL(error(QProcess::ProcessError)), SIGNAL(error(QProcess::ProcessError))); connect(&process, &QProcess::readyReadStandardOutput, this, &QProcessWrapper::readyReadStandardOutput); connect(&process, &QProcess::readyReadStandardError, this, &QProcessWrapper::readyReadStandardError); connect(&process, SIGNAL(finished(int,QProcess::ExitStatus)), SIGNAL(finished(int,QProcess::ExitStatus))); connect(&process, &QIODevice::readyRead, this, &QProcessWrapper::readyRead); connect(&process, &QProcess::started, this, &QProcessWrapper::started); connect(&process, &QProcess::stateChanged, this, &QProcessWrapper::stateChanged); } QProcessWrapper::~QProcessWrapper() { m_timer.stop(); } void QProcessWrapper::processSignals() { if (!isConnectedToServer()) return; if (!m_lock.tryLockForRead()) return; QList receivedSignals = callRemoteMethod >(QString::fromLatin1(Protocol::GetQProcessSignals)); while (!receivedSignals.isEmpty()) { const QString name = receivedSignals.takeFirst().toString(); if (name == QLatin1String(Protocol::QProcessSignalBytesWritten)) { emit bytesWritten(receivedSignals.takeFirst().value()); } else if (name == QLatin1String(Protocol::QProcessSignalAboutToClose)) { emit aboutToClose(); } else if (name == QLatin1String(Protocol::QProcessSignalReadChannelFinished)) { emit readChannelFinished(); } else if (name == QLatin1String(Protocol::QProcessSignalError)) { emit error(static_cast (receivedSignals.takeFirst().toInt())); } else if (name == QLatin1String(Protocol::QProcessSignalReadyReadStandardOutput)) { emit readyReadStandardOutput(); } else if (name == QLatin1String(Protocol::QProcessSignalReadyReadStandardError)) { emit readyReadStandardError(); } else if (name == QLatin1String(Protocol::QProcessSignalStarted)) { emit started(); } else if (name == QLatin1String(Protocol::QProcessSignalReadyRead)) { emit readyRead(); } else if (name == QLatin1String(Protocol::QProcessSignalStateChanged)) { emit stateChanged(static_cast (receivedSignals.takeFirst() .toInt())); } else if (name == QLatin1String(Protocol::QProcessSignalFinished)) { emit finished(receivedSignals.takeFirst().toInt(), static_cast (receivedSignals.takeFirst().toInt())); } } m_lock.unlock(); } bool QProcessWrapper::startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory, qint64 *pid) { QProcessWrapper w; if (w.connectToServer()) { const QPair result = w.callRemoteMethod >(QLatin1String(Protocol::QProcessStartDetached), program, arguments, workingDirectory); if (pid != 0) *pid = result.second; w.processSignals(); return result.first; } return QInstaller::startDetached(program, arguments, workingDirectory, pid); } bool QProcessWrapper::startDetached(const QString &program, const QStringList &arguments) { return startDetached(program, arguments, QDir::currentPath()); } bool QProcessWrapper::startDetached(const QString &program) { return startDetached(program, QStringList()); } void QProcessWrapper::setProcessChannelMode(QProcessWrapper::ProcessChannelMode mode) { if (connectToServer()) { m_lock.lockForWrite(); callRemoteMethod(QLatin1String(Protocol::QProcessSetProcessChannelMode), static_cast(mode), dummy); m_lock.unlock(); } else { process.setProcessChannelMode(static_cast(mode)); } } /*! Cancels the process. This methods tries to terminate the process gracefully by calling QProcess::terminate. After 10 seconds, the process gets killed. */ void QProcessWrapper::cancel() { if (state() == QProcessWrapper::Running) terminate(); if (!waitForFinished(10000)) kill(); } void QProcessWrapper::setReadChannel(QProcessWrapper::ProcessChannel chan) { if (connectToServer()) { m_lock.lockForWrite(); callRemoteMethod(QLatin1String(Protocol::QProcessSetReadChannel), static_cast(chan), dummy); m_lock.unlock(); } else { process.setReadChannel(static_cast(chan)); } } bool QProcessWrapper::waitForFinished(int msecs) { if (connectToServer()) { m_lock.lockForWrite(); const bool value = callRemoteMethod(QLatin1String(Protocol::QProcessWaitForFinished), qint32(msecs)); m_lock.unlock(); return value; } return process.waitForFinished(msecs); } bool QProcessWrapper::waitForStarted(int msecs) { if (connectToServer()) { m_lock.lockForWrite(); const bool value = callRemoteMethod(QLatin1String(Protocol::QProcessWaitForStarted), qint32(msecs)); m_lock.unlock(); return value; } return process.waitForStarted(msecs); } qint64 QProcessWrapper::write(const QByteArray &data) { if (connectToServer()) { m_lock.lockForWrite(); const qint64 value = callRemoteMethod(QLatin1String(Protocol::QProcessWrite), data); m_lock.unlock(); return value; } return process.write(data); } void QProcessWrapper::closeWriteChannel() { if (connectToServer()) { m_lock.lockForWrite(); callRemoteMethod(QLatin1String(Protocol::QProcessCloseWriteChannel)); m_lock.unlock(); } else { process.closeWriteChannel(); } } int QProcessWrapper::exitCode() const { if ((const_cast(this))->connectToServer()) { m_lock.lockForWrite(); const int value = callRemoteMethod(QLatin1String(Protocol::QProcessExitCode)); m_lock.unlock(); return value; } return process.exitCode(); } QProcessWrapper::ExitStatus QProcessWrapper::exitStatus() const { if ((const_cast(this))->connectToServer()) { m_lock.lockForWrite(); const int status = callRemoteMethod(QLatin1String(Protocol::QProcessExitStatus)); m_lock.unlock(); return static_cast(status); } return static_cast(process.exitStatus()); } void QProcessWrapper::kill() { if (connectToServer()) { m_lock.lockForWrite(); callRemoteMethod(QLatin1String(Protocol::QProcessKill)); m_lock.unlock(); } else { process.kill(); } } QByteArray QProcessWrapper::readAll() { if (connectToServer()) { m_lock.lockForWrite(); const QByteArray ba = callRemoteMethod(QLatin1String(Protocol::QProcessReadAll)); m_lock.unlock(); return ba; } return process.readAll(); } QByteArray QProcessWrapper::readAllStandardOutput() { if (connectToServer()) { m_lock.lockForWrite(); const QByteArray ba = callRemoteMethod(QLatin1String(Protocol::QProcessReadAllStandardOutput)); m_lock.unlock(); return ba; } return process.readAllStandardOutput(); } QByteArray QProcessWrapper::readAllStandardError() { if (connectToServer()) { m_lock.lockForWrite(); const QByteArray ba = callRemoteMethod(QLatin1String(Protocol::QProcessReadAllStandardError)); m_lock.unlock(); return ba; } return process.readAllStandardError(); } void QProcessWrapper::start(const QString ¶m1, const QStringList ¶m2, QIODevice::OpenMode param3) { if (connectToServer()) { m_lock.lockForWrite(); callRemoteMethod(QLatin1String(Protocol::QProcessStart3Arg), param1, param2, param3); m_lock.unlock(); } else { process.start(param1, param2, param3); } } void QProcessWrapper::start(const QString ¶m1, QIODevice::OpenMode param2) { if (connectToServer()) { m_lock.lockForWrite(); callRemoteMethod(QLatin1String(Protocol::QProcessStart2Arg), param1, param2); m_lock.unlock(); } else { process.start(param1, param2); } } QProcessWrapper::ProcessState QProcessWrapper::state() const { if ((const_cast(this))->connectToServer()) { m_lock.lockForWrite(); const int state = callRemoteMethod(QLatin1String(Protocol::QProcessState)); m_lock.unlock(); return static_cast(state); } return static_cast(process.state()); } void QProcessWrapper::terminate() { if (connectToServer()) { m_lock.lockForWrite(); callRemoteMethod(QLatin1String(Protocol::QProcessTerminate)); m_lock.unlock(); } else { process.terminate(); } } QProcessWrapper::ProcessChannel QProcessWrapper::readChannel() const { if ((const_cast(this))->connectToServer()) { m_lock.lockForWrite(); const int channel = callRemoteMethod(QLatin1String(Protocol::QProcessReadChannel)); m_lock.unlock(); return static_cast(channel); } return static_cast(process.readChannel()); } QProcessWrapper::ProcessChannelMode QProcessWrapper::processChannelMode() const { if ((const_cast(this))->connectToServer()) { m_lock.lockForWrite(); const int mode = callRemoteMethod(QLatin1String(Protocol::QProcessProcessChannelMode)); m_lock.unlock(); return static_cast(mode); } return static_cast(process.processChannelMode()); } QString QProcessWrapper::workingDirectory() const { if ((const_cast(this))->connectToServer()) { m_lock.lockForWrite(); const QString dir = callRemoteMethod(QLatin1String(Protocol::QProcessWorkingDirectory)); m_lock.unlock(); return dir; } return static_cast(process.workingDirectory()); } QString QProcessWrapper::errorString() const { if ((const_cast(this))->connectToServer()) { m_lock.lockForWrite(); const QString error = callRemoteMethod(QLatin1String(Protocol::QProcessErrorString)); m_lock.unlock(); return error; } return static_cast(process.errorString()); } QStringList QProcessWrapper::environment() const { if ((const_cast(this))->connectToServer()) { m_lock.lockForWrite(); const QStringList env = callRemoteMethod(QLatin1String(Protocol::QProcessEnvironment)); m_lock.unlock(); return env; } return process.environment(); } void QProcessWrapper::setEnvironment(const QStringList ¶m1) { if (connectToServer()) { m_lock.lockForWrite(); callRemoteMethod(QLatin1String(Protocol::QProcessSetEnvironment), param1, dummy); m_lock.unlock(); } else { process.setEnvironment(param1); } } #ifdef Q_OS_WIN void QProcessWrapper::setNativeArguments(const QString ¶m1) { if (connectToServer()) { m_lock.lockForWrite(); callRemoteMethod(QLatin1String(Protocol::QProcessSetNativeArguments), param1, dummy); m_lock.unlock(); } else { process.setNativeArguments(param1); } } #endif void QProcessWrapper::setWorkingDirectory(const QString ¶m1) { if (connectToServer()) { m_lock.lockForWrite(); callRemoteMethod(QLatin1String(Protocol::QProcessSetWorkingDirectory), param1, dummy); m_lock.unlock(); } else { process.setWorkingDirectory(param1); } } } // namespace QInstaller