From 3c689f78808dc71373336dc71b45ed71c4bf7e25 Mon Sep 17 00:00:00 2001
From: Friedemann Kleint <qtc-committer@nokia.com>
Date: Tue, 3 Mar 2009 17:11:27 +0100
Subject: [PATCH] Fixes: Move Windows helpers for AbstractProcess in place for
 use with Windows Debugger.

---
 src/libs/utils/abstractprocess.h              |  10 ++
 src/libs/utils/abstractprocess_win.cpp        | 117 ++++++++++++++++++
 src/libs/utils/consoleprocess.h               |   6 -
 src/libs/utils/consoleprocess_win.cpp         |  57 +--------
 src/libs/utils/utils.pro                      |   3 +-
 src/plugins/debugger/cdb/cdbdebugengine.cpp   |  16 ++-
 src/plugins/projectexplorer/winguiprocess.cpp |  20 +--
 7 files changed, 146 insertions(+), 83 deletions(-)
 create mode 100644 src/libs/utils/abstractprocess_win.cpp

diff --git a/src/libs/utils/abstractprocess.h b/src/libs/utils/abstractprocess.h
index 72049c36c02..d3671f55a40 100644
--- a/src/libs/utils/abstractprocess.h
+++ b/src/libs/utils/abstractprocess.h
@@ -59,6 +59,16 @@ public:
 //signals:
     virtual void processError(const QString &error) = 0;
 
+#ifdef Q_WS_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);
+    // 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
+
 private:
     QString m_workingDir;
     QStringList m_environment;
diff --git a/src/libs/utils/abstractprocess_win.cpp b/src/libs/utils/abstractprocess_win.cpp
new file mode 100644
index 00000000000..1bb820c93fd
--- /dev/null
+++ b/src/libs/utils/abstractprocess_win.cpp
@@ -0,0 +1,117 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact:  Qt Software Information (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+**
+**************************************************************************/
+
+#include "abstractprocess.h"
+
+#include <windows.h>
+
+namespace Core {
+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;
+}
+
+QString AbstractProcess::createWinCommandline(const QString &program, const QStringList &args)
+{
+    const QChar doubleQuote = QLatin1Char('"');
+    const QChar blank = QLatin1Char(' ');
+    const QChar backSlash = QLatin1Char('\\');
+
+    QString programName = program;
+    if (!programName.startsWith(doubleQuote) && !programName.endsWith(doubleQuote) && programName.contains(blank)) {
+        programName.insert(0, doubleQuote);
+        programName.append(doubleQuote);
+    }
+    // add the prgram as the first arrg ... it works better
+    programName.replace(QLatin1Char('/'), backSlash);
+    QString cmdLine = programName;
+    if (args.empty())
+        return cmdLine;
+
+    cmdLine += blank;
+    for (int i = 0; i < args.size(); ++i) {
+        QString tmp = args.at(i);
+        // in the case of \" already being in the string the \ must also be escaped
+        tmp.replace(QLatin1String("\\\""), QLatin1String("\\\\\""));
+        // escape a single " because the arguments will be parsed
+        tmp.replace(QString(doubleQuote), QLatin1String("\\\""));
+        if (tmp.isEmpty() || tmp.contains(blank) || tmp.contains('\t')) {
+            // 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\"
+            QString endQuote(doubleQuote);
+            int i = tmp.length();
+            while (i > 0 && tmp.at(i - 1) == backSlash) {
+                --i;
+                endQuote += backSlash;
+            }
+            cmdLine += QLatin1String(" \"");
+            cmdLine += tmp.left(i);
+            cmdLine += endQuote;
+        } else {
+            cmdLine += blank;
+            cmdLine += tmp;
+        }
+    }
+    return cmdLine;
+}
+
+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
+} //namespace Core
diff --git a/src/libs/utils/consoleprocess.h b/src/libs/utils/consoleprocess.h
index ac8d4b3eb9d..370b256c166 100644
--- a/src/libs/utils/consoleprocess.h
+++ b/src/libs/utils/consoleprocess.h
@@ -67,12 +67,6 @@ public:
     int exitCode() const { return m_appCode; } // This will be the signal number if exitStatus == CrashExit
     QProcess::ExitStatus exitStatus() const { return m_appStatus; }
 
