Commit 3c689f78 authored by Friedemann Kleint's avatar Friedemann Kleint Committed by unknown
Browse files

Fixes: Move Windows helpers for AbstractProcess in place for use with Windows Debugger.

parent ca7cc122
......@@ -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;
......
/**************************************************************************
**
** 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
......@@ -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
......
......@@ -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;
}
......@@ -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 {
......
......@@ -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;
......
......@@ -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);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment