diff options
Diffstat (limited to 'src/corelib/io/qprocess_win.cpp')
-rw-r--r-- | src/corelib/io/qprocess_win.cpp | 127 |
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; } |