-#ifdef Q_OS_WIN
-    // These are public for WinGuiProcess. Should be in AbstractProcess, but it has no .cpp so far.
-    static QString createCommandline(const QString &program, const QStringList &args);
-    static QStringList fixEnvironment(const QStringList &env);
-#endif
-
 signals:
     void processError(const QString &error);
     // These reflect the state of the actual client process
diff --git a/src/libs/utils/consoleprocess_win.cpp b/src/libs/utils/consoleprocess_win.cpp
index aa9f0d24659..ce5d15029d8 100644
--- a/src/libs/utils/consoleprocess_win.cpp
+++ b/src/libs/utils/consoleprocess_win.cpp
@@ -85,7 +85,7 @@ bool ConsoleProcess::start(const QString &program, const QStringList &args)
         QTextStream out(m_tempFile);
         out.setCodec("UTF-16LE");
         out.setGenerateByteOrderMark(false);
-        foreach (const QString &var, fixEnvironment(environment()))
+        foreach (const QString &var, fixWinEnvironment(environment()))
             out << var << QChar(0);
         out << QChar(0);
     }
@@ -106,10 +106,10 @@ bool ConsoleProcess::start(const QString &program, const QStringList &args)
              << m_stubServer.fullServerName()
              << workDir
              << (m_tempFile ? m_tempFile->fileName() : 0)
-             << createCommandline(program, args)
+             << createWinCommandline(program, args)
              << tr("Press <RETURN> to close this window...");
 
