Frage

I want to start cmd.exe from a Qt app with a specific PATH set. I insert "Path" in QProcessEnvironment and set that environment to QProcess. Then I startDetached "cmd". On the command prompt, the path is the same as the from the calling app, not what I just set. Did I miss something? I use Qt 5.2.0 with mingw and Qt-creator 3.0.0 on windows 8.1.s

QProcess process(this);
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
env.insert("Path", "MyPath");
process.setProcessEnvironment(env);
QStringList args;
args << "/D" << "/K" << "dir";
process.startDetached("cmd", args);
War es hilfreich?

Lösung

The startDetached method is a static method. So all the state that you applied to the process object is just ignored, because the method cannot see it. If you start the process with start() instead, the new process will pick up your environment.

process.start("cmd", args);

Of course, you want to the new process to be detached so that the parent can terminate without forcing the new process also to terminate. From what I can tell, the QProcess class does not offer you a way to achieve that easily. You could modify the environment of the parent process so that the new process inherits those modifications, but that does not sound at all desirable.

This question presents a possible workaround: Detaching a started process.

Andere Tipps

As David answered startDetached doesn't use the environment. So I went and take the original code and adjusted it a bit so it works (for me at least).

WProcess.h:

#ifndef WPROCESS_H
#define WPROCESS_H

#include <QProcessEnvironment>

class WProcess
{
public:
  WProcess();

  void setProcessEnvironment(const QProcessEnvironment &value) {environment = value;}
  bool startDetached(const QString &program, const QStringList &arguments, const QString &workingDir);

private:
  QProcessEnvironment environment;
};

#endif // WPROCESS_H

WProcess.cpp:

#include "WProcess.h"

#include <Windows.h>
#include <WinBase.h>

static QString w_create_commandline(const QString &program, const QStringList &arguments)
{
    QString args;
    if (!program.isEmpty()) {
        QString programName = program;
        if (!programName.startsWith(QLatin1Char('\"')) && !programName.endsWith(QLatin1Char('\"')) && programName.contains(QLatin1Char(' ')))
            programName = QLatin1Char('\"') + programName + QLatin1Char('\"');
        programName.replace(QLatin1Char('/'), QLatin1Char('\\'));

        // add the prgram as the first arg ... it works better
        args = programName + QLatin1Char(' ');
    }

    for (int i=0; i<arguments.size(); ++i) {
        QString tmp = arguments.at(i);
        // Quotes are escaped and their preceding backslashes are doubled.
        tmp.replace(QRegExp(QLatin1String("(\\\\*)\"")), QLatin1String("\\1\\1\\\""));
        if (tmp.isEmpty() || tmp.contains(QLatin1Char(' ')) || tmp.contains(QLatin1Char('\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\"
            int i = tmp.length();
            while (i > 0 && tmp.at(i - 1) == QLatin1Char('\\'))
                --i;
            tmp.insert(i, QLatin1Char('"'));
            tmp.prepend(QLatin1Char('"'));
        }
        args += QLatin1Char(' ') + tmp;
    }
    return args;
}


static QByteArray w_create_environment(const QProcessEnvironment &environment)
{
  QByteArray envlist;
  if (!environment.isEmpty())
  {
    static const wchar_t equal = L'=';
    static const wchar_t nul = L'\0';

    int pos = 0;
    QStringList keys = environment.keys();
    foreach(QString key, keys)
    {
      QString value = environment.value(key);

      uint tmpSize = sizeof(wchar_t) * (key.length() + value.length() + 2);
      // ignore empty strings
      if (tmpSize != sizeof(wchar_t) * 2)
      {
        envlist.resize(envlist.size() + tmpSize);

        tmpSize = key.length() * sizeof(wchar_t);
        memcpy(envlist.data() + pos, key.utf16(), tmpSize);
        pos += tmpSize;

        memcpy(envlist.data() + pos, &equal, sizeof(wchar_t));
        pos += sizeof(wchar_t);

        tmpSize = value.length() * sizeof(wchar_t);
        memcpy(envlist.data() + pos, value.utf16(), tmpSize);
        pos += tmpSize;

        memcpy(envlist.data() + pos, &nul, sizeof(wchar_t));
        pos += sizeof(wchar_t);
      }
    }

    // add the 2 terminating 0 (actually 4, just to be on the safe side)
    envlist.resize( envlist.size()+4 );
    envlist[pos++] = 0;
    envlist[pos++] = 0;
    envlist[pos++] = 0;
    envlist[pos++] = 0;
  }
  return envlist;
}


WProcess::WProcess()
{
}


bool WProcess::startDetached(const QString &program, const QStringList &arguments, const QString &workingDir)
{
  QByteArray envlist;
  if (!environment.isEmpty())
  {
    envlist = w_create_environment(environment);
  }

  QString args = w_create_commandline(program, arguments);
  bool success = false;
  PROCESS_INFORMATION pinfo;

  STARTUPINFOW startupInfo = { sizeof( STARTUPINFO ), 0, 0, 0,
                               (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
                               (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
                               0, 0, 0, 0, 0, 0, 0, 0, 0, 0
                             };
  success = CreateProcess(0, (wchar_t*)args.utf16(),
                          0, 0, FALSE, CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_CONSOLE, 
                          envlist.isEmpty() ? 0 : envlist.data(),
                          workingDir.isEmpty() ? 0 : (wchar_t*)workingDir.utf16(),
                          &startupInfo, &pinfo);

  if (success) 
  {
    CloseHandle(pinfo.hThread);
    CloseHandle(pinfo.hProcess);
    //if (pid) *pid = pinfo.dwProcessId;
  }

  return success;
}

Usage, open command prompt in C:\Qt\Qt-creator and set path to "mypath".

WProcess process;
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
env.insert("Path", "mypath");
process.setProcessEnvironment(env);    
process.startDetached("cmd", QStringList(), "C:\\Qt\\Qt-creator");
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top