diff options
author | Oswald Buddenhagen <oswald.buddenhagen@nokia.com> | 2011-05-11 12:48:14 +0200 |
---|---|---|
committer | Oswald Buddenhagen <oswald.buddenhagen@nokia.com> | 2011-05-12 20:39:44 +0200 |
commit | 322a8481a754109b7dd8306598fce39f49e57ad9 (patch) | |
tree | 2d7717123a8d408049660758350359abf4890560 | |
parent | 9a2814d64684d423cb0a373d029ba697d1bf9ba3 (diff) | |
download | qt-creator-322a8481a754109b7dd8306598fce39f49e57ad9.tar.gz |
unify application launcher between platforms
purge abstractprocess and winguiprocess. they serve no purpose.
applications can have stdio on windows as well, in addition to the
windows debug channel.
Task-number: QTCREATORBUG-4822
-rw-r--r-- | src/libs/utils/abstractprocess.h | 87 | ||||
-rw-r--r-- | src/libs/utils/abstractprocess_win.cpp | 129 | ||||
-rw-r--r-- | src/libs/utils/consoleprocess.cpp | 52 | ||||
-rw-r--r-- | src/libs/utils/consoleprocess.h | 20 | ||||
-rw-r--r-- | src/libs/utils/consoleprocess_p.h (renamed from src/libs/utils/abstractprocess.cpp) | 68 | ||||
-rw-r--r-- | src/libs/utils/consoleprocess_unix.cpp | 60 | ||||
-rw-r--r-- | src/libs/utils/consoleprocess_win.cpp | 134 | ||||
-rw-r--r-- | src/libs/utils/utils-lib.pri | 5 | ||||
-rw-r--r-- | src/plugins/debugger/qml/qmlengine.cpp | 3 | ||||
-rw-r--r-- | src/plugins/projectexplorer/applicationlauncher.cpp (renamed from src/plugins/projectexplorer/applicationlauncher_x11.cpp) | 60 | ||||
-rw-r--r-- | src/plugins/projectexplorer/applicationlauncher.h | 11 | ||||
-rw-r--r-- | src/plugins/projectexplorer/applicationlauncher_win.cpp | 154 | ||||
-rw-r--r-- | src/plugins/projectexplorer/projectexplorer.pro | 7 | ||||
-rw-r--r-- | src/plugins/projectexplorer/windebuginterface.cpp | 2 | ||||
-rw-r--r-- | src/plugins/projectexplorer/winguiprocess.cpp | 173 | ||||
-rw-r--r-- | src/plugins/projectexplorer/winguiprocess.h | 85 |
16 files changed, 256 insertions, 794 deletions
diff --git a/src/libs/utils/abstractprocess.h b/src/libs/utils/abstractprocess.h deleted file mode 100644 index 98bc07f72e..0000000000 --- a/src/libs/utils/abstractprocess.h +++ /dev/null @@ -1,87 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (info@qt.nokia.com) -** -** -** GNU Lesser General Public License Usage -** -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this file. -** Please review the following information to ensure the GNU Lesser General -** Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** Other Usage -** -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** If you have questions regarding the use of this file, please contact -** Nokia at info@qt.nokia.com. -** -**************************************************************************/ - -#ifndef ABSTRACTPROCESS_H -#define ABSTRACTPROCESS_H - -#include "utils_global.h" - -#include "environment.h" - -#include <QtCore/QStringList> - -namespace Utils { - -class QTCREATOR_UTILS_EXPORT AbstractProcess -{ -public: - AbstractProcess(); - virtual ~AbstractProcess(); - - QString workingDirectory() const; - void setWorkingDirectory(const QString &dir); - - void setEnvironment(const Environment &env); - Environment environment() const; - - virtual bool start(const QString &program, const QString &args) = 0; - virtual void stop() = 0; - - virtual bool isRunning() const = 0; - virtual qint64 applicationPID() const = 0; - virtual int exitCode() const = 0; - - static QString msgWinCannotRetrieveDebuggingOutput(); - -//signals: - virtual void processMessage(const QString &error, bool isError) = 0; - -#ifdef Q_OS_WIN - // Add PATH and SystemRoot environment variables in case they are missing - static QStringList fixWinEnvironment(const QStringList &env); - // Quote a Windows command line correctly for the "CreateProcess" API - static QString createWinCommandline(const QString &program, const QStringList &args); - static QString createWinCommandline(const QString &program, const QString &args); - // Create a bytearray suitable to be passed on as environment - // to the "CreateProcess" API (0-terminated UTF 16 strings). - static QByteArray createWinEnvironment(const QStringList &env); -#endif - -protected: - QString m_workingDir; - Environment m_environment; -}; - -} //namespace Utils - -#endif // ABSTRACTPROCESS_H - diff --git a/src/libs/utils/abstractprocess_win.cpp b/src/libs/utils/abstractprocess_win.cpp deleted file mode 100644 index 8faf3711fa..0000000000 --- a/src/libs/utils/abstractprocess_win.cpp +++ /dev/null @@ -1,129 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (info@qt.nokia.com) -** -** -** GNU Lesser General Public License Usage -** -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this file. -** Please review the following information to ensure the GNU Lesser General -** Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** Other Usage -** -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** If you have questions regarding the use of this file, please contact -** Nokia at info@qt.nokia.com. -** -**************************************************************************/ - -#include "abstractprocess.h" - -#include <windows.h> - -namespace Utils { - -QStringList AbstractProcess::fixWinEnvironment(const QStringList &env) -{ - QStringList envStrings = env; - // add PATH if necessary (for DLL loading) - if (envStrings.filter(QRegExp(QLatin1String("^PATH="),Qt::CaseInsensitive)).isEmpty()) { - QByteArray path = qgetenv("PATH"); - if (!path.isEmpty()) - envStrings.prepend(QString(QLatin1String("PATH=%1")).arg(QString::fromLocal8Bit(path))); - } - // add systemroot if needed - if (envStrings.filter(QRegExp(QLatin1String("^SystemRoot="),Qt::CaseInsensitive)).isEmpty()) { - QByteArray systemRoot = qgetenv("SystemRoot"); - if (!systemRoot.isEmpty()) - envStrings.prepend(QString(QLatin1String("SystemRoot=%1")).arg(QString::fromLocal8Bit(systemRoot))); - } - return envStrings; -} - -static QString quoteWinCommand(const QString &program) -{ - const QChar doubleQuote = QLatin1Char('"'); - - // add the program as the first arg ... it works better - QString programName = program; - programName.replace(QLatin1Char('/'), QLatin1Char('\\')); - if (!programName.startsWith(doubleQuote) && !programName.endsWith(doubleQuote) - && programName.contains(QLatin1Char(' '))) { - programName.prepend(doubleQuote); - programName.append(doubleQuote); - } - return programName; -} - -static QString quoteWinArgument(const QString &arg) -{ - if (!arg.length()) - return QString::fromLatin1("\"\""); - - QString ret(arg); - // Quotes are escaped and their preceding backslashes are doubled. - ret.replace(QRegExp(QLatin1String("(\\\\*)\"")), QLatin1String("\\1\\1\\\"")); - if (ret.contains(QRegExp(QLatin1String("\\s")))) { - // The argument must not end with a \ since this would be interpreted - // as escaping the quote -- rather put the \ behind the quote: e.g. - // rather use "foo"\ than "foo\" - int i = ret.length(); - while (i > 0 && ret.at(i - 1) == QLatin1Char('\\')) - --i; - ret.insert(i, QLatin1Char('"')); - ret.prepend(QLatin1Char('"')); - } - return ret; -} - -QString AbstractProcess::createWinCommandline(const QString &program, const QStringList &args) -{ - QString programName = quoteWinCommand(program); - foreach (const QString &arg, args) { - programName += QLatin1Char(' '); - programName += quoteWinArgument(arg); - } - return programName; -} - -QString AbstractProcess::createWinCommandline(const QString &program, const QString &args) -{ - QString programName = quoteWinCommand(program); - if (!args.isEmpty()) { - programName += QLatin1Char(' '); - programName += args; - } - return programName; -} - -QByteArray AbstractProcess::createWinEnvironment(const QStringList &env) -{ - QByteArray envlist; - int pos = 0; - foreach (const QString &tmp, env) { - const uint tmpSize = sizeof(TCHAR) * (tmp.length() + 1); - envlist.resize(envlist.size() + tmpSize); - memcpy(envlist.data() + pos, tmp.utf16(), tmpSize); - pos += tmpSize; - } - envlist.resize(envlist.size() + 2); - envlist[pos++] = 0; - envlist[pos++] = 0; - return envlist; -} - -} //namespace Utils diff --git a/src/libs/utils/consoleprocess.cpp b/src/libs/utils/consoleprocess.cpp index d484be901c..0c7c8702c8 100644 --- a/src/libs/utils/consoleprocess.cpp +++ b/src/libs/utils/consoleprocess.cpp @@ -30,10 +30,25 @@ ** **************************************************************************/ -#include "consoleprocess.h" +#include "consoleprocess_p.h" namespace Utils { +ConsoleProcess::~ConsoleProcess() +{ + stop(); +} + +void ConsoleProcess::setMode(Mode m) +{ + d->m_mode = m; +} + +ConsoleProcess::Mode ConsoleProcess::mode() const +{ + return d->m_mode; +} + QString ConsoleProcess::modeOption(Mode m) { switch (m) { @@ -47,6 +62,41 @@ QString ConsoleProcess::modeOption(Mode m) return QLatin1String("run"); } +qint64 ConsoleProcess::applicationPID() const +{ + return d->m_appPid; +} + +int ConsoleProcess::exitCode() const +{ + return d->m_appCode; +} // This will be the signal number if exitStatus == CrashExit + +QProcess::ExitStatus ConsoleProcess::exitStatus() const +{ + return d->m_appStatus; +} + +void ConsoleProcess::setWorkingDirectory(const QString &dir) +{ + d->m_workingDir = dir; +} + +QString ConsoleProcess::workingDirectory() const +{ + return d->m_workingDir; +} + +void ConsoleProcess::setEnvironment(const Environment &env) +{ + d->m_environment = env; +} + +Environment ConsoleProcess::environment() const +{ + return d->m_environment; +} + QString ConsoleProcess::msgCommChannelFailed(const QString &error) { return tr("Cannot set up communication channel: %1").arg(error); diff --git a/src/libs/utils/consoleprocess.h b/src/libs/utils/consoleprocess.h index 3152b7ccd3..cc83b12192 100644 --- a/src/libs/utils/consoleprocess.h +++ b/src/libs/utils/consoleprocess.h @@ -33,7 +33,9 @@ #ifndef CONSOLEPROCESS_H #define CONSOLEPROCESS_H -#include "abstractprocess.h" +#include "utils_global.h" + +#include "environment.h" #include <QtCore/QObject> #include <QtCore/QString> @@ -48,7 +50,7 @@ QT_END_NAMESPACE namespace Utils { struct ConsoleProcessPrivate; -class QTCREATOR_UTILS_EXPORT ConsoleProcess : public QObject, public AbstractProcess +class QTCREATOR_UTILS_EXPORT ConsoleProcess : public QObject { Q_OBJECT @@ -57,6 +59,12 @@ public: ConsoleProcess(QObject *parent = 0); ~ConsoleProcess(); + void setWorkingDirectory(const QString &dir); + QString workingDirectory() const; + + void setEnvironment(const Environment &env); + Environment environment() const; + bool start(const QString &program, const QString &args); void stop(); @@ -73,7 +81,13 @@ public: int exitCode() const; QProcess::ExitStatus exitStatus() const; -#ifdef Q_OS_UNIX +#ifdef Q_OS_WIN + // Add PATH and SystemRoot environment variables in case they are missing + static QStringList fixWinEnvironment(const QStringList &env); + // Quote a Windows command line correctly for the "CreateProcess" API + static QString createWinCommandline(const QString &program, const QStringList &args); + static QString createWinCommandline(const QString &program, const QString &args); +#else void setSettings(QSettings *settings); static QString defaultTerminalEmulator(); static QString terminalEmulator(const QSettings *settings); diff --git a/src/libs/utils/abstractprocess.cpp b/src/libs/utils/consoleprocess_p.h index afa4610656..5d0441cd89 100644 --- a/src/libs/utils/abstractprocess.cpp +++ b/src/libs/utils/consoleprocess_p.h @@ -30,45 +30,51 @@ ** **************************************************************************/ -#include "abstractprocess.h" +#ifndef CONSOLEPROCESS_P_H +#define CONSOLEPROCESS_P_H -#include <QtCore/QCoreApplication> +#include "consoleprocess.h" -namespace Utils { - -AbstractProcess::AbstractProcess() -{ -} +#include <QtCore/QTemporaryFile> -AbstractProcess::~AbstractProcess() -{ -} +#include <QtNetwork/QLocalSocket> +#include <QtNetwork/QLocalServer> -QString AbstractProcess::workingDirectory() const -{ - return m_workingDir; -} +#ifdef Q_OS_WIN +#include <QtCore/private/qwineventnotifier_p.h> -void AbstractProcess::setWorkingDirectory(const QString &dir) -{ - m_workingDir = dir; -} +#include <windows.h> +#endif -void AbstractProcess::setEnvironment(const Environment &env) -{ - m_environment = env; -} +namespace Utils { -Environment AbstractProcess::environment() const -{ - return m_environment; -} +struct ConsoleProcessPrivate { + ConsoleProcessPrivate(); -QString AbstractProcess::msgWinCannotRetrieveDebuggingOutput() -{ - return QCoreApplication::translate("Utils::AbstractProcess", "Cannot retrieve debugging output.\n"); -} + ConsoleProcess::Mode m_mode; + QString m_workingDir; + Environment m_environment; + qint64 m_appPid; + int m_appCode; + QString m_executable; + QProcess::ExitStatus m_appStatus; + QLocalServer m_stubServer; + QLocalSocket *m_stubSocket; + QTemporaryFile *m_tempFile; -} // namespace Utils +#ifdef Q_OS_UNIX + QProcess m_process; + QByteArray m_stubServerDir; + QSettings *m_settings; +#else + qint64 m_appMainThreadId; + PROCESS_INFORMATION *m_pid; + HANDLE m_hInferior; + QWinEventNotifier *inferiorFinishedNotifier; + QWinEventNotifier *processFinishedNotifier; +#endif +}; +} //namespace Utils +#endif diff --git a/src/libs/utils/consoleprocess_unix.cpp b/src/libs/utils/consoleprocess_unix.cpp index 180c4cab43..4e492e027c 100644 --- a/src/libs/utils/consoleprocess_unix.cpp +++ b/src/libs/utils/consoleprocess_unix.cpp @@ -30,7 +30,7 @@ ** **************************************************************************/ -#include "consoleprocess.h" +#include "consoleprocess_p.h" #include "environment.h" #include "qtcprocess.h" @@ -38,10 +38,6 @@ #include <QtCore/QCoreApplication> #include <QtCore/QDir> #include <QtCore/QSettings> -#include <QtCore/QTemporaryFile> - -#include <QtNetwork/QLocalSocket> -#include <QtNetwork/QLocalServer> #include <sys/stat.h> #include <sys/types.h> @@ -50,23 +46,6 @@ #include <unistd.h> namespace Utils { -struct ConsoleProcessPrivate { - ConsoleProcessPrivate(); - - ConsoleProcess::Mode m_mode; - qint64 m_appPid; - qint64 m_appMainThreadId; - int m_appCode; - QString m_executable; - QProcess::ExitStatus m_appStatus; - QLocalServer m_stubServer; - QLocalSocket *m_stubSocket; - QTemporaryFile *m_tempFile; - - QProcess m_process; - QByteArray m_stubServerDir; - QSettings *m_settings; -}; ConsoleProcessPrivate::ConsoleProcessPrivate() : m_mode(ConsoleProcess::Run), @@ -76,6 +55,7 @@ ConsoleProcessPrivate::ConsoleProcessPrivate() : m_settings(0) { } + ConsoleProcess::ConsoleProcess(QObject *parent) : QObject(parent), d(new ConsoleProcessPrivate) { @@ -86,36 +66,6 @@ ConsoleProcess::ConsoleProcess(QObject *parent) : SLOT(stubExited())); } -ConsoleProcess::~ConsoleProcess() -{ - stop(); -} - -void ConsoleProcess::setMode(Mode m) -{ - d->m_mode = m; -} - -ConsoleProcess::Mode ConsoleProcess::mode() const -{ - return d->m_mode; -} - -qint64 ConsoleProcess::applicationPID() const -{ - return d->m_appPid; -} - -int ConsoleProcess::exitCode() const -{ - return d->m_appCode; -} // This will be the signal number if exitStatus == CrashExit - -QProcess::ExitStatus ConsoleProcess::exitStatus() const -{ - return d->m_appStatus; -} - void ConsoleProcess::setSettings(QSettings *settings) { d->m_settings = settings; @@ -127,7 +77,7 @@ bool ConsoleProcess::start(const QString &program, const QString &args) return false; QtcProcess::SplitError perr; - QStringList pargs = QtcProcess::prepareArgs(args, &perr, &m_environment, &m_workingDir); + QStringList pargs = QtcProcess::prepareArgs(args, &perr, &d->m_environment, &d->m_workingDir); QString pcmd; if (perr == QtcProcess::SplitOk) { pcmd = program; @@ -148,7 +98,7 @@ bool ConsoleProcess::start(const QString &program, const QString &args) QtcProcess::SplitError qerr; QStringList xtermArgs = QtcProcess::prepareArgs(terminalEmulator(d->m_settings), &qerr, - &m_environment, &m_workingDir); + &d->m_environment, &d->m_workingDir); if (qerr != QtcProcess::SplitOk) { emit processMessage(qerr == QtcProcess::BadQuoting ? tr("Quoting error in terminal command.") @@ -162,7 +112,7 @@ bool ConsoleProcess::start(const QString &program, const QString &args) return false; } - QStringList env = m_environment.toStringList(); + QStringList env = d->m_environment.toStringList(); if (!env.isEmpty()) { d->m_tempFile = new QTemporaryFile(); if (!d->m_tempFile->open()) { diff --git a/src/libs/utils/consoleprocess_win.cpp b/src/libs/utils/consoleprocess_win.cpp index 9ce134296d..3cab6f03a1 100644 --- a/src/libs/utils/consoleprocess_win.cpp +++ b/src/libs/utils/consoleprocess_win.cpp @@ -30,42 +30,18 @@ ** **************************************************************************/ -#include "consoleprocess.h" +#include "consoleprocess_p.h" #include "environment.h" #include "qtcprocess.h" #include "winutils.h" -#include <windows.h> - #include <QtCore/QCoreApplication> #include <QtCore/QDir> -#include <QtCore/QTemporaryFile> #include <QtCore/QAbstractEventDispatcher> -#include <QtCore/private/qwineventnotifier_p.h> - -#include <QtNetwork/QLocalSocket> -#include <QtNetwork/QLocalServer> #include <stdlib.h> namespace Utils { -struct ConsoleProcessPrivate { - ConsoleProcessPrivate(); - - ConsoleProcess::Mode m_mode; - qint64 m_appPid; - qint64 m_appMainThreadId; - int m_appCode; - QString m_executable; - QProcess::ExitStatus m_appStatus; - QLocalServer m_stubServer; - QLocalSocket *m_stubSocket; - QTemporaryFile *m_tempFile; - PROCESS_INFORMATION *m_pid; - HANDLE m_hInferior; - QWinEventNotifier *inferiorFinishedNotifier; - QWinEventNotifier *processFinishedNotifier; -}; ConsoleProcessPrivate::ConsoleProcessPrivate() : m_mode(ConsoleProcess::Run), @@ -85,41 +61,11 @@ ConsoleProcess::ConsoleProcess(QObject *parent) : connect(&d->m_stubServer, SIGNAL(newConnection()), SLOT(stubConnectionAvailable())); } -ConsoleProcess::~ConsoleProcess() -{ - stop(); -} - -void ConsoleProcess::setMode(Mode m) -{ - d->m_mode = m; -} - -ConsoleProcess::Mode ConsoleProcess::mode() const -{ - return d->m_mode; -} - -qint64 ConsoleProcess::applicationPID() const -{ - return d->m_appPid; -} - qint64 ConsoleProcess::applicationMainThreadID() const { return d->m_appMainThreadId; } -int ConsoleProcess::exitCode() const -{ - return d->m_appCode; -} // This will be the signal number if exitStatus == CrashExit - -QProcess::ExitStatus ConsoleProcess::exitStatus() const -{ - return d->m_appStatus; -} - bool ConsoleProcess::start(const QString &program, const QString &args) { if (isRunning()) @@ -131,7 +77,7 @@ bool ConsoleProcess::start(const QString &program, const QString &args) pcmd = program; pargs = args; } else { - QtcProcess::prepareCommand(program, args, &pcmd, &pargs, &m_environment, &m_workingDir); + QtcProcess::prepareCommand(program, args, &pcmd, &pargs, &d->m_environment, &d->m_workingDir); } const QString err = stubServerListen(); @@ -140,7 +86,7 @@ bool ConsoleProcess::start(const QString &program, const QString &args) return false; } - QStringList env = m_environment.toStringList(); + QStringList env = d->m_environment.toStringList(); if (!env.isEmpty()) { d->m_tempFile = new QTemporaryFile(); if (!d->m_tempFile->open()) { @@ -340,4 +286,78 @@ void ConsoleProcess::stubExited() emit wrapperStopped(); } +QStringList ConsoleProcess::fixWinEnvironment(const QStringList &env) +{ + QStringList envStrings = env; + // add PATH if necessary (for DLL loading) + if (envStrings.filter(QRegExp(QLatin1String("^PATH="),Qt::CaseInsensitive)).isEmpty()) { + QByteArray path = qgetenv("PATH"); + if (!path.isEmpty()) + envStrings.prepend(QString(QLatin1String("PATH=%1")).arg(QString::fromLocal8Bit(path))); + } + // add systemroot if needed + if (envStrings.filter(QRegExp(QLatin1String("^SystemRoot="),Qt::CaseInsensitive)).isEmpty()) { + QByteArray systemRoot = qgetenv("SystemRoot"); + if (!systemRoot.isEmpty()) + envStrings.prepend(QString(QLatin1String("SystemRoot=%1")).arg(QString::fromLocal8Bit(systemRoot))); + } + return envStrings; +} + +static QString quoteWinCommand(const QString &program) +{ + const QChar doubleQuote = QLatin1Char('"'); + + // add the program as the first arg ... it works better + QString programName = program; + programName.replace(QLatin1Char('/'), QLatin1Char('\\')); + if (!programName.startsWith(doubleQuote) && !programName.endsWith(doubleQuote) + && programName.contains(QLatin1Char(' '))) { + programName.prepend(doubleQuote); + programName.append(doubleQuote); + } + return programName; +} + +static QString quoteWinArgument(const QString &arg) +{ + if (!arg.length()) + return QString::fromLatin1("\"\""); + + QString ret(arg); + // Quotes are escaped and their preceding backslashes are doubled. + ret.replace(QRegExp(QLatin1String("(\\\\*)\"")), QLatin1String("\\1\\1\\\"")); + if (ret.contains(QRegExp(QLatin1String("\\s")))) { + // The argument must not end with a \ since this would be interpreted + // as escaping the quote -- rather put the \ behind the quote: e.g. + // rather use "foo"\ than "foo\" + int i = ret.length(); + while (i > 0 && ret.at(i - 1) == QLatin1Char('\\')) + --i; + ret.insert(i, QLatin1Char('"')); + ret.prepend(QLatin1Char('"')); + } + return ret; +} + +QString ConsoleProcess::createWinCommandline(const QString &program, const QStringList &args) +{ + QString programName = quoteWinCommand(program); + foreach (const QString &arg, args) { + programName += QLatin1Char(' '); + programName += quoteWinArgument(arg); + } + return programName; +} + +QString ConsoleProcess::createWinCommandline(const QString &program, const QString &args) +{ + QString programName = quoteWinCommand(program); + if (!args.isEmpty()) { + programName += QLatin1Char(' '); + programName += args; + } + return programName; +} + } // namespace Utils diff --git a/src/libs/utils/utils-lib.pri b/src/libs/utils/utils-lib.pri index 5e0b483e05..7528a4e14d 100644 --- a/src/libs/utils/utils-lib.pri +++ b/src/libs/utils/utils-lib.pri @@ -10,7 +10,6 @@ QT += network SOURCES += $$PWD/environment.cpp \ $$PWD/environmentmodel.cpp \ $$PWD/qtcprocess.cpp \ - $$PWD/abstractprocess.cpp \ $$PWD/reloadpromptutils.cpp \ $$PWD/stringutils.cpp \ $$PWD/filesearch.cpp \ @@ -85,7 +84,7 @@ SOURCES += $$PWD/environment.cpp \ $$PWD/outputformatter.cpp win32 { - SOURCES += $$PWD/abstractprocess_win.cpp \ + SOURCES += \ $$PWD/consoleprocess_win.cpp \ $$PWD/winutils.cpp HEADERS += $$PWD/winutils.h @@ -122,8 +121,8 @@ HEADERS += $$PWD/environment.h \ $$PWD/qtcolorbutton.h \ $$PWD/savedaction.h \ $$PWD/submiteditorwidget.h \ - $$PWD/abstractprocess.h \ $$PWD/consoleprocess.h \ + $$PWD/consoleprocess_p.h \ $$PWD/synchronousprocess.h \ $$PWD/savefile.h \ $$PWD/fileutils.h \ diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp index 2211633234..4155a9fd58 100644 --- a/src/plugins/debugger/qml/qmlengine.cpp +++ b/src/plugins/debugger/qml/qmlengine.cpp @@ -54,7 +54,6 @@ #include <projectexplorer/applicationlauncher.h> #include <utils/environment.h> -#include <utils/abstractprocess.h> #include <utils/qtcassert.h> #include <utils/fileinprojectfinder.h> @@ -295,7 +294,7 @@ bool QmlEngine::canDisplayTooltip() const void QmlEngine::filterApplicationMessage(const QString &msg, int /*channel*/) { static const QString qddserver = QLatin1String("QDeclarativeDebugServer: "); - static const QString cannotRetrieveDebuggingOutput = Utils::AbstractProcess::msgWinCannotRetrieveDebuggingOutput(); + static const QString cannotRetrieveDebuggingOutput = ApplicationLauncher::msgWinCannotRetrieveDebuggingOutput(); const int index = msg.indexOf(qddserver); if (index != -1) { diff --git a/src/plugins/projectexplorer/applicationlauncher_x11.cpp b/src/plugins/projectexplorer/applicationlauncher.cpp index 09b2824924..43f823ab84 100644 --- a/src/plugins/projectexplorer/applicationlauncher_x11.cpp +++ b/src/plugins/projectexplorer/applicationlauncher.cpp @@ -32,14 +32,24 @@ #include "applicationlauncher.h" #include "consoleprocess.h" +#ifdef Q_OS_WIN +#include "windebuginterface.h" +#endif #include <coreplugin/icore.h> #include <utils/qtcprocess.h> +#ifdef Q_OS_WIN +#include <utils/winutils.h> +#endif #include <QtCore/QTimer> #include <QtCore/QTextCodec> +#ifdef Q_OS_WIN +#include <windows.h> +#endif + /*! \class ProjectExplorer::ApplicationLauncher @@ -53,6 +63,10 @@ namespace ProjectExplorer { +#ifdef Q_OS_WIN +using namespace Internal; // for WinDebugInterface +#endif + struct ApplicationLauncherPrivate { ApplicationLauncherPrivate(); @@ -86,11 +100,18 @@ ApplicationLauncher::ApplicationLauncher(QObject *parent) connect(&d->m_guiProcess, SIGNAL(started()), this, SLOT(bringToForeground())); +#ifdef Q_OS_UNIX d->m_consoleProcess.setSettings(Core::ICore::instance()->settings()); +#endif connect(&d->m_consoleProcess, SIGNAL(processMessage(QString,bool)), this, SLOT(appendProcessMessage(QString,bool))); connect(&d->m_consoleProcess, SIGNAL(processStopped()), this, SLOT(processStopped())); + +#ifdef Q_OS_WIN + connect(WinDebugInterface::instance(), SIGNAL(debugOutput(qint64,QString)), + this, SLOT(checkDebugOutput(qint64,QString))); +#endif } ApplicationLauncher::~ApplicationLauncher() @@ -104,8 +125,19 @@ void ApplicationLauncher::appendProcessMessage(const QString &output, bool onStd void ApplicationLauncher::setWorkingDirectory(const QString &dir) { - d->m_guiProcess.setWorkingDirectory(dir); - d->m_consoleProcess.setWorkingDirectory(dir); +#ifdef Q_OS_WIN + // Work around QTBUG-17529 (QtDeclarative fails with 'File name case mismatch' ...) + const QString fixedPath = Utils::normalizePathName(dir); +#else +# define fixedPath dir +#endif + + d->m_guiProcess.setWorkingDirectory(fixedPath); + d->m_consoleProcess.setWorkingDirectory(fixedPath); + +#ifndef Q_OS_WIN +# undef fixedPath +#endif } void ApplicationLauncher::setEnvironment(const Utils::Environment &env) @@ -116,6 +148,13 @@ void ApplicationLauncher::setEnvironment(const Utils::Environment &env) void ApplicationLauncher::start(Mode mode, const QString &program, const QString &args) { +#ifdef Q_OS_WIN + if (!WinDebugInterface::instance()->isRunning()) + WinDebugInterface::instance()->start(); // Try to start listener again... + if (!WinDebugInterface::instance()->isRunning()) + emit appendMessage(msgWinCannotRetrieveDebuggingOutput(), Utils::ErrorMessageFormat); +#endif + d->m_currentMode = mode; if (mode == Gui) { d->m_guiProcess.setCommand(program, args); @@ -158,7 +197,11 @@ qint64 ApplicationLauncher::applicationPID() const if (d->m_currentMode == Console) { result = d->m_consoleProcess.applicationPID(); } else { +#ifdef Q_OS_WIN + result = (qint64)d->m_guiProcess.pid()->dwProcessId; +#else result = (qint64)d->m_guiProcess.pid(); +#endif } return result; } @@ -196,6 +239,14 @@ void ApplicationLauncher::readStandardError() emit appendMessage(msg, Utils::StdErrFormatSameLine); } +#ifdef Q_OS_WIN +void ApplicationLauncher::checkDebugOutput(qint64 pid, const QString &message) +{ + if (applicationPID() == pid) + emit appendMessage(message, Utils::DebugFormat); +} +#endif + void ApplicationLauncher::processStopped() { emit processExited(0); @@ -211,4 +262,9 @@ void ApplicationLauncher::bringToForeground() emit bringToForegroundRequested(applicationPID()); } +QString ApplicationLauncher::msgWinCannotRetrieveDebuggingOutput() +{ + return tr("Cannot retrieve debugging output.\n"); +} + } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/applicationlauncher.h b/src/plugins/projectexplorer/applicationlauncher.h index 5113cf2608..45a7c85ce1 100644 --- a/src/plugins/projectexplorer/applicationlauncher.h +++ b/src/plugins/projectexplorer/applicationlauncher.h @@ -69,6 +69,8 @@ public: bool isRunning() const; qint64 applicationPID() const; + static QString msgWinCannotRetrieveDebuggingOutput(); + signals: void appendMessage(const QString &message, Utils::OutputFormat format); void processExited(int exitCode); @@ -77,16 +79,13 @@ signals: private slots: void processStopped(); void appendProcessMessage(const QString &output, bool onStdErr); -#ifdef Q_OS_WIN - void readWinDebugOutput(const QString &output); - void processFinished(int exitCode); -#else void guiProcessError(); void readStandardOutput(); void readStandardError(); - void processDone(int, QProcess::ExitStatus); +#ifdef Q_OS_WIN + void checkDebugOutput(qint64 pid, const QString &message); #endif - + void processDone(int, QProcess::ExitStatus); void bringToForeground(); private: diff --git a/src/plugins/projectexplorer/applicationlauncher_win.cpp b/src/plugins/projectexplorer/applicationlauncher_win.cpp deleted file mode 100644 index b28cf138cb..0000000000 --- a/src/plugins/projectexplorer/applicationlauncher_win.cpp +++ /dev/null @@ -1,154 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (info@qt.nokia.com) -** -** -** GNU Lesser General Public License Usage -** -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this file. -** Please review the following information to ensure the GNU Lesser General -** Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** Other Usage -** -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** If you have questions regarding the use of this file, please contact -** Nokia at info@qt.nokia.com. -** -**************************************************************************/ - -#include "applicationlauncher.h" -#include "consoleprocess.h" -#include "winguiprocess.h" - -#include <utils/winutils.h> - -#include <QtCore/QDebug> - -namespace ProjectExplorer { - -struct ApplicationLauncherPrivate { - ApplicationLauncherPrivate() : m_currentMode(ApplicationLauncher::Gui) {} - - Utils::ConsoleProcess m_consoleProcess; - ApplicationLauncher::Mode m_currentMode; - Internal::WinGuiProcess m_winGuiProcess; -}; - -ApplicationLauncher::ApplicationLauncher(QObject *parent) - : QObject(parent), d(new ApplicationLauncherPrivate) -{ - connect(&d->m_consoleProcess, SIGNAL(processMessage(QString,bool)), - this, SLOT(appendProcessMessage(QString,bool))); - connect(&d->m_consoleProcess, SIGNAL(processStopped()), - this, SLOT(processStopped())); - - connect(&d->m_winGuiProcess, SIGNAL(processMessage(QString, bool)), - this, SLOT(appendProcessMessage(QString,bool))); - connect(&d->m_winGuiProcess, SIGNAL(receivedDebugOutput(QString)), - this, SLOT(readWinDebugOutput(QString))); - connect(&d->m_winGuiProcess, SIGNAL(processFinished(int)), - this, SLOT(processFinished(int))); -} - -ApplicationLauncher::~ApplicationLauncher() -{ -} - -void ApplicationLauncher::setWorkingDirectory(const QString &dir) -{ - // Work around QTBUG-17529 (QtDeclarative fails with 'File name case mismatch' ...) - const QString fixedPath = Utils::normalizePathName(dir); - - d->m_winGuiProcess.setWorkingDirectory(fixedPath); - d->m_consoleProcess.setWorkingDirectory(fixedPath); -} - -void ApplicationLauncher::setEnvironment(const Utils::Environment &env) -{ - d->m_winGuiProcess.setEnvironment(env); - d->m_consoleProcess.setEnvironment(env); -} - -void ApplicationLauncher::start(Mode mode, const QString &program, const QString &args) -{ - d->m_currentMode = mode; - if (mode == Gui) { - d->m_winGuiProcess.start(program, args); - } else { - d->m_consoleProcess.start(program, args); - } -} - -void ApplicationLauncher::stop() -{ - if (!isRunning()) - return; - if (d->m_currentMode == Gui) { - d->m_winGuiProcess.stop(); - } else { - d->m_consoleProcess.stop(); - processStopped(); - } -} - -bool ApplicationLauncher::isRunning() const -{ - if (d->m_currentMode == Gui) - return d->m_winGuiProcess.isRunning(); - else - return d->m_consoleProcess.isRunning(); -} - -qint64 ApplicationLauncher::applicationPID() const -{ - qint64 result = 0; - if (!isRunning()) - return result; - - if (d->m_currentMode == Console) { - result = d->m_consoleProcess.applicationPID(); - } else { - result = d->m_winGuiProcess.applicationPID(); - } - return result; -} - -void ApplicationLauncher::appendProcessMessage(const QString &output, bool onStdErr) -{ - emit appendMessage(output, onStdErr ? Utils::ErrorMessageFormat : Utils::NormalMessageFormat); -} - -void ApplicationLauncher::readWinDebugOutput(const QString &output) -{ - emit appendMessage(output, Utils::DebugFormat); -} - -void ApplicationLauncher::processStopped() -{ - emit processExited(0); -} - -void ApplicationLauncher::processFinished(int exitCode) -{ - emit processExited(exitCode); -} - -void ApplicationLauncher::bringToForeground() -{ -} - -} // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/projectexplorer.pro b/src/plugins/projectexplorer/projectexplorer.pro index f21c0c9bd1..430a2aac35 100644 --- a/src/plugins/projectexplorer/projectexplorer.pro +++ b/src/plugins/projectexplorer/projectexplorer.pro @@ -139,6 +139,7 @@ SOURCES += projectexplorer.cpp \ editorconfiguration.cpp \ editorsettingspropertiespage.cpp \ runconfiguration.cpp \ + applicationlauncher.cpp \ applicationrunconfiguration.cpp \ runsettingspropertiespage.cpp \ projecttreewidget.cpp \ @@ -204,17 +205,15 @@ equals(TEST, 1) { } win32 { - SOURCES += applicationlauncher_win.cpp \ + SOURCES += \ windebuginterface.cpp \ - winguiprocess.cpp \ msvcparser.cpp \ msvctoolchain.cpp - HEADERS += winguiprocess.h \ + HEADERS += \ windebuginterface.h \ msvcparser.h \ msvctoolchain.h } else { - SOURCES += applicationlauncher_x11.cpp macx:LIBS += -framework Carbon } RESOURCES += projectexplorer.qrc diff --git a/src/plugins/projectexplorer/windebuginterface.cpp b/src/plugins/projectexplorer/windebuginterface.cpp index d90cef46b1..3d562eb82c 100644 --- a/src/plugins/projectexplorer/windebuginterface.cpp +++ b/src/plugins/projectexplorer/windebuginterface.cpp @@ -42,8 +42,6 @@ OutputDebugString puts its data into a shared memory segment named \c DBWIN_BUFFER which can be accessed via file mapping. - - \sa ProjectExplorer::Internal::WinGuiProcess */ namespace ProjectExplorer { diff --git a/src/plugins/projectexplorer/winguiprocess.cpp b/src/plugins/projectexplorer/winguiprocess.cpp deleted file mode 100644 index 0d83d10be9..0000000000 --- a/src/plugins/projectexplorer/winguiprocess.cpp +++ /dev/null @@ -1,173 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (info@qt.nokia.com) -** -** -** GNU Lesser General Public License Usage -** -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this file. -** Please review the following information to ensure the GNU Lesser General -** Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** Other Usage -** -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** If you have questions regarding the use of this file, please contact -** Nokia at info@qt.nokia.com. -** -**************************************************************************/ - -#include "winguiprocess.h" -#include "windebuginterface.h" -#include "consoleprocess.h" - -#include <utils/qtcprocess.h> -#include <utils/winutils.h> - -#include <QtCore/QDir> - -using namespace ProjectExplorer::Internal; - -/*! - \class ProjectExplorer::Internal::WinGuiProcess - \brief Captures the debug output of a Windows GUI application. - - The output of a Windows GUI application would otherwise not be - visible. Uses the debug interface and emits via a signal. - - \sa ProjectExplorer::Internal::WinDebugInterface -*/ - -WinGuiProcess::WinGuiProcess(QObject *parent) : - QThread(parent), - m_pid(0), - m_exitCode(0) -{ - connect(this, SIGNAL(processFinished(int)), this, SLOT(done())); -} - -WinGuiProcess::~WinGuiProcess() -{ - stop(); -} - -bool WinGuiProcess::isRunning() const -{ - return QThread::isRunning(); -} - -bool WinGuiProcess::start(const QString &program, const QString &args) -{ - if (isRunning()) - return false; - - connect(WinDebugInterface::instance(), SIGNAL(debugOutput(qint64,QString)), - this, SLOT(checkDebugOutput(qint64,QString))); - - m_program = program; - m_args = args; - - QThread::start(); - return true; -} - -void WinGuiProcess::stop() -{ - if (m_pid) - TerminateProcess(m_pid->hProcess, 1); - wait(); -} - -void WinGuiProcess::run() -{ - if (m_pid) - return; - - STARTUPINFO si; - ZeroMemory(&si, sizeof(si)); - si.cb = sizeof(si); - - m_pid = new PROCESS_INFORMATION; - ZeroMemory(m_pid, sizeof(PROCESS_INFORMATION)); - - m_exitCode = 0; - bool started = false; - - if (!WinDebugInterface::instance()->isRunning()) - WinDebugInterface::instance()->start(); // Try to start listener again... - - do { - QString pcmd, pargs; - QtcProcess::prepareCommand(m_program, m_args, &pcmd, &pargs, &m_environment, &m_workingDir); - const QString cmdLine = createWinCommandline(pcmd, pargs); - const QStringList env = m_environment.toStringList(); - started = CreateProcessW(0, (WCHAR*)cmdLine.utf16(), - 0, 0, TRUE, CREATE_UNICODE_ENVIRONMENT, - env.isEmpty() ? 0 - : createWinEnvironment(fixWinEnvironment(env)).data(), - workingDirectory().isEmpty() ? 0 - : (WCHAR*)QDir::convertSeparators(workingDirectory()).utf16(), - &si, m_pid); - - if (!started) { - emit processMessage(tr("The process could not be started: %1"). - arg(Utils::winErrorMessage(GetLastError())), true); - emit processFinished(0); - break; - } - - if (!WinDebugInterface::instance()->isRunning()) - emit processMessage(msgWinCannotRetrieveDebuggingOutput(), false); - - WaitForSingleObject(m_pid->hProcess, INFINITE); - } while (false); - - if (started) { - GetExitCodeProcess(m_pid->hProcess, &m_exitCode); - emit processFinished(static_cast<int>(m_exitCode)); - } - - if (m_pid->hProcess != NULL) - CloseHandle(m_pid->hProcess); - if (m_pid->hThread != NULL) - CloseHandle(m_pid->hThread); - delete m_pid; - m_pid = 0; -} - -void WinGuiProcess::checkDebugOutput(qint64 pid, const QString &message) -{ - if (applicationPID() == pid) - emit receivedDebugOutput(message); -} - -void WinGuiProcess::done() -{ - disconnect(WinDebugInterface::instance(), SIGNAL(debugOutput(qint64,QString)), - this, SLOT(checkDebugOutput(qint64,QString))); -} - -qint64 WinGuiProcess::applicationPID() const -{ - if (m_pid) - return m_pid->dwProcessId; - return 0; -} - -int WinGuiProcess::exitCode() const -{ - return static_cast<int>(m_exitCode); -} diff --git a/src/plugins/projectexplorer/winguiprocess.h b/src/plugins/projectexplorer/winguiprocess.h deleted file mode 100644 index 95b4c0d17d..0000000000 --- a/src/plugins/projectexplorer/winguiprocess.h +++ /dev/null @@ -1,85 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (info@qt.nokia.com) -** -** -** GNU Lesser General Public License Usage -** -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this file. -** Please review the following information to ensure the GNU Lesser General -** Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** Other Usage -** -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** If you have questions regarding the use of this file, please contact -** Nokia at info@qt.nokia.com. -** -**************************************************************************/ - -#ifndef WINGUIPROCESS_H -#define WINGUIPROCESS_H - -#include "abstractprocess.h" - -#include <QtCore/QThread> -#include <QtCore/QStringList> - -#include <windows.h> - -using namespace Utils; - -namespace ProjectExplorer { -namespace Internal { - -// Documentation inside. -class WinGuiProcess : public QThread, public AbstractProcess -{ - Q_OBJECT - -public: - explicit WinGuiProcess(QObject *parent = 0); - virtual ~WinGuiProcess(); - - bool isRunning() const; - bool start(const QString &program, const QString &args); - void stop(); - - qint64 applicationPID() const; - int exitCode() const; - -signals: - void processMessage(const QString &error, bool isError); - void receivedDebugOutput(const QString &output); - void processFinished(int exitCode); - -private slots: - void checkDebugOutput(qint64, const QString &); - void done(); - -private: - void run(); - - PROCESS_INFORMATION *m_pid; - QString m_program; - QString m_args; - unsigned long m_exitCode; -}; - -} // namespace Internal -} // namespace ProjectExplorer - -#endif // WINGUIPROCESS_H |