-    QString cmdLine = createCommandline(
+    QString cmdLine = createWinCommandline(
             QCoreApplication::applicationDirPath() + "/qtcreator_process_stub.exe", stubArgs);
 
     bool success = CreateProcessW(0, (WCHAR*)cmdLine.utf16(),
@@ -262,54 +262,3 @@ void ConsoleProcess::stubExited()
     emit wrapperStopped();
 }
 
-QStringList ConsoleProcess::fixEnvironment(const QStringList &env)
-{
-    QStringList envStrings = env;
-    // add PATH if necessary (for DLL loading)
-    if (envStrings.filter(QRegExp("^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("^SystemRoot=",Qt::CaseInsensitive)).isEmpty()) {
-        QByteArray systemRoot = qgetenv("SystemRoot");
-        if (!systemRoot.isEmpty())
-            envStrings.prepend(QString(QLatin1String("SystemRoot=%1")).arg(QString::fromLocal8Bit(systemRoot)));
-    }
-    return envStrings;
-}
-
-QString ConsoleProcess::createCommandline(const QString &program, const QStringList &args)
-{
-    QString programName = program;
-    if (!programName.startsWith(QLatin1Char('\"')) && !programName.endsWith(QLatin1Char('\"')) && programName.contains(" "))
-        programName = "\"" + programName + "\"";
-    programName.replace("/", "\\");
-
-    QString cmdLine;
-    // add the prgram as the first arrg ... it works better
-    cmdLine = programName + " ";
-    for (int i = 0; i < args.size(); ++i) {
-        QString tmp = args.at(i);
-        // in the case of \" already being in the string the \ must also be escaped
-        tmp.replace( "\\\"", "\\\\\"" );
-        // escape a single " because the arguments will be parsed
-        tmp.replace( "\"", "\\\"" );
-        if (tmp.isEmpty() || tmp.contains(' ') || tmp.contains('\t')) {
-            // 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\"
-            QString endQuote("\"");
-            int i = tmp.length();
-            while (i > 0 && tmp.at(i - 1) == '\\') {
-                --i;
-                endQuote += "\\";
-            }
-            cmdLine += QString(" \"") + tmp.left(i) + endQuote;
-        } else {
-            cmdLine += ' ' + tmp;
-        }
-    }
-    return cmdLine;
-}
diff --git a/src/libs/utils/utils.pro b/src/libs/utils/utils.pro
index 5c33948ae12..7649ab87486 100644
--- a/src/libs/utils/utils.pro
+++ b/src/libs/utils/utils.pro
@@ -27,7 +27,8 @@ SOURCES += \
     synchronousprocess.cpp
 
 win32 {
-    SOURCES += consoleprocess_win.cpp \
+    SOURCES += abstractprocess_win.cpp \
+               consoleprocess_win.cpp \
                winutils.cpp
     HEADERS += winutils.h
 } else {
diff --git a/src/plugins/debugger/cdb/cdbdebugengine.cpp b/src/plugins/debugger/cdb/cdbdebugengine.cpp
index 4217378cf2e..d204e158c96 100644
--- a/src/plugins/debugger/cdb/cdbdebugengine.cpp
+++ b/src/plugins/debugger/cdb/cdbdebugengine.cpp
@@ -35,6 +35,7 @@
 #include "stackhandler.h"
 
 #include <utils/qtcassert.h>
+#include <utils/consoleprocess.h>
 
 #include <QtCore/QDebug>
 #include <QtCore/QTimerEvent>
@@ -202,12 +203,19 @@ bool CdbDebugEngine::startDebugger()
         qWarning("CdbDebugEngine: attach to process not yet implemented!");
         return false;
     } else {
+        QString cmd = Core::Utils::AbstractProcess::createWinCommandline(filename, m_d->m_debuggerManager->m_processArgs);
+        PCWSTR env = 0;
+        QByteArray envData;
+        if (!m_d->m_debuggerManager->m_environment.empty()) {
+            envData = Core::Utils::AbstractProcess::createWinEnvironment(Core::Utils::AbstractProcess::fixWinEnvironment(m_d->m_debuggerManager->m_environment));
+            env = reinterpret_cast<PCWSTR>(envData.data());
+        }
         HRESULT hr = m_d->m_pDebugClient->CreateProcess2Wide(NULL,
-                                                const_cast<PWSTR>(filename.utf16()),
+                                                const_cast<PWSTR>(cmd.utf16()),
                                                 &dbgopts,
                                                 sizeof(dbgopts),
-                                                NULL,  // TODO: think about the initial directory
-                                                NULL); // TODO: think about setting the environment
+                                                m_d->m_debuggerManager->m_workingDir.utf16(),
+                                                env);
         if (FAILED(hr)) {
             //qWarning("CreateProcess2Wide failed");
             m_d->m_debuggerManagerAccess->notifyInferiorExited();
@@ -503,7 +511,7 @@ void CdbDebugEngine::reloadRegisters()
 }
 
 void CdbDebugEngine::timerEvent(QTimerEvent* te)
-{    
+{
     if (te->timerId() != m_d->m_watchTimer)
         return;
 
diff --git a/src/plugins/projectexplorer/winguiprocess.cpp b/src/plugins/projectexplorer/winguiprocess.cpp
index 86b90509186..75efc7cb736 100644
--- a/src/plugins/projectexplorer/winguiprocess.cpp
+++ b/src/plugins/projectexplorer/winguiprocess.cpp
@@ -34,22 +34,6 @@
 
 using namespace ProjectExplorer::Internal;
 
-static QByteArray createEnvironment(const QStringList &env)
-{
-    QByteArray envlist;
-    int pos = 0;
-    foreach (const QString &tmp, env) {
-        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;
-}
-
 WinGuiProcess::WinGuiProcess(QObject *parent)
     : QThread(parent)
 {
@@ -125,11 +109,11 @@ void WinGuiProcess::run()
 
     bool dbgInterface = setupDebugInterface(bufferReadyEvent, dataReadyEvent, sharedFile, sharedMem);
 
-    QString cmdLine = ConsoleProcess::createCommandline(m_program, m_args);
+    QString cmdLine = createWinCommandline(m_program, m_args);
     bool success = CreateProcessW(0, (WCHAR*)cmdLine.utf16(),
                                   0, 0, TRUE, CREATE_UNICODE_ENVIRONMENT,
                                   environment().isEmpty() ? 0
-                                  : createEnvironment(ConsoleProcess::fixEnvironment(environment())).data(),
+                                  : createWinEnvironment(fixWinEnvironment(environment())).data(),
                                   workingDirectory().isEmpty() ? 0
                                   : (WCHAR*)QDir::convertSeparators(workingDirectory()).utf16(),
                                   &si, m_pid);
-- 
GitLab