From 068baa9bb6d526cccc0c8bc7cdbb84bbdf137f95 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Fri, 5 Jun 2015 16:57:18 +0200 Subject: add a way to modify CreateProcess parameters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ChangeLog][QtCore][QProcess] Added method setCreateProcessArgumentsModifier to QProcess on Windows to enable users to intercept and modify CreateProcess parameters. With such a modifier, calling code can decide whether to inherit handles, modify the STARTUPINFO struct, and pass its own combination of process flags to CreateProcess. Task-number: QTBUG-390 Task-number: QTBUG-6917 Task-number: QTBUG-9350 Task-number: QTBUG-24619 Change-Id: I14757dbbacfebb1c89f52402d36fba0ba9c45f3a Reviewed-by: Björn Breitmeyer Reviewed-by: Thiago Macieira --- src/corelib/io/qprocess.cpp | 74 +++++++++++++++++++++++++++++++++++++++++ src/corelib/io/qprocess.h | 22 +++++++++++- src/corelib/io/qprocess_p.h | 1 + src/corelib/io/qprocess_win.cpp | 20 ++++++++--- 4 files changed, 111 insertions(+), 6 deletions(-) (limited to 'src/corelib/io') diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp index 952116b9db..315142aabe 100644 --- a/src/corelib/io/qprocess.cpp +++ b/src/corelib/io/qprocess.cpp @@ -743,6 +743,47 @@ void QProcessPrivate::Channel::clear() \sa exitStatus() */ +/*! + \typedef QProcess::CreateProcessArgumentModifier + \note This typedef is only available on desktop Windows and Windows CE. + + On Windows, QProcess uses the Win32 API function \c CreateProcess to + start child processes. While QProcess provides a comfortable way to start + processes without worrying about platform + details, it is in some cases desirable to fine-tune the parameters that are + passed to \c CreateProcess. This is done by defining a + \c CreateProcessArgumentModifier function and passing it to + \c setCreateProcessArgumentsModifier. + + A \c CreateProcessArgumentModifier function takes one parameter: a pointer + to a \c CreateProcessArguments struct. The members of this struct will be + passed to \c CreateProcess after the \c CreateProcessArgumentModifier + function is called. + + The following example demonstrates how to pass custom flags to + \c CreateProcess. + When starting a console process B from a console process A, QProcess will + reuse the console window of process A for process B by default. In this + example, a new console window with a custom color scheme is created for the + child process B instead. + + \snippet qprocess/qprocess-createprocessargumentsmodifier.cpp 0 + + \sa QProcess::CreateProcessArguments + \sa setCreateProcessArgumentsModifier() +*/ + +/*! + \class QProcess::CreateProcessArguments + \note This struct is only available on the Windows platform. + + This struct is a representation of all parameters of the Windows API + function \c CreateProcess. It is used as parameter for + \c CreateProcessArgumentModifier functions. + + \sa QProcess::CreateProcessArgumentModifier +*/ + /*! \fn void QProcess::error(QProcess::ProcessError error) \obsolete @@ -1563,6 +1604,39 @@ void QProcess::setNativeArguments(const QString &arguments) d->nativeArguments = arguments; } +/*! + \since 5.7 + + Returns a previously set \c CreateProcess modifier function. + + \note This function is available only on the Windows platform. + + \sa setCreateProcessArgumentsModifier() + \sa QProcess::CreateProcessArgumentModifier +*/ +QProcess::CreateProcessArgumentModifier QProcess::createProcessArgumentsModifier() const +{ + Q_D(const QProcess); + return d->modifyCreateProcessArgs; +} + +/*! + \since 5.7 + + Sets the \a modifier for the \c CreateProcess Win32 API call. + Pass \c QProcess::CreateProcessArgumentModifier() to remove a previously set one. + + \note This function is available only on the Windows platform and requires + C++11. + + \sa QProcess::CreateProcessArgumentModifier +*/ +void QProcess::setCreateProcessArgumentsModifier(CreateProcessArgumentModifier modifier) +{ + Q_D(QProcess); + d->modifyCreateProcessArgs = modifier; +} + #endif /*! diff --git a/src/corelib/io/qprocess.h b/src/corelib/io/qprocess.h index f95358250e..52e0316857 100644 --- a/src/corelib/io/qprocess.h +++ b/src/corelib/io/qprocess.h @@ -38,6 +38,8 @@ #include #include +#include + QT_BEGIN_NAMESPACE @@ -48,6 +50,8 @@ typedef qint64 Q_PID; #else QT_END_NAMESPACE typedef struct _PROCESS_INFORMATION *Q_PID; +typedef struct _SECURITY_ATTRIBUTES Q_SECURITY_ATTRIBUTES; +typedef struct _STARTUPINFOW Q_STARTUPINFO; QT_BEGIN_NAMESPACE #endif @@ -180,7 +184,23 @@ public: #if defined(Q_OS_WIN) QString nativeArguments() const; void setNativeArguments(const QString &arguments); -#endif + struct CreateProcessArguments + { + const wchar_t *applicationName; + wchar_t *arguments; + Q_SECURITY_ATTRIBUTES *processAttributes; + Q_SECURITY_ATTRIBUTES *threadAttributes; + bool inheritHandles; + unsigned long flags; + void *environment; + const wchar_t *currentDirectory; + Q_STARTUPINFO *startupInfo; + Q_PID processInformation; + }; + typedef std::function CreateProcessArgumentModifier; + CreateProcessArgumentModifier createProcessArgumentsModifier() const; + void setCreateProcessArgumentsModifier(CreateProcessArgumentModifier modifier); +#endif // Q_OS_WIN QString workingDirectory() const; void setWorkingDirectory(const QString &dir); diff --git a/src/corelib/io/qprocess_p.h b/src/corelib/io/qprocess_p.h index af88d07a7a..227a583718 100644 --- a/src/corelib/io/qprocess_p.h +++ b/src/corelib/io/qprocess_p.h @@ -329,6 +329,7 @@ public: QStringList arguments; #if defined(Q_OS_WIN) QString nativeArguments; + QProcess::CreateProcessArgumentModifier modifyCreateProcessArgs; #endif QProcessEnvironment environment; diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp index 80e6d5bb61..bb5bb4b0a5 100644 --- a/src/corelib/io/qprocess_win.cpp +++ b/src/corelib/io/qprocess_win.cpp @@ -497,11 +497,21 @@ void QProcessPrivate::startProcess() 0, 0, 0, stdinChannel.pipe[0], stdoutChannel.pipe[1], stderrChannel.pipe[1] }; - success = CreateProcess(0, (wchar_t*)args.utf16(), - 0, 0, TRUE, dwCreationFlags, - environment.isEmpty() ? 0 : envlist.data(), - workingDirectory.isEmpty() ? 0 : (wchar_t*)QDir::toNativeSeparators(workingDirectory).utf16(), - &startupInfo, pid); + + QProcess::CreateProcessArguments cpargs = { + 0, (wchar_t*)args.utf16(), + 0, 0, TRUE, dwCreationFlags, + environment.isEmpty() ? 0 : envlist.data(), + workingDirectory.isEmpty() ? 0 : (wchar_t*)QDir::toNativeSeparators(workingDirectory).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); + QString errorString; if (!success) { // Capture the error string before we do CloseHandle below -- cgit v1.2.3