QProcess::startDetached: support custom process environment
Starting a detached process with a custom process environment can now be achieved by: QProcess p; p.setProgram("foo"); p.setProcessEnvironment(myEnv); p.startDetached(); [ChangeLog][QtCore][QProcess] Added the ability to set a custom process environment for detached processes. Task-number: QTBUG-2284 Change-Id: I49406dffb64fa2aed41ea05cb271bd42eeabb729 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
28666d167a
commit
6ba8708a2f
@ -937,6 +937,14 @@ bool QProcessPrivate::startDetached(qint64 *pid)
|
|||||||
argv[i + 1] = ::strdup(QFile::encodeName(arguments.at(i)).constData());
|
argv[i + 1] = ::strdup(QFile::encodeName(arguments.at(i)).constData());
|
||||||
argv[arguments.size() + 1] = 0;
|
argv[arguments.size() + 1] = 0;
|
||||||
|
|
||||||
|
// Duplicate the environment.
|
||||||
|
int envc = 0;
|
||||||
|
char **envp = nullptr;
|
||||||
|
if (environment.d.constData()) {
|
||||||
|
QProcessEnvironmentPrivate::MutexLocker locker(environment.d);
|
||||||
|
envp = _q_dupEnvironment(environment.d.constData()->hash, &envc);
|
||||||
|
}
|
||||||
|
|
||||||
QByteArray tmp;
|
QByteArray tmp;
|
||||||
if (!program.contains(QLatin1Char('/'))) {
|
if (!program.contains(QLatin1Char('/'))) {
|
||||||
const QString &exeFilePath = QStandardPaths::findExecutable(program);
|
const QString &exeFilePath = QStandardPaths::findExecutable(program);
|
||||||
@ -946,7 +954,11 @@ bool QProcessPrivate::startDetached(qint64 *pid)
|
|||||||
if (tmp.isEmpty())
|
if (tmp.isEmpty())
|
||||||
tmp = QFile::encodeName(program);
|
tmp = QFile::encodeName(program);
|
||||||
argv[0] = tmp.data();
|
argv[0] = tmp.data();
|
||||||
qt_safe_execv(argv[0], argv);
|
|
||||||
|
if (envp)
|
||||||
|
qt_safe_execve(argv[0], argv, envp);
|
||||||
|
else
|
||||||
|
qt_safe_execv(argv[0], argv);
|
||||||
|
|
||||||
struct sigaction noaction;
|
struct sigaction noaction;
|
||||||
memset(&noaction, 0, sizeof(noaction));
|
memset(&noaction, 0, sizeof(noaction));
|
||||||
|
@ -867,6 +867,13 @@ bool QProcessPrivate::startDetached(qint64 *pid)
|
|||||||
bool success = false;
|
bool success = false;
|
||||||
PROCESS_INFORMATION pinfo;
|
PROCESS_INFORMATION pinfo;
|
||||||
|
|
||||||
|
void *envPtr = nullptr;
|
||||||
|
QByteArray envlist;
|
||||||
|
if (environment.d.constData()) {
|
||||||
|
envlist = qt_create_environment(environment.d.constData()->hash);
|
||||||
|
envPtr = envlist.data();
|
||||||
|
}
|
||||||
|
|
||||||
DWORD dwCreationFlags = (GetConsoleWindow() ? 0 : CREATE_NO_WINDOW);
|
DWORD dwCreationFlags = (GetConsoleWindow() ? 0 : CREATE_NO_WINDOW);
|
||||||
dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
|
dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
|
||||||
STARTUPINFOW startupInfo = { sizeof( STARTUPINFO ), 0, 0, 0,
|
STARTUPINFOW startupInfo = { sizeof( STARTUPINFO ), 0, 0, 0,
|
||||||
@ -875,7 +882,7 @@ bool QProcessPrivate::startDetached(qint64 *pid)
|
|||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||||
};
|
};
|
||||||
success = CreateProcess(0, (wchar_t*)args.utf16(),
|
success = CreateProcess(0, (wchar_t*)args.utf16(),
|
||||||
0, 0, FALSE, dwCreationFlags, 0,
|
0, 0, FALSE, dwCreationFlags, envPtr,
|
||||||
workingDirectory.isEmpty() ? 0 : (wchar_t*)workingDirectory.utf16(),
|
workingDirectory.isEmpty() ? 0 : (wchar_t*)workingDirectory.utf16(),
|
||||||
&startupInfo, &pinfo);
|
&startupInfo, &pinfo);
|
||||||
|
|
||||||
@ -885,6 +892,8 @@ bool QProcessPrivate::startDetached(qint64 *pid)
|
|||||||
if (pid)
|
if (pid)
|
||||||
*pid = pinfo.dwProcessId;
|
*pid = pinfo.dwProcessId;
|
||||||
} else if (GetLastError() == errorElevationRequired) {
|
} else if (GetLastError() == errorElevationRequired) {
|
||||||
|
if (envPtr)
|
||||||
|
qWarning("QProcess: custom environment will be ignored for detached elevated process.");
|
||||||
success = startDetachedUacPrompt(program, arguments, workingDirectory, pid);
|
success = startDetachedUacPrompt(program, arguments, workingDirectory, pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,6 +65,8 @@ int main(int argc, char **argv)
|
|||||||
f.write(QByteArray::number(quint64(GetCurrentProcessId())));
|
f.write(QByteArray::number(quint64(GetCurrentProcessId())));
|
||||||
#endif
|
#endif
|
||||||
f.putChar('\n');
|
f.putChar('\n');
|
||||||
|
f.write(qgetenv("tst_QProcess"));
|
||||||
|
f.putChar('\n');
|
||||||
|
|
||||||
f.close();
|
f.close();
|
||||||
|
|
||||||
|
@ -126,7 +126,7 @@ private slots:
|
|||||||
void systemEnvironment();
|
void systemEnvironment();
|
||||||
void lockupsInStartDetached();
|
void lockupsInStartDetached();
|
||||||
void waitForReadyReadForNonexistantProcess();
|
void waitForReadyReadForNonexistantProcess();
|
||||||
void detachedWorkingDirectoryAndPid();
|
void detachedProcessParameters();
|
||||||
void startFinishStartFinish();
|
void startFinishStartFinish();
|
||||||
void invalidProgramString_data();
|
void invalidProgramString_data();
|
||||||
void invalidProgramString();
|
void invalidProgramString();
|
||||||
@ -2030,7 +2030,7 @@ void tst_QProcess::fileWriterProcess()
|
|||||||
} while (stopWatch.elapsed() < 3000);
|
} while (stopWatch.elapsed() < 3000);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_QProcess::detachedWorkingDirectoryAndPid()
|
void tst_QProcess::detachedProcessParameters()
|
||||||
{
|
{
|
||||||
qint64 pid;
|
qint64 pid;
|
||||||
|
|
||||||
@ -2042,9 +2042,17 @@ void tst_QProcess::detachedWorkingDirectoryAndPid()
|
|||||||
|
|
||||||
QVERIFY(QFile::exists(workingDir));
|
QVERIFY(QFile::exists(workingDir));
|
||||||
|
|
||||||
QStringList args;
|
QVERIFY(qgetenv("tst_QProcess").isEmpty());
|
||||||
args << infoFile.fileName();
|
QByteArray envVarValue("foobarbaz");
|
||||||
QVERIFY(QProcess::startDetached(QDir::currentPath() + QLatin1String("/testDetached/testDetached"), args, workingDir, &pid));
|
QProcessEnvironment environment = QProcessEnvironment::systemEnvironment();
|
||||||
|
environment.insert(QStringLiteral("tst_QProcess"), QString::fromUtf8(envVarValue));
|
||||||
|
|
||||||
|
QProcess process;
|
||||||
|
process.setProgram(QDir::currentPath() + QLatin1String("/testDetached/testDetached"));
|
||||||
|
process.setArguments(QStringList(infoFile.fileName()));
|
||||||
|
process.setWorkingDirectory(workingDir);
|
||||||
|
process.setProcessEnvironment(environment);
|
||||||
|
QVERIFY(process.startDetached(&pid));
|
||||||
|
|
||||||
QFileInfo fi(infoFile);
|
QFileInfo fi(infoFile);
|
||||||
fi.setCaching(false);
|
fi.setCaching(false);
|
||||||
@ -2055,10 +2063,9 @@ void tst_QProcess::detachedWorkingDirectoryAndPid()
|
|||||||
}
|
}
|
||||||
|
|
||||||
QVERIFY(infoFile.open(QIODevice::ReadOnly | QIODevice::Text));
|
QVERIFY(infoFile.open(QIODevice::ReadOnly | QIODevice::Text));
|
||||||
QString actualWorkingDir = QString::fromUtf8(infoFile.readLine());
|
QString actualWorkingDir = QString::fromUtf8(infoFile.readLine()).trimmed();
|
||||||
actualWorkingDir.chop(1); // strip off newline
|
QByteArray processIdString = infoFile.readLine().trimmed();
|
||||||
QByteArray processIdString = infoFile.readLine();
|
QByteArray actualEnvVarValue = infoFile.readLine().trimmed();
|
||||||
processIdString.chop(1);
|
|
||||||
infoFile.close();
|
infoFile.close();
|
||||||
infoFile.remove();
|
infoFile.remove();
|
||||||
|
|
||||||
@ -2068,6 +2075,7 @@ void tst_QProcess::detachedWorkingDirectoryAndPid()
|
|||||||
|
|
||||||
QCOMPARE(actualWorkingDir, workingDir);
|
QCOMPARE(actualWorkingDir, workingDir);
|
||||||
QCOMPARE(actualPid, pid);
|
QCOMPARE(actualPid, pid);
|
||||||
|
QCOMPARE(actualEnvVarValue, envVarValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_QProcess::switchReadChannels()
|
void tst_QProcess::switchReadChannels()
|
||||||
|
Loading…
Reference in New Issue
Block a user