From 2588a5b24965d9afa0d6e368a9f42491d1cfb5f7 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Thu, 5 Jan 2012 18:24:53 +0100 Subject: [PATCH] QProcess/Win: direct forwarding of stdout and stderr We are now directly passing the standard out/err handles to CreateProcess instead of reading the output and writing it. The downside is, that we cannot automatically forward the process output of GUI applications anymore. This behaviour is intended by the CreateProcess API. Change-Id: Ic6e35c8c338dbea1a9f345567a37d938da1f34a2 Reviewed-by: Oswald Buddenhagen Reviewed-by: Joerg Bornemann --- dist/changes-5.0.0 | 4 ++++ src/corelib/io/qprocess.cpp | 8 +++++++ src/corelib/io/qprocess_win.cpp | 40 ++++++++++++--------------------- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/dist/changes-5.0.0 b/dist/changes-5.0.0 index 8855aa3852..1d6a7d6c84 100644 --- a/dist/changes-5.0.0 +++ b/dist/changes-5.0.0 @@ -144,6 +144,10 @@ information about a particular change. - The QHttp, QHttpHeader, QHttpResponseHeader and QHttpRequestHeader classes have been removed, QNetworkAccessManager should be used instead. +- QProcess + + * On Windows, QProcess::ForwardedChannels will not forward the output of GUI + applications anymore, if they do not create a console. **************************************************************************** * General * diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp index 6f57f9f0e8..9f6fa4933e 100644 --- a/src/corelib/io/qprocess.cpp +++ b/src/corelib/io/qprocess.cpp @@ -617,6 +617,14 @@ void QProcessPrivate::Channel::clear() writes to its standard output and standard error will be written to the standard output and standard error of the main process. + \note Windows intentionally suppresses output from GUI-only + applications to inherited consoles. + This does \e not apply to output redirected to files or pipes. + To forward the output of GUI-only applications on the console + nonetheless, you must use SeparateChannels and do the forwarding + yourself by reading the output and writing it to the appropriate + output channels. + \sa setProcessChannelMode() */ diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp index fd5f078ff0..8c6444d173 100644 --- a/src/corelib/io/qprocess_win.cpp +++ b/src/corelib/io/qprocess_win.cpp @@ -92,6 +92,15 @@ static void qt_create_pipe(Q_PIPE *pipe, bool in) CloseHandle(tmpHandle); } +static void duplicateStdWriteChannel(Q_PIPE *pipe, DWORD nStdHandle) +{ + pipe[0] = INVALID_Q_PIPE; + HANDLE hStdWriteChannel = GetStdHandle(nStdHandle); + HANDLE hCurrentProcess = GetCurrentProcess(); + DuplicateHandle(hCurrentProcess, hStdWriteChannel, hCurrentProcess, + &pipe[1], 0, TRUE, DUPLICATE_SAME_ACCESS); +} + /* Create the pipes to a QProcessPrivate::Channel. @@ -108,8 +117,11 @@ bool QProcessPrivate::createChannel(Channel &channel) if (channel.type == Channel::Normal) { // we're piping this channel to our own process - qt_create_pipe(channel.pipe, &channel == &stdinChannel); - + const bool isStdInChannel = (&channel == &stdinChannel); + if (isStdInChannel || processChannelMode != QProcess::ForwardedChannels) + qt_create_pipe(channel.pipe, isStdInChannel); + else + duplicateStdWriteChannel(channel.pipe, (&channel == &stdoutChannel) ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE); return true; } else if (channel.type == Channel::Redirect) { // we're redirecting the channel to/from a file @@ -465,18 +477,6 @@ qint64 QProcessPrivate::bytesAvailableFromStdout() const #if defined QPROCESS_DEBUG qDebug("QProcessPrivate::bytesAvailableFromStdout() == %d", bytesAvail); #endif - if (processChannelMode == QProcess::ForwardedChannels && bytesAvail > 0) { - QByteArray buf(bytesAvail, 0); - DWORD bytesRead = 0; - if (ReadFile(stdoutChannel.pipe[0], buf.data(), buf.size(), &bytesRead, 0) && bytesRead > 0) { - HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); - if (hStdout) { - DWORD bytesWritten = 0; - WriteFile(hStdout, buf.data(), bytesRead, &bytesWritten, 0); - } - } - bytesAvail = 0; - } return bytesAvail; } @@ -490,18 +490,6 @@ qint64 QProcessPrivate::bytesAvailableFromStderr() const #if defined QPROCESS_DEBUG qDebug("QProcessPrivate::bytesAvailableFromStderr() == %d", bytesAvail); #endif - if (processChannelMode == QProcess::ForwardedChannels && bytesAvail > 0) { - QByteArray buf(bytesAvail, 0); - DWORD bytesRead = 0; - if (ReadFile(stderrChannel.pipe[0], buf.data(), buf.size(), &bytesRead, 0) && bytesRead > 0) { - HANDLE hStderr = GetStdHandle(STD_ERROR_HANDLE); - if (hStderr) { - DWORD bytesWritten = 0; - WriteFile(hStderr, buf.data(), bytesRead, &bytesWritten, 0); - } - } - bytesAvail = 0; - } return bytesAvail; }