summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJoerg Bornemann <joerg.bornemann@nokia.com>2011-12-08 14:16:47 +0100
committerQt by Nokia <qt-info@nokia.com>2012-01-26 18:45:14 +0100
commit9efbc9f60a511e902d3f8b368296212b43222f52 (patch)
treefd34641f490d74066e23a1b41b4d0d01f678d17e /src
parent389fc8885b9221857c843f88f94595d06ea5bd26 (diff)
QProcess/Win: use named pipes for redirecting standard I/O
Named pipes allow us to make use of overlapped I/O for redirected stdin, stdout and stderr. Change-Id: I50191b036bce696147139b200ddbc6c31c16112b Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@nokia.com>
Diffstat (limited to 'src')
-rw-r--r--src/corelib/io/qprocess_win.cpp72
1 files changed, 51 insertions, 21 deletions
diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp
index 4f5f151868..8981f19e31 100644
--- a/src/corelib/io/qprocess_win.cpp
+++ b/src/corelib/io/qprocess_win.cpp
@@ -48,9 +48,6 @@
#include <qfileinfo.h>
#include <qregexp.h>
#include <qtimer.h>
-#include <qthread.h>
-#include <qmutex.h>
-#include <qwaitcondition.h>
#include <qwineventnotifier.h>
#include <private/qthread_p.h>
#include <qdebug.h>
@@ -66,30 +63,63 @@ QT_BEGIN_NAMESPACE
#define NOTIFYTIMEOUT 100
-static void qt_create_pipe(Q_PIPE *pipe, bool in)
+static void qt_create_pipe(Q_PIPE *pipe, bool isInputPipe)
{
- // Open the pipes. Make non-inheritable copies of input write and output
- // read handles to avoid non-closable handles (this is done by the
- // DuplicateHandle() call).
+ // Anomymous pipes do not support asynchronous I/O. Thus we
+ // create named pipes for redirecting stdout, stderr and stdin.
- SECURITY_ATTRIBUTES secAtt = { sizeof( SECURITY_ATTRIBUTES ), NULL, TRUE };
+ SECURITY_ATTRIBUTES secAtt = { 0 };
+ secAtt.nLength = sizeof(secAtt);
+ secAtt.bInheritHandle = isInputPipe; // The read handle must be non-inheritable for output pipes.
- HANDLE tmpHandle;
- if (in) { // stdin
- if (!CreatePipe(&pipe[0], &tmpHandle, &secAtt, 1024 * 1024))
- return;
- if (!DuplicateHandle(GetCurrentProcess(), tmpHandle, GetCurrentProcess(),
- &pipe[1], 0, FALSE, DUPLICATE_SAME_ACCESS))
- return;
- } else { // stdout or stderr
- if (!CreatePipe(&tmpHandle, &pipe[1], &secAtt, 1024 * 1024))
- return;
- if (!DuplicateHandle(GetCurrentProcess(), tmpHandle, GetCurrentProcess(),
- &pipe[0], 0, FALSE, DUPLICATE_SAME_ACCESS))
+ HANDLE hRead;
+ wchar_t pipeName[256];
+ unsigned int attempts = 1000;
+ forever {
+ // ### The user must make sure to call qsrand() to make the pipe names less predictable.
+ // ### Replace the call to qrand() with a secure version, once we have it in Qt.
+ swprintf_s(pipeName, sizeof(pipeName) / sizeof(wchar_t), L"\\\\.\\pipe\\qt-%X", qrand());
+
+ const DWORD dwPipeBufferSize = 1024 * 1024;
+ hRead = CreateNamedPipe(pipeName,
+ PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
+ PIPE_TYPE_BYTE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS,
+ 1, // only one pipe instance
+ 0, // output buffer size
+ dwPipeBufferSize, // input buffer size
+ 0,
+ &secAtt);
+ if (hRead != INVALID_HANDLE_VALUE)
+ break;
+ DWORD dwError = GetLastError();
+ if (dwError != ERROR_PIPE_BUSY || !--attempts) {
+ qErrnoWarning(dwError, "QProcess: CreateNamedPipe failed.", GetLastError());
return;
+ }
}
- CloseHandle(tmpHandle);
+ // The write handle must be non-inheritable for input pipes.
+ secAtt.bInheritHandle = !isInputPipe;
+
+ HANDLE hWrite = INVALID_HANDLE_VALUE;
+ hWrite = CreateFile(pipeName,
+ GENERIC_WRITE,
+ 0,
+ &secAtt,
+ OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED,
+ NULL);
+ if (hWrite == INVALID_HANDLE_VALUE) {
+ qWarning("QProcess: CreateFile failed with error code %d.\n", GetLastError());
+ CloseHandle(hRead);
+ return;
+ }
+
+ // Wait until connection is in place.
+ ConnectNamedPipe(hRead, NULL);
+
+ pipe[0] = hRead;
+ pipe[1] = hWrite;
}
static void duplicateStdWriteChannel(Q_PIPE *pipe, DWORD nStdHandle)