summaryrefslogtreecommitdiffstats
path: root/src/corelib/io/qprocess_win.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/io/qprocess_win.cpp')
-rw-r--r--src/corelib/io/qprocess_win.cpp127
1 files changed, 88 insertions, 39 deletions
diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp
index 05c9d6594c..2bbc4eddd0 100644
--- a/src/corelib/io/qprocess_win.cpp
+++ b/src/corelib/io/qprocess_win.cpp
@@ -358,7 +358,8 @@ void QProcessPrivate::closeChannel(Channel *channel)
destroyPipe(channel->pipe);
}
-static QString qt_create_commandline(const QString &program, const QStringList &arguments)
+static QString qt_create_commandline(const QString &program, const QStringList &arguments,
+ const QString &nativeArguments)
{
QString args;
if (!program.isEmpty()) {
@@ -387,6 +388,13 @@ static QString qt_create_commandline(const QString &program, const QStringList &
}
args += QLatin1Char(' ') + tmp;
}
+
+ if (!nativeArguments.isEmpty()) {
+ if (!args.isEmpty())
+ args += QLatin1Char(' ');
+ args += nativeArguments;
+ }
+
return args;
}
@@ -450,6 +458,30 @@ static QByteArray qt_create_environment(const QProcessEnvironmentPrivate::Map &e
return envlist;
}
+bool QProcessPrivate::callCreateProcess(QProcess::CreateProcessArguments *cpargs)
+{
+ if (modifyCreateProcessArgs)
+ modifyCreateProcessArgs(cpargs);
+ bool success = CreateProcess(cpargs->applicationName, cpargs->arguments,
+ cpargs->processAttributes, cpargs->threadAttributes,
+ cpargs->inheritHandles, cpargs->flags, cpargs->environment,
+ cpargs->currentDirectory, cpargs->startupInfo,
+ cpargs->processInformation);
+ if (stdinChannel.pipe[0] != INVALID_Q_PIPE) {
+ CloseHandle(stdinChannel.pipe[0]);
+ stdinChannel.pipe[0] = INVALID_Q_PIPE;
+ }
+ if (stdoutChannel.pipe[1] != INVALID_Q_PIPE) {
+ CloseHandle(stdoutChannel.pipe[1]);
+ stdoutChannel.pipe[1] = INVALID_Q_PIPE;
+ }
+ if (stderrChannel.pipe[1] != INVALID_Q_PIPE) {
+ CloseHandle(stderrChannel.pipe[1]);
+ stderrChannel.pipe[1] = INVALID_Q_PIPE;
+ }
+ return success;
+}
+
void QProcessPrivate::startProcess()
{
Q_Q(QProcess);
@@ -472,15 +504,10 @@ void QProcessPrivate::startProcess()
!openChannel(stderrChannel))
return;
- QString args = qt_create_commandline(program, arguments);
+ const QString args = qt_create_commandline(program, arguments, nativeArguments);
QByteArray envlist;
if (environment.d.constData())
envlist = qt_create_environment(environment.d.constData()->vars);
- if (!nativeArguments.isEmpty()) {
- if (!args.isEmpty())
- args += QLatin1Char(' ');
- args += nativeArguments;
- }
#if defined QPROCESS_DEBUG
qDebug("Creating process");
@@ -507,18 +534,14 @@ void QProcessPrivate::startProcess()
const QString nativeWorkingDirectory = QDir::toNativeSeparators(workingDirectory);
QProcess::CreateProcessArguments cpargs = {
- 0, (wchar_t*)args.utf16(),
- 0, 0, TRUE, dwCreationFlags,
- environment.isEmpty() ? 0 : envlist.data(),
- nativeWorkingDirectory.isEmpty() ? Q_NULLPTR : (wchar_t*)nativeWorkingDirectory.utf16(),
+ nullptr, reinterpret_cast<wchar_t *>(const_cast<ushort *>(args.utf16())),
+ nullptr, nullptr, true, dwCreationFlags,
+ environment.isEmpty() ? nullptr : envlist.data(),
+ nativeWorkingDirectory.isEmpty()
+ ? nullptr : reinterpret_cast<const wchar_t *>(nativeWorkingDirectory.utf16()),
&startupInfo, pid
};
- if (modifyCreateProcessArgs)
- modifyCreateProcessArgs(&cpargs);
- success = CreateProcess(cpargs.applicationName, cpargs.arguments, cpargs.processAttributes,
- cpargs.threadAttributes, cpargs.inheritHandles, cpargs.flags,
- cpargs.environment, cpargs.currentDirectory, cpargs.startupInfo,
- cpargs.processInformation);
+ success = callCreateProcess(&cpargs);
QString errorString;
if (!success) {
@@ -526,19 +549,6 @@ void QProcessPrivate::startProcess()
errorString = QProcess::tr("Process failed to start: %1").arg(qt_error_string());
}
- if (stdinChannel.pipe[0] != INVALID_Q_PIPE) {
- CloseHandle(stdinChannel.pipe[0]);
- stdinChannel.pipe[0] = INVALID_Q_PIPE;
- }
- if (stdoutChannel.pipe[1] != INVALID_Q_PIPE) {
- CloseHandle(stdoutChannel.pipe[1]);
- stdoutChannel.pipe[1] = INVALID_Q_PIPE;
- }
- if (stderrChannel.pipe[1] != INVALID_Q_PIPE) {
- CloseHandle(stderrChannel.pipe[1]);
- stderrChannel.pipe[1] = INVALID_Q_PIPE;
- }
-
if (!success) {
cleanup();
setErrorAndEmit(QProcess::FailedToStart, errorString);
@@ -826,6 +836,7 @@ bool QProcessPrivate::writeToStdin()
// Use ShellExecuteEx() to trigger an UAC prompt when CreateProcess()fails
// with ERROR_ELEVATION_REQUIRED.
static bool startDetachedUacPrompt(const QString &programIn, const QStringList &arguments,
+ const QString &nativeArguments,
const QString &workingDir, qint64 *pid)
{
typedef BOOL (WINAPI *ShellExecuteExType)(SHELLEXECUTEINFOW *);
@@ -836,7 +847,8 @@ static bool startDetachedUacPrompt(const QString &programIn, const QStringList &
if (!shellExecuteEx)
return false;
- const QString args = qt_create_commandline(QString(), arguments); // needs arguments only
+ const QString args = qt_create_commandline(QString(), // needs arguments only
+ arguments, nativeArguments);
SHELLEXECUTEINFOW shellExecuteExInfo;
memset(&shellExecuteExInfo, 0, sizeof(SHELLEXECUTEINFOW));
shellExecuteExInfo.cbSize = sizeof(SHELLEXECUTEINFOW);
@@ -859,25 +871,52 @@ static bool startDetachedUacPrompt(const QString &programIn, const QStringList &
return true;
}
-bool QProcessPrivate::startDetached(const QString &program, const QStringList &arguments, const QString &workingDir, qint64 *pid)
+bool QProcessPrivate::startDetached(qint64 *pid)
{
static const DWORD errorElevationRequired = 740;
- QString args = qt_create_commandline(program, arguments);
+ if ((stdinChannel.type == Channel::Redirect && !openChannel(stdinChannel))
+ || (stdoutChannel.type == Channel::Redirect && !openChannel(stdoutChannel))
+ || (stderrChannel.type == Channel::Redirect && !openChannel(stderrChannel))) {
+ closeChannel(&stdinChannel);
+ closeChannel(&stdoutChannel);
+ closeChannel(&stderrChannel);
+ return false;
+ }
+
+ QString args = qt_create_commandline(program, arguments, nativeArguments);
bool success = false;
PROCESS_INFORMATION pinfo;
+ void *envPtr = nullptr;
+ QByteArray envlist;
+ if (environment.d.constData()) {
+ envlist = qt_create_environment(environment.d.constData()->vars);
+ envPtr = envlist.data();
+ }
+
DWORD dwCreationFlags = (GetConsoleWindow() ? 0 : CREATE_NO_WINDOW);
dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
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
+ 0, 0, 0,
+ STARTF_USESTDHANDLES,
+ 0, 0, 0,
+ stdinChannel.pipe[0], stdoutChannel.pipe[1], stderrChannel.pipe[1]
};
- success = CreateProcess(0, (wchar_t*)args.utf16(),
- 0, 0, FALSE, dwCreationFlags, 0,
- workingDir.isEmpty() ? 0 : (wchar_t*)workingDir.utf16(),
- &startupInfo, &pinfo);
+
+ const bool inheritHandles = stdinChannel.type == Channel::Redirect
+ || stdoutChannel.type == Channel::Redirect
+ || stderrChannel.type == Channel::Redirect;
+ QProcess::CreateProcessArguments cpargs = {
+ nullptr, reinterpret_cast<wchar_t *>(const_cast<ushort *>(args.utf16())),
+ nullptr, nullptr, inheritHandles, dwCreationFlags, envPtr,
+ workingDirectory.isEmpty()
+ ? nullptr : reinterpret_cast<const wchar_t *>(workingDirectory.utf16()),
+ &startupInfo, &pinfo
+ };
+ success = callCreateProcess(&cpargs);
if (success) {
CloseHandle(pinfo.hThread);
@@ -885,9 +924,19 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a
if (pid)
*pid = pinfo.dwProcessId;
} else if (GetLastError() == errorElevationRequired) {
- success = startDetachedUacPrompt(program, arguments, workingDir, pid);
+ if (envPtr)
+ qWarning("QProcess: custom environment will be ignored for detached elevated process.");
+ if (!stdinChannel.file.isEmpty() || !stdoutChannel.file.isEmpty()
+ || !stderrChannel.file.isEmpty()) {
+ qWarning("QProcess: file redirection is unsupported for detached elevated processes.");
+ }
+ success = startDetachedUacPrompt(program, arguments, nativeArguments,
+ workingDirectory, pid);
}
+ closeChannel(&stdinChannel);
+ closeChannel(&stdoutChannel);
+ closeChannel(&stderrChannel);
return success;
}