使用QProcessEnvironment更改cmd.exe的PATH环境变量

时间:2014-01-17 11:36:03

标签: c++ windows qt cmd qprocess

我想从具有特定PATH设置的Qt应用启动cmd.exe。我在QProcessEnvironment中插入“Path”并将该环境设置为QProcess。然后我startDetached“cmd”。在命令提示符下,路径与调用应用程序的路径相同,而不是我刚刚设置的路径。我错过了什么?我在Windows 8.1.s上使用Qt 5.2.0和mingw以及Qt-creator 3.0.0

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

2 个答案:

答案 0 :(得分:3)

startDetached方法是一种静态方法。因此,您应用于process对象的所有状态都被忽略,因为该方法无法看到它。如果您使用start()启动流程,新流程将会启动您的环境。

process.start("cmd", args);

当然,您希望将新进程分离,以便父进程可以在不强制新进程终止的情况下终止。据我所知,QProcess课程并没有为你提供一种轻松实现这一目标的方法。您可以修改父进程的环境,以便新进程继承这些修改,但这听起来根本不可取。

此问题提供了一种可能的解决方法:Detaching a started process

答案 1 :(得分:1)

大卫回答startDetached不使用环境。所以我去拿原始代码调整了一下,以便它起作用(至少对我而言)。

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;
}

用法,在C:\ Qt \ Qt-creator中打开命令提示符,并将路径设置为“mypath”。

WProcess process;
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
env.insert("Path", "mypath");
process.setProcessEnvironment(env);    
process.startDetached("cmd", QStringList(), "C:\\Qt\\Qt-creator");