diff options
Diffstat (limited to 'src/corelib/io/qprocess_win.cpp')
-rw-r--r-- | src/corelib/io/qprocess_win.cpp | 128 |
1 files changed, 57 insertions, 71 deletions
diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp index d316af7c38..e64b133815 100644 --- a/src/corelib/io/qprocess_win.cpp +++ b/src/corelib/io/qprocess_win.cpp @@ -1,42 +1,6 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Copyright (C) 2017 Intel Corporation. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// Copyright (C) 2017 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only //#define QPROCESS_DEBUG #include <qdebug.h> @@ -64,6 +28,10 @@ QT_BEGIN_NAMESPACE +constexpr UINT KillProcessExitCode = 0xf291; + +using namespace Qt::StringLiterals; + QProcessEnvironment QProcessEnvironment::systemEnvironment() { QProcessEnvironment env; @@ -172,6 +140,7 @@ static bool qt_create_pipe(Q_PIPE *pipe, bool isInputPipe, BOOL defInheritFlag) DWORD dwError = GetLastError(); if (dwError != ERROR_PIPE_BUSY || !--attempts) { qErrnoWarning(dwError, "QProcess: CreateNamedPipe failed."); + SetLastError(dwError); return false; } } @@ -186,8 +155,10 @@ static bool qt_create_pipe(Q_PIPE *pipe, bool isInputPipe, BOOL defInheritFlag) FILE_FLAG_OVERLAPPED, NULL); if (hClient == INVALID_HANDLE_VALUE) { + DWORD dwError = GetLastError(); qErrnoWarning("QProcess: CreateFile failed."); CloseHandle(hServer); + SetLastError(dwError); return false; } @@ -204,10 +175,12 @@ static bool qt_create_pipe(Q_PIPE *pipe, bool isInputPipe, BOOL defInheritFlag) WaitForSingleObject(overlapped.hEvent, INFINITE); break; default: + dwError = GetLastError(); qErrnoWarning(dwError, "QProcess: ConnectNamedPipe failed."); CloseHandle(overlapped.hEvent); CloseHandle(hClient); CloseHandle(hServer); + SetLastError(dwError); return false; } } @@ -233,8 +206,13 @@ bool QProcessPrivate::openChannel(Channel &channel) switch (channel.type) { case Channel::Normal: { // we're piping this channel to our own process - if (&channel == &stdinChannel) - return qt_create_pipe(channel.pipe, true, FALSE); + if (&channel == &stdinChannel) { + if (!qt_create_pipe(channel.pipe, true, FALSE)) { + setErrorAndEmit(QProcess::FailedToStart, "pipe: "_L1 + qt_error_string(errno)); + return false; + } + return true; + } if (&channel == &stdoutChannel) { if (!stdoutChannel.reader) { @@ -247,8 +225,10 @@ bool QProcessPrivate::openChannel(Channel &channel) q->connect(stderrChannel.reader, SIGNAL(readyRead()), SLOT(_q_canReadStandardError())); } } - if (!qt_create_pipe(channel.pipe, false, FALSE)) + if (!qt_create_pipe(channel.pipe, false, FALSE)) { + setErrorAndEmit(QProcess::FailedToStart, "pipe: "_L1 + qt_error_string(errno)); return false; + } channel.reader->setHandle(channel.pipe[0]); channel.reader->startAsyncRead(); @@ -297,7 +277,6 @@ bool QProcessPrivate::openChannel(Channel &channel) setErrorAndEmit(QProcess::FailedToStart, QProcess::tr("Could not open output redirection for writing")); } - cleanup(); return false; } case Channel::PipeSource: { @@ -314,8 +293,10 @@ bool QProcessPrivate::openChannel(Channel &channel) Q_ASSERT(source == &stdoutChannel); Q_ASSERT(sink->process == this && sink->type == Channel::PipeSink); - if (!qt_create_pipe(source->pipe, /* in = */ false, TRUE)) // source is stdout + if (!qt_create_pipe(source->pipe, /* in = */ false, TRUE)) { // source is stdout + setErrorAndEmit(QProcess::FailedToStart, "pipe: "_L1 + qt_error_string(errno)); return false; + } sink->pipe[0] = source->pipe[0]; source->pipe[0] = INVALID_Q_PIPE; @@ -334,8 +315,10 @@ bool QProcessPrivate::openChannel(Channel &channel) Q_ASSERT(sink == &stdinChannel); Q_ASSERT(source->process == this && source->type == Channel::PipeSource); - if (!qt_create_pipe(sink->pipe, /* in = */ true, TRUE)) // sink is stdin + if (!qt_create_pipe(sink->pipe, /* in = */ true, TRUE)) { // sink is stdin + setErrorAndEmit(QProcess::FailedToStart, "pipe: "_L1 + qt_error_string(errno)); return false; + } source->pipe[1] = sink->pipe[1]; sink->pipe[1] = INVALID_Q_PIPE; @@ -391,44 +374,44 @@ static QString qt_create_commandline(const QString &program, const QStringList & 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('\\')); + if (!programName.startsWith(u'\"') && !programName.endsWith(u'\"') && programName.contains(u' ')) + programName = u'\"' + programName + u'\"'; + programName.replace(u'/', u'\\'); // add the program as the first arg ... it works better - args = programName + QLatin1Char(' '); + args = programName + u' '; } - for (int i=0; i<arguments.size(); ++i) { + for (qsizetype i = 0; i < arguments.size(); ++i) { QString tmp = arguments.at(i); // Quotes are escaped and their preceding backslashes are doubled. - int index = tmp.indexOf(QLatin1Char('"')); + qsizetype index = tmp.indexOf(u'"'); while (index >= 0) { // Escape quote - tmp.insert(index++, QLatin1Char('\\')); + tmp.insert(index++, u'\\'); // Double preceding backslashes (ignoring the one we just inserted) - for (int i = index - 2 ; i >= 0 && tmp.at(i) == QLatin1Char('\\') ; --i) { - tmp.insert(i, QLatin1Char('\\')); + for (qsizetype i = index - 2 ; i >= 0 && tmp.at(i) == u'\\' ; --i) { + tmp.insert(i, u'\\'); index++; } - index = tmp.indexOf(QLatin1Char('"'), index + 1); + index = tmp.indexOf(u'"', index + 1); } - if (tmp.isEmpty() || tmp.contains(QLatin1Char(' ')) || tmp.contains(QLatin1Char('\t'))) { + if (tmp.isEmpty() || tmp.contains(u' ') || tmp.contains(u'\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('\\')) + qsizetype i = tmp.length(); + while (i > 0 && tmp.at(i - 1) == u'\\') --i; - tmp.insert(i, QLatin1Char('"')); - tmp.prepend(QLatin1Char('"')); + tmp.insert(i, u'"'); + tmp.prepend(u'"'); } - args += QLatin1Char(' ') + tmp; + args += u' ' + tmp; } if (!nativeArguments.isEmpty()) { if (!args.isEmpty()) - args += QLatin1Char(' '); + args += u' '; args += nativeArguments; } @@ -441,7 +424,7 @@ static QByteArray qt_create_environment(const QProcessEnvironmentPrivate::Map &e QProcessEnvironmentPrivate::Map copy = environment; // add PATH if necessary (for DLL loading) - QProcessEnvironmentPrivate::Key pathKey(QLatin1String("PATH")); + QProcessEnvironmentPrivate::Key pathKey("PATH"_L1); if (!copy.contains(pathKey)) { QByteArray path = qgetenv("PATH"); if (!path.isEmpty()) @@ -449,7 +432,7 @@ static QByteArray qt_create_environment(const QProcessEnvironmentPrivate::Map &e } // add systemroot if needed - QProcessEnvironmentPrivate::Key rootKey(QLatin1String("SystemRoot")); + QProcessEnvironmentPrivate::Key rootKey("SystemRoot"_L1); if (!copy.contains(rootKey)) { QByteArray systemRoot = qgetenv("SystemRoot"); if (!systemRoot.isEmpty()) @@ -471,14 +454,14 @@ static QByteArray qt_create_environment(const QProcessEnvironmentPrivate::Map &e envlist.resize(envlist.size() + tmpSize); tmpSize = it.key().length() * sizeof(wchar_t); - memcpy(envlist.data() + pos, it.key().utf16(), tmpSize); + memcpy(envlist.data() + pos, it.key().data(), tmpSize); pos += tmpSize; memcpy(envlist.data() + pos, &equal, sizeof(wchar_t)); pos += sizeof(wchar_t); tmpSize = it.value().length() * sizeof(wchar_t); - memcpy(envlist.data() + pos, it.value().utf16(), tmpSize); + memcpy(envlist.data() + pos, it.value().data(), tmpSize); pos += tmpSize; memcpy(envlist.data() + pos, &nul, sizeof(wchar_t)); @@ -555,9 +538,9 @@ void QProcessPrivate::startProcess() q->setProcessState(QProcess::Starting); if (!openChannels()) { - QString errorString = QProcess::tr("Process failed to start: %1").arg(qt_error_string()); + // openChannel sets the error string + Q_ASSERT(!errorString.isEmpty()); cleanup(); - setErrorAndEmit(QProcess::FailedToStart, errorString); return; } @@ -666,7 +649,7 @@ void QProcessPrivate::terminateProcess() void QProcessPrivate::killProcess() { if (pid) - TerminateProcess(pid->hProcess, 0xf291); + TerminateProcess(pid->hProcess, KillProcessExitCode); } bool QProcessPrivate::waitForStarted(const QDeadlineTimer &) @@ -816,8 +799,11 @@ void QProcessPrivate::findExitCode() Q_ASSERT(pid); if (GetExitCodeProcess(pid->hProcess, &theExitCode)) { exitCode = theExitCode; - crashed = (exitCode == 0xf291 // our magic number, see killProcess - || (theExitCode >= 0x80000000 && theExitCode < 0xD0000000)); + if (exitCode == KillProcessExitCode + || (theExitCode >= 0x80000000 && theExitCode < 0xD0000000)) + exitStatus = QProcess::CrashExit; + else + exitStatus = QProcess::NormalExit; } } |