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 <oswald.buddenhagen@nokia.com>
Reviewed-by: Joerg Bornemann <joerg.bornemann@nokia.com>
This commit is contained in:
Joerg Bornemann 2012-01-05 18:24:53 +01:00 committed by Qt by Nokia
parent ece75a8adf
commit 2588a5b249
3 changed files with 26 additions and 26 deletions

4
dist/changes-5.0.0 vendored
View File

@ -144,6 +144,10 @@ information about a particular change.
- The QHttp, QHttpHeader, QHttpResponseHeader and QHttpRequestHeader classes have - The QHttp, QHttpHeader, QHttpResponseHeader and QHttpRequestHeader classes have
been removed, QNetworkAccessManager should be used instead. 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 * * General *

View File

@ -617,6 +617,14 @@ void QProcessPrivate::Channel::clear()
writes to its standard output and standard error will be written writes to its standard output and standard error will be written
to the standard output and standard error of the main process. 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() \sa setProcessChannelMode()
*/ */

View File

@ -92,6 +92,15 @@ static void qt_create_pipe(Q_PIPE *pipe, bool in)
CloseHandle(tmpHandle); 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. Create the pipes to a QProcessPrivate::Channel.
@ -108,8 +117,11 @@ bool QProcessPrivate::createChannel(Channel &channel)
if (channel.type == Channel::Normal) { if (channel.type == Channel::Normal) {
// we're piping this channel to our own process // 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; return true;
} else if (channel.type == Channel::Redirect) { } else if (channel.type == Channel::Redirect) {
// we're redirecting the channel to/from a file // we're redirecting the channel to/from a file
@ -465,18 +477,6 @@ qint64 QProcessPrivate::bytesAvailableFromStdout() const
#if defined QPROCESS_DEBUG #if defined QPROCESS_DEBUG
qDebug("QProcessPrivate::bytesAvailableFromStdout() == %d", bytesAvail); qDebug("QProcessPrivate::bytesAvailableFromStdout() == %d", bytesAvail);
#endif #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; return bytesAvail;
} }
@ -490,18 +490,6 @@ qint64 QProcessPrivate::bytesAvailableFromStderr() const
#if defined QPROCESS_DEBUG #if defined QPROCESS_DEBUG
qDebug("QProcessPrivate::bytesAvailableFromStderr() == %d", bytesAvail); qDebug("QProcessPrivate::bytesAvailableFromStderr() == %d", bytesAvail);
#endif #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; return bytesAvail;
} }