简体   繁体   English

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

[英]Change PATH environment variable for cmd.exe with QProcessEnvironment

I want to start cmd.exe from a Qt app with a specific PATH set. 我想从具有特定PATH设置的Qt应用程序启动cmd.exe。 I insert "Path" in QProcessEnvironment and set that environment to QProcess. 我在QProcessEnvironment中插入“路径”,并将该环境设置为QProcess。 Then I startDetached "cmd". 然后,我开始分离“ 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 我在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);

The startDetached method is a static method. startDetached方法是静态方法。 So all the state that you applied to the process object is just ignored, because the method cannot see it. 因此,将忽略您应用于process对象的所有状态,因为该方法无法看到它。 If you start the process with start() instead, the new process will pick up your environment. 如果改为使用start()启动该过程,则新过程将启动您的环境。

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. 据我所知, QProcess类无法为您提供轻松实现这一目标的方法。 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 . 这个问题提出了一个可能的解决方法: 分离已启动的进程

As David answered startDetached doesn't use the environment. 正如David回答的startDetached不使用环境。 So I went and take the original code and adjusted it a bit so it works (for me at least). 因此,我去了原始代码并对其进行了一些调整,以使其起作用(至少对我而言)。

WProcess.h: 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: 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". 用法,在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");

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM