7#include <private/qdebug_p.h>
20#include <private/qsystemlibrary_p.h>
21#include <private/qthread_p.h>
23#include "private/qfsfileengine_p.h"
25#ifndef PIPE_REJECT_REMOTE_CLIENTS
26#define PIPE_REJECT_REMOTE_CLIENTS 0x08
40 if (
wchar_t *envStrings = GetEnvironmentStringsW()) {
41 for (
const wchar_t *
entry = envStrings; *
entry; ) {
42 const int entryLen = int(wcslen(
entry));
44 if (
const wchar_t *
equal = wcschr(
entry + 1, L
'=')) {
50 entry += entryLen + 1;
52 FreeEnvironmentStringsW(envStrings);
62 QProcessPoller(
const QProcessPrivate &proc);
66 enum { maxHandles = 4 };
67 HANDLE handles[maxHandles];
68 DWORD handleCount = 0;
71QProcessPoller::QProcessPoller(
const QProcessPrivate &proc)
73 if (proc.stdinChannel.writer)
74 handles[handleCount++] = proc.stdinChannel.writer->syncEvent();
75 if (proc.stdoutChannel.reader)
76 handles[handleCount++] = proc.stdoutChannel.reader->syncEvent();
77 if (proc.stderrChannel.reader)
78 handles[handleCount++] = proc.stderrChannel.reader->syncEvent();
80 handles[handleCount++] = proc.pid->hProcess;
88 waitRet = WaitForMultipleObjectsEx(handleCount, handles, FALSE,
90 }
while (waitRet == WAIT_IO_COMPLETION);
92 if (waitRet - WAIT_OBJECT_0 < handleCount)
95 return (waitRet == WAIT_TIMEOUT) ? 0 : -1;
99static bool qt_create_pipe(
Q_PIPE *pipe,
bool isInputPipe, BOOL defInheritFlag)
108 SECURITY_ATTRIBUTES secAtt = {
sizeof(SECURITY_ATTRIBUTES), 0, defInheritFlag };
111 wchar_t pipeName[256];
112 unsigned int attempts = 1000;
114 _snwprintf(pipeName,
sizeof(pipeName) /
sizeof(pipeName[0]),
118 DWORD dwOpenMode = FILE_FLAG_OVERLAPPED;
119 DWORD dwOutputBufferSize = 0;
120 DWORD dwInputBufferSize = 0;
121 const DWORD dwPipeBufferSize = 1024 * 1024;
123 dwOpenMode |= PIPE_ACCESS_OUTBOUND;
124 dwOutputBufferSize = dwPipeBufferSize;
126 dwOpenMode |= PIPE_ACCESS_INBOUND;
127 dwInputBufferSize = dwPipeBufferSize;
130 hServer = CreateNamedPipe(pipeName,
138 if (hServer != INVALID_HANDLE_VALUE)
140 DWORD dwError = GetLastError();
141 if (dwError != ERROR_PIPE_BUSY || !--attempts) {
147 secAtt.bInheritHandle = TRUE;
148 const HANDLE hClient = CreateFile(pipeName,
149 (isInputPipe ? (GENERIC_READ | FILE_WRITE_ATTRIBUTES)
154 FILE_FLAG_OVERLAPPED,
156 if (hClient == INVALID_HANDLE_VALUE) {
158 CloseHandle(hServer);
163 OVERLAPPED overlapped;
164 ZeroMemory(&overlapped,
sizeof(overlapped));
165 overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
166 if (ConnectNamedPipe(hServer, &overlapped) == 0) {
167 DWORD dwError = GetLastError();
169 case ERROR_PIPE_CONNECTED:
171 case ERROR_IO_PENDING:
172 WaitForSingleObject(overlapped.hEvent, INFINITE);
175 qErrnoWarning(dwError,
"QProcess: ConnectNamedPipe failed.");
176 CloseHandle(overlapped.hEvent);
177 CloseHandle(hClient);
178 CloseHandle(hServer);
182 CloseHandle(overlapped.hEvent);
197bool QProcessPrivate::openChannel(Channel &
channel)
202 case Channel::Normal: {
205 return qt_create_pipe(
channel.pipe,
true, FALSE);
207 if (&
channel == &stdoutChannel) {
208 if (!stdoutChannel.reader) {
210 q->connect(stdoutChannel.reader,
SIGNAL(readyRead()),
SLOT(_q_canReadStandardOutput()));
213 if (!stderrChannel.reader) {
215 q->connect(stderrChannel.reader,
SIGNAL(readyRead()),
SLOT(_q_canReadStandardError()));
218 if (!qt_create_pipe(
channel.pipe,
false, FALSE))
222 channel.reader->startAsyncRead();
225 case Channel::Redirect: {
227 SECURITY_ATTRIBUTES secAtt = {
sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
229 if (&
channel == &stdinChannel) {
233 CreateFile((
const wchar_t*)QFSFileEnginePrivate::longFileName(
channel.file).utf16(),
235 FILE_SHARE_READ | FILE_SHARE_WRITE,
238 FILE_ATTRIBUTE_NORMAL,
244 setErrorAndEmit(QProcess::FailedToStart,
245 QProcess::tr(
"Could not open input redirection for reading"));
250 CreateFile((
const wchar_t *)QFSFileEnginePrivate::longFileName(
channel.file).utf16(),
252 FILE_SHARE_READ | FILE_SHARE_WRITE,
254 channel.append ? OPEN_ALWAYS : CREATE_ALWAYS,
255 FILE_ATTRIBUTE_NORMAL,
260 SetFilePointer(
channel.pipe[1], 0, NULL, FILE_END);
265 setErrorAndEmit(QProcess::FailedToStart,
266 QProcess::tr(
"Could not open output redirection for writing"));
271 case Channel::PipeSource: {
285 if (!qt_create_pipe(
source->pipe,
false, TRUE))
293 case Channel::PipeSink: {
305 if (!qt_create_pipe(
sink->pipe,
true, TRUE))
317void QProcessPrivate::destroyPipe(
Q_PIPE pipe[2])
320 CloseHandle(pipe[0]);
324 CloseHandle(pipe[1]);
329void QProcessPrivate::closeChannel(Channel *
channel)
331 if (
channel == &stdinChannel) {
341void QProcessPrivate::cleanup()
343 q_func()->setProcessState(QProcess::NotRunning);
346 delete processFinishedNotifier;
347 processFinishedNotifier =
nullptr;
349 CloseHandle(pid->hThread);
350 CloseHandle(pid->hProcess);
357 const QString &nativeArguments)
363 programName = u
'\"' + programName + u
'\"';
364 programName.
replace(u
'/', u
'\\');
367 args = programName + u
' ';
389 while (
i > 0 && tmp.
at(
i - 1) == u
'\\')
397 if (!nativeArguments.
isEmpty()) {
400 args += nativeArguments;
413 if (!
copy.contains(pathKey)) {
421 if (!
copy.contains(rootKey)) {
428 auto it =
copy.constBegin();
429 const auto end =
copy.constEnd();
431 static const wchar_t equal = L
'=';
432 static const wchar_t nul = L
'\0';
435 qsizetype tmpSize =
sizeof(wchar_t) * (
it.key().length() +
it.value().length() + 2);
437 if (tmpSize ==
sizeof(
wchar_t) * 2)
441 tmpSize =
it.key().length() *
sizeof(wchar_t);
442 memcpy(envlist.
data() +
pos,
it.key().data(), tmpSize);
446 pos +=
sizeof(wchar_t);
448 tmpSize =
it.value().length() *
sizeof(wchar_t);
449 memcpy(envlist.
data() +
pos,
it.value().data(), tmpSize);
452 memcpy(envlist.
data() +
pos, &nul,
sizeof(
wchar_t));
453 pos +=
sizeof(wchar_t);
465static Q_PIPE pipeOrStdHandle(
Q_PIPE pipe, DWORD handleNumber)
467 return pipe !=
INVALID_Q_PIPE ? pipe : GetStdHandle(handleNumber);
470STARTUPINFOW QProcessPrivate::createStartupInfo()
472 Q_PIPE stdinPipe = pipeOrStdHandle(stdinChannel.pipe[0], STD_INPUT_HANDLE);
473 Q_PIPE stdoutPipe = pipeOrStdHandle(stdoutChannel.pipe[1], STD_OUTPUT_HANDLE);
474 Q_PIPE stderrPipe = stderrChannel.pipe[1];
476 stderrPipe = (processChannelMode == QProcess::MergedChannels)
478 : GetStdHandle(STD_ERROR_HANDLE);
482 sizeof(STARTUPINFOW), 0, 0, 0,
486 STARTF_USESTDHANDLES,
488 stdinPipe, stdoutPipe, stderrPipe
492bool QProcessPrivate::callCreateProcess(QProcess::CreateProcessArguments *cpargs)
494 if (modifyCreateProcessArgs)
495 modifyCreateProcessArgs(cpargs);
496 bool success = CreateProcess(cpargs->applicationName, cpargs->arguments,
497 cpargs->processAttributes, cpargs->threadAttributes,
498 cpargs->inheritHandles, cpargs->flags, cpargs->environment,
499 cpargs->currentDirectory, cpargs->startupInfo,
500 cpargs->processInformation);
502 CloseHandle(stdinChannel.pipe[0]);
506 CloseHandle(stdoutChannel.pipe[1]);
510 CloseHandle(stderrChannel.pipe[1]);
516void QProcessPrivate::startProcess()
520 pid =
new PROCESS_INFORMATION;
521 memset(pid, 0,
sizeof(PROCESS_INFORMATION));
523 q->setProcessState(QProcess::Starting);
525 if (!openChannels()) {
528 setErrorAndEmit(QProcess::FailedToStart, errorString);
534 if (!environment.inheritsFromParent())
535 envlist = qt_create_environment(environment.d.constData()->vars);
537#if defined QPROCESS_DEBUG
538 qDebug(
"Creating process");
541 qDebug(
" pass environment : %s", environment.
isEmpty() ?
"no" :
"yes");
549 DWORD dwCreationFlags = (GetConsoleWindow() ? 0 : CREATE_NO_WINDOW);
550 dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
551 STARTUPINFOW startupInfo = createStartupInfo();
553 QProcess::CreateProcessArguments cpargs = {
554 nullptr,
reinterpret_cast<wchar_t *
>(
const_cast<ushort *
>(
args.utf16())),
555 nullptr,
nullptr,
true, dwCreationFlags,
556 environment.inheritsFromParent() ?
nullptr : envlist.
data(),
557 nativeWorkingDirectory.
isEmpty()
558 ?
nullptr :
reinterpret_cast<const wchar_t *
>(nativeWorkingDirectory.
utf16()),
562 if (!callCreateProcess(&cpargs)) {
566 setErrorAndEmit(QProcess::FailedToStart, errorString);
573 if (stdinChannel.writer)
574 stdinChannel.writer->setHandle(stdinChannel.pipe[1]);
576 q->setProcessState(QProcess::Running);
582 if (threadData.loadRelaxed()->hasEventDispatcher()) {
585 processFinishedNotifier->setEnabled(
true);
588 _q_startupNotification();
591bool QProcessPrivate::processStarted(
QString * )
593 return processState == QProcess::Running;
596qint64 QProcessPrivate::bytesAvailableInChannel(
const Channel *
channel)
const
601 DWORD bytesAvail =
channel->reader->bytesAvailable();
602#if defined QPROCESS_DEBUG
603 qDebug(
"QProcessPrivate::bytesAvailableInChannel(%d) == %lld",
616static BOOL QT_WIN_CALLBACK qt_terminateApp(HWND hwnd, LPARAM procId)
618 DWORD currentProcId = 0;
619 GetWindowThreadProcessId(hwnd, ¤tProcId);
620 if (currentProcId == (DWORD)procId)
621 PostMessage(hwnd, WM_CLOSE, 0, 0);
626void QProcessPrivate::terminateProcess()
629 EnumWindows(qt_terminateApp, (LPARAM)pid->dwProcessId);
630 PostThreadMessage(pid->dwThreadId, WM_CLOSE, 0, 0);
634void QProcessPrivate::killProcess()
642 if (processStarted())
645 if (processError == QProcess::FailedToStart)
652bool QProcessPrivate::drainOutputPipes()
654 bool readyReadEmitted =
false;
656 if (stdoutChannel.reader) {
657 stdoutChannel.reader->drainAndStop();
658 readyReadEmitted = _q_canReadStandardOutput();
660 if (stderrChannel.reader) {
661 stderrChannel.reader->drainAndStop();
662 readyReadEmitted |= _q_canReadStandardError();
665 return readyReadEmitted;
671 QProcessPoller poller(*
this);
678 if (stdinChannel.writer)
679 stdinChannel.writer->checkForWrite();
681 if ((stdoutChannel.reader && stdoutChannel.reader->checkForReadyRead())
682 || (stderrChannel.reader && stderrChannel.reader->checkForReadyRead()))
688 if (WaitForSingleObject(pid->hProcess, 0) == WAIT_OBJECT_0) {
689 bool readyReadEmitted = drainOutputPipes();
692 return readyReadEmitted;
707 if (!stdinChannel.writer || !stdinChannel.writer->isWriteOperationActive())
710 QProcessPoller poller(*
this);
717 if (stdinChannel.writer->checkForWrite())
721 if (stdoutChannel.reader)
722 stdoutChannel.reader->checkForReadyRead();
725 if (stderrChannel.reader)
726 stderrChannel.reader->checkForReadyRead();
733 if (WaitForSingleObject(pid->hProcess, 0) == WAIT_OBJECT_0) {
747#if defined QPROCESS_DEBUG
752 QProcessPoller poller(*
this);
759 if (stdinChannel.writer)
760 stdinChannel.writer->checkForWrite();
761 if (stdoutChannel.reader)
762 stdoutChannel.reader->checkForReadyRead();
763 if (stderrChannel.reader)
764 stderrChannel.reader->checkForReadyRead();
769 if (WaitForSingleObject(pid->hProcess, 0) == WAIT_OBJECT_0) {
781void QProcessPrivate::findExitCode()
785 if (GetExitCodeProcess(pid->hProcess, &theExitCode)) {
786 exitCode = theExitCode;
788 || (theExitCode >= 0x80000000 && theExitCode < 0xD0000000))
789 exitStatus = QProcess::CrashExit;
791 exitStatus = QProcess::NormalExit;
802 if (
d->stdinChannel.closed) {
803#if defined QPROCESS_DEBUG
804 qDebug(
"QProcess::writeData(%p \"%s\", %lld) == 0 (write channel closing)",
810 if (!
d->stdinChannel.writer) {
813 d, &QProcessPrivate::_q_bytesWritten);
815 d, &QProcessPrivate::_q_writeFailed);
818 if (
d->isWriteChunkCached(
data,
len))
819 d->stdinChannel.writer->write(*(
d->currentWriteChunk));
821 d->stdinChannel.writer->write(
data,
len);
823#if defined QPROCESS_DEBUG
824 qDebug(
"QProcess::writeData(%p \"%s\", %lld) == %lld (written to buffer)",
830qint64 QProcessPrivate::pipeWriterBytesToWrite()
const
832 return stdinChannel.writer ? stdinChannel.writer->bytesToWrite() :
qint64(0);
835void QProcessPrivate::_q_bytesWritten(
qint64 bytes)
839 if (!emittedBytesWritten) {
841 emit q->bytesWritten(bytes);
843 if (stdinChannel.closed && pipeWriterBytesToWrite() == 0)
847void QProcessPrivate::_q_writeFailed()
850 setErrorAndEmit(QProcess::WriteError);
856 const QString &nativeArguments,
861 SHELLEXECUTEINFOW shellExecuteExInfo;
862 memset(&shellExecuteExInfo, 0,
sizeof(SHELLEXECUTEINFOW));
863 shellExecuteExInfo.cbSize =
sizeof(SHELLEXECUTEINFOW);
864 shellExecuteExInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_UNICODE | SEE_MASK_FLAG_NO_UI | SEE_MASK_CLASSNAME;
865 shellExecuteExInfo.lpClass = L
"exefile";
866 shellExecuteExInfo.lpVerb = L
"runas";
868 shellExecuteExInfo.lpFile =
reinterpret_cast<LPCWSTR
>(
program.utf16());
870 shellExecuteExInfo.lpParameters =
reinterpret_cast<LPCWSTR
>(
args.utf16());
872 shellExecuteExInfo.lpDirectory =
reinterpret_cast<LPCWSTR
>(workingDir.
utf16());
873 shellExecuteExInfo.nShow = SW_SHOWNORMAL;
875 if (!ShellExecuteExW(&shellExecuteExInfo))
878 *pid =
qint64(GetProcessId(shellExecuteExInfo.hProcess));
879 CloseHandle(shellExecuteExInfo.hProcess);
883bool QProcessPrivate::startDetached(
qint64 *pid)
885 static const DWORD errorElevationRequired = 740;
887 if (!openChannelsForDetached()) {
894 bool success =
false;
895 PROCESS_INFORMATION pinfo;
897 void *envPtr =
nullptr;
899 if (!environment.inheritsFromParent()) {
900 envlist = qt_create_environment(environment.d.constData()->vars);
901 envPtr = envlist.
data();
904 DWORD dwCreationFlags = (GetConsoleWindow() ? 0 : CREATE_NO_WINDOW);
905 dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
906 STARTUPINFOW startupInfo = createStartupInfo();
907 QProcess::CreateProcessArguments cpargs = {
908 nullptr,
reinterpret_cast<wchar_t *
>(
const_cast<ushort *
>(
args.utf16())),
909 nullptr,
nullptr,
true, dwCreationFlags, envPtr,
910 workingDirectory.isEmpty()
911 ?
nullptr :
reinterpret_cast<const wchar_t *
>(workingDirectory.utf16()),
914 success = callCreateProcess(&cpargs);
917 CloseHandle(pinfo.hThread);
918 CloseHandle(pinfo.hProcess);
920 *pid = pinfo.dwProcessId;
921 }
else if (GetLastError() == errorElevationRequired) {
923 qWarning(
"QProcess: custom environment will be ignored for detached elevated process.");
924 if (!stdinChannel.file.isEmpty() || !stdoutChannel.file.isEmpty()
925 || !stderrChannel.file.isEmpty()) {
926 qWarning(
"QProcess: file redirection is unsupported for detached elevated processes.");
929 workingDirectory, pid);
934 setErrorAndEmit(QProcess::FailedToStart);
IOBluetoothL2CAPChannel * channel
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
void resize(qsizetype size)
Sets the size of the byte array to size bytes.
static qint64 applicationPid() Q_DECL_CONST_FUNCTION
qint64 remainingTime() const noexcept
Returns the remaining time in this QDeadlineTimer object in milliseconds.
static QString toNativeSeparators(const QString &pathName)
qsizetype size() const noexcept
const_pointer constData() const noexcept
bool isEmpty() const noexcept
const_reference at(qsizetype i) const noexcept
iterator insert(const Key &key, const T &value)
static QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer< Func1 >::Object *sender, Func1 signal, const typename QtPrivate::FunctionPointer< Func2 >::Object *receiverPrivate, Func2 slot, Qt::ConnectionType type=Qt::AutoConnection)
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
static QProcessEnvironment systemEnvironment()
static Q_DECL_CONST_FUNCTION QRandomGenerator * global()
\threadsafe
\macro QT_RESTRICTED_CAST_FROM_ASCII
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
QString & replace(qsizetype i, qsizetype len, QChar after)
const ushort * utf16() const
Returns the QString as a '\0\'-terminated array of unsigned shorts.
static QString fromLocal8Bit(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=u' ') const
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string ends with s; otherwise returns false.
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
QString & insert(qsizetype i, QChar c)
bool contains(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
static QString fromWCharArray(const wchar_t *string, qsizetype size=-1)
static QString static QString qsizetype indexOf(QChar c, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
QString & prepend(QChar c)
qsizetype length() const
Returns the number of characters in this string.
void bytesWritten(qint64 bytes)
QSet< QString >::iterator it
QList< QVariant > arguments
void qErrnoWarning(const char *msg,...)
Combined button and popup list for selecting options.
Q_CORE_EXPORT QByteArray toPrintable(const char *data, qint64 len, qsizetype maxSize)
static jboolean copy(JNIEnv *, jobject)
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
Q_DECL_COLD_FUNCTION Q_CORE_EXPORT QString qt_error_string(int errorCode=-1)
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLsizei GLsizei GLchar * source
GLdouble GLdouble GLdouble GLdouble q
GLsizei const GLchar *const * path
GLsizei GLenum GLboolean sink
QT_BEGIN_NAMESPACE constexpr UINT KillProcessExitCode
#define PIPE_REJECT_REMOTE_CLIENTS
static void setError(QJsonObject *response, const QString &msg)
#define Q_ASSERT_X(cond, x, msg)
Q_CORE_EXPORT QByteArray qgetenv(const char *varName)
static bool equal(const QChar *a, int l, const char *b)
QDeadlineTimer deadline(30s)