8#include <private/qdebug_p.h>
19#include <qwineventnotifier.h>
20#include <qscopedvaluerollback.h>
21#include <private/qsystemlibrary_p.h>
22#include <private/qthread_p.h>
24#include "private/qfsfileengine_p.h"
26#ifndef PIPE_REJECT_REMOTE_CLIENTS
27#define PIPE_REJECT_REMOTE_CLIENTS 0x08
34using namespace Qt::StringLiterals;
36QProcessEnvironment QProcessEnvironment::systemEnvironment()
38 QProcessEnvironment env;
41 if (
wchar_t *envStrings = GetEnvironmentStringsW()) {
42 for (
const wchar_t *entry = envStrings; *entry; ) {
43 const int entryLen =
int(wcslen(entry));
45 if (
const wchar_t *equal = wcschr(entry + 1, L'=')) {
46 int nameLen = equal - entry;
47 QString name = QString::fromWCharArray(entry, nameLen);
48 QString value = QString::fromWCharArray(equal + 1, entryLen - nameLen - 1);
49 env.d->vars.insert(QProcessEnvironmentPrivate::Key(name), value);
51 entry += entryLen + 1;
53 FreeEnvironmentStringsW(envStrings);
63 QProcessPoller(
const QProcessPrivate &proc);
65 int poll(
const QDeadlineTimer &deadline);
67 enum { maxHandles = 4 };
68 HANDLE handles[maxHandles];
69 DWORD handleCount = 0;
72QProcessPoller::QProcessPoller(
const QProcessPrivate &proc)
74 if (proc.stdinChannel.writer)
75 handles[handleCount++] = proc.stdinChannel.writer->syncEvent();
76 if (proc.stdoutChannel.reader)
77 handles[handleCount++] = proc.stdoutChannel.reader->syncEvent();
78 if (proc.stderrChannel.reader)
79 handles[handleCount++] = proc.stderrChannel.reader->syncEvent();
81 handles[handleCount++] = proc.pid->hProcess;
84int QProcessPoller::poll(
const QDeadlineTimer &deadline)
89 waitRet = WaitForMultipleObjectsEx(handleCount, handles, FALSE,
90 deadline.remainingTime(), TRUE);
91 }
while (waitRet == WAIT_IO_COMPLETION);
93 if (waitRet - WAIT_OBJECT_0 < handleCount)
96 return (waitRet == WAIT_TIMEOUT) ? 0 : -1;
100static bool qt_create_pipe(Q_PIPE *pipe,
bool isInputPipe, BOOL defInheritFlag)
109 SECURITY_ATTRIBUTES secAtt = {
sizeof(SECURITY_ATTRIBUTES), 0, defInheritFlag };
112 wchar_t pipeName[256];
113 unsigned int attempts = 1000;
115 _snwprintf(pipeName,
sizeof(pipeName) /
sizeof(pipeName[0]),
116 L"\\\\.\\pipe\\qt-%lX-%X",
long(QCoreApplication::applicationPid()),
117 QRandomGenerator::global()->generate());
119 DWORD dwOpenMode = FILE_FLAG_OVERLAPPED;
120 DWORD dwOutputBufferSize = 0;
121 DWORD dwInputBufferSize = 0;
122 const DWORD dwPipeBufferSize = 1024 * 1024;
124 dwOpenMode |= PIPE_ACCESS_OUTBOUND;
125 dwOutputBufferSize = dwPipeBufferSize;
127 dwOpenMode |= PIPE_ACCESS_INBOUND;
128 dwInputBufferSize = dwPipeBufferSize;
130 DWORD dwPipeFlags = PIPE_TYPE_BYTE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS;
131 hServer = CreateNamedPipe(pipeName,
139 if (hServer != INVALID_HANDLE_VALUE)
141 DWORD dwError = GetLastError();
142 if (dwError != ERROR_PIPE_BUSY || !--attempts) {
143 qErrnoWarning(dwError,
"QProcess: CreateNamedPipe failed.");
144 SetLastError(dwError);
149 secAtt.bInheritHandle = TRUE;
150 const HANDLE hClient = CreateFile(pipeName,
151 (isInputPipe ? (GENERIC_READ | FILE_WRITE_ATTRIBUTES)
156 FILE_FLAG_OVERLAPPED,
158 if (hClient == INVALID_HANDLE_VALUE) {
159 DWORD dwError = GetLastError();
160 qErrnoWarning(
"QProcess: CreateFile failed.");
161 CloseHandle(hServer);
162 SetLastError(dwError);
167 OVERLAPPED overlapped;
168 ZeroMemory(&overlapped,
sizeof(overlapped));
169 overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
170 if (ConnectNamedPipe(hServer, &overlapped) == 0) {
171 DWORD dwError = GetLastError();
173 case ERROR_PIPE_CONNECTED:
175 case ERROR_IO_PENDING:
176 WaitForSingleObject(overlapped.hEvent, INFINITE);
179 dwError = GetLastError();
180 qErrnoWarning(dwError,
"QProcess: ConnectNamedPipe failed.");
181 CloseHandle(overlapped.hEvent);
182 CloseHandle(hClient);
183 CloseHandle(hServer);
184 SetLastError(dwError);
188 CloseHandle(overlapped.hEvent);
201
202
203bool QProcessPrivate::openChannel(Channel &channel)
207 switch (channel.type) {
208 case Channel::Normal: {
210 if (&channel == &stdinChannel) {
211 if (!qt_create_pipe(channel.pipe,
true, FALSE)) {
212 setErrorAndEmit(QProcess::FailedToStart,
"pipe: "_L1 + qt_error_string(errno));
219 if (!channel.reader) {
220 auto receiver = &channel == &stdoutChannel ? &QProcessPrivate::_q_canReadStandardOutput
221 : &QProcessPrivate::_q_canReadStandardError;
222 channel.reader =
new QWindowsPipeReader(q);
223 QObjectPrivate::connect(channel.reader, &QWindowsPipeReader::readyRead,
226 if (!qt_create_pipe(channel.pipe,
false, FALSE)) {
227 setErrorAndEmit(QProcess::FailedToStart,
"pipe: "_L1 + qt_error_string(errno));
231 channel.reader->setHandle(channel.pipe[0]);
232 channel.reader->startAsyncRead();
235 case Channel::Redirect: {
237 SECURITY_ATTRIBUTES secAtt = {
sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
239 if (&channel == &stdinChannel) {
241 channel.pipe[1] = INVALID_Q_PIPE;
243 CreateFile((
const wchar_t*)QFSFileEnginePrivate::longFileName(channel.file).utf16(),
245 FILE_SHARE_READ | FILE_SHARE_WRITE,
248 FILE_ATTRIBUTE_NORMAL,
251 if (channel.pipe[0] != INVALID_Q_PIPE)
254 setErrorAndEmit(QProcess::FailedToStart,
255 QProcess::tr(
"Could not open input redirection for reading"));
258 channel.pipe[0] = INVALID_Q_PIPE;
260 CreateFile((
const wchar_t *)QFSFileEnginePrivate::longFileName(channel.file).utf16(),
262 FILE_SHARE_READ | FILE_SHARE_WRITE,
264 channel.append ? OPEN_ALWAYS : CREATE_ALWAYS,
265 FILE_ATTRIBUTE_NORMAL,
268 if (channel.pipe[1] != INVALID_Q_PIPE) {
269 if (channel.append) {
270 SetFilePointer(channel.pipe[1], 0, NULL, FILE_END);
275 setErrorAndEmit(QProcess::FailedToStart,
276 QProcess::tr(
"Could not open output redirection for writing"));
280 case Channel::PipeSource: {
281 Q_ASSERT_X(channel.process,
"QProcess::start",
"Internal error");
283 Channel *source = &channel;
284 Channel *sink = &channel.process->stdinChannel;
286 if (source->pipe[1] != INVALID_Q_PIPE) {
291 Q_ASSERT(source == &stdoutChannel);
292 Q_ASSERT(sink->process ==
this && sink->type == Channel::PipeSink);
294 if (!qt_create_pipe(source->pipe,
false, TRUE)) {
295 setErrorAndEmit(QProcess::FailedToStart,
"pipe: "_L1 + qt_error_string(errno));
299 sink->pipe[0] = source->pipe[0];
300 source->pipe[0] = INVALID_Q_PIPE;
304 case Channel::PipeSink: {
305 Q_ASSERT_X(channel.process,
"QProcess::start",
"Internal error");
306 Channel *source = &channel.process->stdoutChannel;
307 Channel *sink = &channel;
309 if (sink->pipe[0] != INVALID_Q_PIPE) {
313 Q_ASSERT(sink == &stdinChannel);
314 Q_ASSERT(source->process ==
this && source->type == Channel::PipeSource);
316 if (!qt_create_pipe(sink->pipe,
true, TRUE)) {
317 setErrorAndEmit(QProcess::FailedToStart,
"pipe: "_L1 + qt_error_string(errno));
321 source->pipe[1] = sink->pipe[1];
322 sink->pipe[1] = INVALID_Q_PIPE;
330void QProcessPrivate::destroyPipe(Q_PIPE pipe[2])
332 if (pipe[0] != INVALID_Q_PIPE) {
333 CloseHandle(pipe[0]);
334 pipe[0] = INVALID_Q_PIPE;
336 if (pipe[1] != INVALID_Q_PIPE) {
337 CloseHandle(pipe[1]);
338 pipe[1] = INVALID_Q_PIPE;
342void QProcessPrivate::closeChannel(Channel *channel)
344 if (channel == &stdinChannel) {
345 delete channel->writer;
346 channel->writer =
nullptr;
348 delete channel->reader;
349 channel->reader =
nullptr;
351 destroyPipe(channel->pipe);
354void QProcessPrivate::cleanup()
356 q_func()->setProcessState(QProcess::NotRunning);
359 delete processFinishedNotifier;
360 processFinishedNotifier =
nullptr;
362 CloseHandle(pid->hThread);
363 CloseHandle(pid->hProcess);
369static QString qt_create_commandline(
const QString &program,
const QStringList &arguments,
370 const QString &nativeArguments)
373 if (!program.isEmpty()) {
374 QString programName = program;
375 if (!programName.startsWith(u'\"') && !programName.endsWith(u'\"') && programName.contains(u' '))
376 programName = u'\"' + programName + u'\"';
377 programName.replace(u'/', u'\\');
380 args = programName + u' ';
383 for (qsizetype i = 0; i < arguments.size(); ++i) {
384 QString tmp = arguments.at(i);
386 qsizetype index = tmp.indexOf(u'"');
389 tmp.insert(index++, u'\\');
391 for (qsizetype i = index - 2 ; i >= 0 && tmp.at(i) == u'\\' ; --i) {
392 tmp.insert(i, u'\\');
395 index = tmp.indexOf(u'"', index + 1);
397 if (tmp.isEmpty() || tmp.contains(u' ') || tmp.contains(u'\t')) {
401 qsizetype i = tmp.length();
402 while (i > 0 && tmp.at(i - 1) == u'\\')
410 if (!nativeArguments.isEmpty()) {
413 args += nativeArguments;
419static QByteArray qt_create_environment(
const QProcessEnvironmentPrivate::Map &environment)
422 QProcessEnvironmentPrivate::Map copy = environment;
425 QProcessEnvironmentPrivate::Key pathKey(
"PATH"_L1);
426 if (!copy.contains(pathKey)) {
427 QByteArray path = qgetenv(
"PATH");
429 copy.insert(pathKey, QString::fromLocal8Bit(path));
433 QProcessEnvironmentPrivate::Key rootKey(
"SystemRoot"_L1);
434 if (!copy.contains(rootKey)) {
435 QByteArray systemRoot = qgetenv(
"SystemRoot");
436 if (!systemRoot.isEmpty())
437 copy.insert(rootKey, QString::fromLocal8Bit(systemRoot));
441 auto it = copy.constBegin();
442 const auto end = copy.constEnd();
444 static const wchar_t equal = L'=';
445 static const wchar_t nul = L'\0';
447 for (; it != end; ++it) {
448 qsizetype tmpSize =
sizeof(
wchar_t) * (it.key().length() + it.value().length() + 2);
450 if (tmpSize ==
sizeof(
wchar_t) * 2)
452 envlist.resize(envlist.size() + tmpSize);
454 tmpSize = it.key().length() *
sizeof(
wchar_t);
455 memcpy(envlist.data() + pos, it.key().data(), tmpSize);
458 memcpy(envlist.data() + pos, &equal,
sizeof(
wchar_t));
459 pos +=
sizeof(
wchar_t);
461 tmpSize = it.value().length() *
sizeof(
wchar_t);
462 memcpy(envlist.data() + pos, it.value().data(), tmpSize);
465 memcpy(envlist.data() + pos, &nul,
sizeof(
wchar_t));
466 pos +=
sizeof(
wchar_t);
469 envlist.resize(envlist.size() + 4);
478static Q_PIPE pipeOrStdHandle(Q_PIPE pipe, DWORD handleNumber)
480 return pipe != INVALID_Q_PIPE ? pipe : GetStdHandle(handleNumber);
483STARTUPINFOW QProcessPrivate::createStartupInfo()
485 Q_PIPE stdinPipe = pipeOrStdHandle(stdinChannel.pipe[0], STD_INPUT_HANDLE);
486 Q_PIPE stdoutPipe = pipeOrStdHandle(stdoutChannel.pipe[1], STD_OUTPUT_HANDLE);
487 Q_PIPE stderrPipe = stderrChannel.pipe[1];
488 if (stderrPipe == INVALID_Q_PIPE) {
489 stderrPipe = (processChannelMode == QProcess::MergedChannels)
491 : GetStdHandle(STD_ERROR_HANDLE);
495 sizeof(STARTUPINFOW), 0, 0, 0,
496 (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
497 (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
499 STARTF_USESTDHANDLES,
501 stdinPipe, stdoutPipe, stderrPipe
505bool QProcessPrivate::callCreateProcess(QProcess::CreateProcessArguments *cpargs)
507 if (modifyCreateProcessArgs)
508 modifyCreateProcessArgs(cpargs);
509 bool success = CreateProcess(cpargs->applicationName, cpargs->arguments,
510 cpargs->processAttributes, cpargs->threadAttributes,
511 cpargs->inheritHandles, cpargs->flags, cpargs->environment,
512 cpargs->currentDirectory, cpargs->startupInfo,
513 cpargs->processInformation);
520 if (stdinChannel.pipe[0] != INVALID_Q_PIPE) {
521 CloseHandle(stdinChannel.pipe[0]);
522 stdinChannel.pipe[0] = INVALID_Q_PIPE;
524 if (stdoutChannel.pipe[1] != INVALID_Q_PIPE) {
525 CloseHandle(stdoutChannel.pipe[1]);
526 stdoutChannel.pipe[1] = INVALID_Q_PIPE;
528 if (stderrChannel.pipe[1] != INVALID_Q_PIPE) {
529 CloseHandle(stderrChannel.pipe[1]);
530 stderrChannel.pipe[1] = INVALID_Q_PIPE;
535void QProcessPrivate::startProcess()
539 pid =
new PROCESS_INFORMATION;
540 memset(pid, 0,
sizeof(PROCESS_INFORMATION));
542 q->setProcessState(QProcess::Starting);
544 if (!openChannels()) {
546 Q_ASSERT(!errorString.isEmpty());
551 QString args = qt_create_commandline(program, arguments, nativeArguments);
553 if (!environment.inheritsFromParent())
554 envlist = qt_create_environment(environment.d.constData()->vars);
556#if defined QPROCESS_DEBUG
557 qDebug(
"Creating process");
558 qDebug(
" program : [%s]", program.toLatin1().constData());
559 qDebug(
" args : %s", args.toLatin1().constData());
560 qDebug(
" pass environment : %s", environment.isEmpty() ?
"no" :
"yes");
568 DWORD dwCreationFlags = (GetConsoleWindow() ? 0 : CREATE_NO_WINDOW);
569 dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
570 STARTUPINFOW startupInfo = createStartupInfo();
571 const QString nativeWorkingDirectory = QDir::toNativeSeparators(workingDirectory);
572 QProcess::CreateProcessArguments cpargs = {
573 nullptr,
reinterpret_cast<
wchar_t *>(args.data_ptr().data()),
574 nullptr,
nullptr,
true, dwCreationFlags,
575 environment.inheritsFromParent() ?
nullptr : envlist.data(),
576 nativeWorkingDirectory.isEmpty()
577 ?
nullptr :
reinterpret_cast<
const wchar_t *>(nativeWorkingDirectory.utf16()),
581 if (!callCreateProcess(&cpargs)) {
583 QString errorString = qt_error_string();
585 setErrorAndEmit(QProcess::FailedToStart,
586 QProcess::tr(
"Process failed to start: %1").arg(errorString));
593 if (stdinChannel.writer)
594 stdinChannel.writer->setHandle(stdinChannel.pipe[1]);
596 q->setProcessState(QProcess::Running);
602 if (threadData.loadRelaxed()->hasEventDispatcher()) {
603 processFinishedNotifier =
new QWinEventNotifier(pid->hProcess, q);
604 QObjectPrivate::connect(processFinishedNotifier, &QWinEventNotifier::activated,
this,
605 &QProcessPrivate::_q_processDied);
607 processFinishedNotifier->setEnabled(
true);
610 _q_startupNotification();
613bool QProcessPrivate::processStarted(QString * )
615 return processState == QProcess::Running;
618qint64 QProcessPrivate::bytesAvailableInChannel(
const Channel *channel)
const
620 Q_ASSERT(channel->pipe[0] != INVALID_Q_PIPE);
621 Q_ASSERT(channel->reader);
623 DWORD bytesAvail = channel->reader->bytesAvailable();
624#if defined QPROCESS_DEBUG
625 qDebug(
"QProcessPrivate::bytesAvailableInChannel(%d) == %lld",
626 int(channel - &stdinChannel), qint64(bytesAvail));
631qint64 QProcessPrivate::readFromChannel(
const Channel *channel,
char *data, qint64 maxlen)
633 Q_ASSERT(channel->pipe[0] != INVALID_Q_PIPE);
634 Q_ASSERT(channel->reader);
635 return channel->reader->read(data, maxlen);
638static BOOL QT_WIN_CALLBACK qt_terminateApp(HWND hwnd, LPARAM procId)
640 DWORD currentProcId = 0;
641 GetWindowThreadProcessId(hwnd, ¤tProcId);
642 if (currentProcId == (DWORD)procId)
643 PostMessage(hwnd, WM_CLOSE, 0, 0);
648void QProcessPrivate::terminateProcess()
651 EnumWindows(qt_terminateApp, (LPARAM)pid->dwProcessId);
652 PostThreadMessage(pid->dwThreadId, WM_CLOSE, 0, 0);
656void QProcessPrivate::killProcess()
659 TerminateProcess(pid->hProcess, KillProcessExitCode);
662bool QProcessPrivate::waitForStarted(
const QDeadlineTimer &)
664 if (processStarted())
667 if (processError == QProcess::FailedToStart)
670 setError(QProcess::Timedout);
674bool QProcessPrivate::drainOutputPipes()
676 bool readyReadEmitted =
false;
678 if (stdoutChannel.reader) {
679 stdoutChannel.reader->drainAndStop();
680 readyReadEmitted = _q_canReadStandardOutput();
682 if (stderrChannel.reader) {
683 stderrChannel.reader->drainAndStop();
684 readyReadEmitted |= _q_canReadStandardError();
687 return readyReadEmitted;
690bool QProcessPrivate::waitForReadyRead(
const QDeadlineTimer &deadline)
693 QProcessPoller poller(*
this);
694 int ret = poller.poll(deadline);
700 if (stdinChannel.writer)
701 stdinChannel.writer->checkForWrite();
703 if ((stdoutChannel.reader && stdoutChannel.reader->checkForReadyRead())
704 || (stderrChannel.reader && stderrChannel.reader->checkForReadyRead()))
710 if (WaitForSingleObject(pid->hProcess, 0) == WAIT_OBJECT_0) {
711 bool readyReadEmitted = drainOutputPipes();
714 return readyReadEmitted;
718 setError(QProcess::Timedout);
722bool QProcessPrivate::waitForBytesWritten(
const QDeadlineTimer &deadline)
729 if (!stdinChannel.writer || !stdinChannel.writer->isWriteOperationActive())
732 QProcessPoller poller(*
this);
733 int ret = poller.poll(deadline);
739 if (stdinChannel.writer->checkForWrite())
743 if (stdoutChannel.reader)
744 stdoutChannel.reader->checkForReadyRead();
747 if (stderrChannel.reader)
748 stderrChannel.reader->checkForReadyRead();
755 if (WaitForSingleObject(pid->hProcess, 0) == WAIT_OBJECT_0) {
763 setError(QProcess::Timedout);
767bool QProcessPrivate::waitForFinished(
const QDeadlineTimer &deadline)
769#if defined QPROCESS_DEBUG
770 qDebug(
"QProcessPrivate::waitForFinished(%lld)", deadline.remainingTime());
774 QProcessPoller poller(*
this);
775 int ret = poller.poll(deadline);
781 if (stdinChannel.writer)
782 stdinChannel.writer->checkForWrite();
783 if (stdoutChannel.reader)
784 stdoutChannel.reader->checkForReadyRead();
785 if (stderrChannel.reader)
786 stderrChannel.reader->checkForReadyRead();
791 if (WaitForSingleObject(pid->hProcess, 0) == WAIT_OBJECT_0) {
799 setError(QProcess::Timedout);
803void QProcessPrivate::findExitCode()
807 if (GetExitCodeProcess(pid->hProcess, &theExitCode)) {
808 exitCode = theExitCode;
809 if (exitCode == KillProcessExitCode
810 || (theExitCode >= 0x80000000 && theExitCode < 0xD0000000))
811 exitStatus = QProcess::CrashExit;
813 exitStatus = QProcess::NormalExit;
818
819
820qint64 QProcess::writeData(
const char *data, qint64 len)
824 if (d->stdinChannel.closed) {
825#if defined QPROCESS_DEBUG
826 qDebug(
"QProcess::writeData(%p \"%s\", %lld) == 0 (write channel closing)",
827 data, QtDebugUtils::toPrintable(data, len, 16).constData(), len);
832 if (!d->stdinChannel.writer) {
833 d->stdinChannel.writer =
new QWindowsPipeWriter(d->stdinChannel.pipe[1],
this);
834 QObjectPrivate::connect(d->stdinChannel.writer, &QWindowsPipeWriter::bytesWritten,
835 d, &QProcessPrivate::_q_bytesWritten);
836 QObjectPrivate::connect(d->stdinChannel.writer, &QWindowsPipeWriter::writeFailed,
837 d, &QProcessPrivate::_q_writeFailed);
840 if (d->isWriteChunkCached(data, len))
841 d->stdinChannel.writer->write(*(d->currentWriteChunk));
843 d->stdinChannel.writer->write(data, len);
845#if defined QPROCESS_DEBUG
846 qDebug(
"QProcess::writeData(%p \"%s\", %lld) == %lld (written to buffer)",
847 data, QtDebugUtils::toPrintable(data, len, 16).constData(), len, len);
852qint64 QProcessPrivate::pipeWriterBytesToWrite()
const
854 return stdinChannel.writer ? stdinChannel.writer->bytesToWrite() : qint64(0);
857void QProcessPrivate::_q_bytesWritten(qint64 bytes)
861 if (!emittedBytesWritten) {
862 QScopedValueRollback<
bool> guard(emittedBytesWritten,
true);
863 emit q->bytesWritten(bytes);
865 if (stdinChannel.closed && pipeWriterBytesToWrite() == 0)
869void QProcessPrivate::_q_writeFailed()
872 setErrorAndEmit(QProcess::WriteError);
877static bool startDetachedUacPrompt(
const QString &programIn,
const QStringList &arguments,
878 const QString &nativeArguments,
879 const QString &workingDir, qint64 *pid)
881 const QString args = qt_create_commandline(QString(),
882 arguments, nativeArguments);
883 SHELLEXECUTEINFOW shellExecuteExInfo;
884 memset(&shellExecuteExInfo, 0,
sizeof(SHELLEXECUTEINFOW));
885 shellExecuteExInfo.cbSize =
sizeof(SHELLEXECUTEINFOW);
886 shellExecuteExInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_UNICODE | SEE_MASK_FLAG_NO_UI | SEE_MASK_CLASSNAME;
887 shellExecuteExInfo.lpClass = L"exefile";
888 shellExecuteExInfo.lpVerb = L"runas";
889 const QString program = QDir::toNativeSeparators(programIn);
890 shellExecuteExInfo.lpFile =
reinterpret_cast<LPCWSTR>(program.utf16());
892 shellExecuteExInfo.lpParameters =
reinterpret_cast<LPCWSTR>(args.utf16());
893 if (!workingDir.isEmpty())
894 shellExecuteExInfo.lpDirectory =
reinterpret_cast<LPCWSTR>(workingDir.utf16());
895 shellExecuteExInfo.nShow = SW_SHOWNORMAL;
897 if (!ShellExecuteExW(&shellExecuteExInfo))
900 *pid = qint64(GetProcessId(shellExecuteExInfo.hProcess));
901 CloseHandle(shellExecuteExInfo.hProcess);
905bool QProcessPrivate::startDetached(qint64 *pid)
907 static const DWORD errorElevationRequired = 740;
909 if (!openChannelsForDetached()) {
915 QString args = qt_create_commandline(program, arguments, nativeArguments);
916 bool success =
false;
917 PROCESS_INFORMATION pinfo;
919 void *envPtr =
nullptr;
921 if (!environment.inheritsFromParent()) {
922 envlist = qt_create_environment(environment.d.constData()->vars);
923 envPtr = envlist.data();
926 DWORD dwCreationFlags = (GetConsoleWindow() ? 0 : CREATE_NO_WINDOW);
927 dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
928 STARTUPINFOW startupInfo = createStartupInfo();
929 QProcess::CreateProcessArguments cpargs = {
930 nullptr,
reinterpret_cast<
wchar_t *>(args.data_ptr().data()),
931 nullptr,
nullptr,
true, dwCreationFlags, envPtr,
932 workingDirectory.isEmpty()
933 ?
nullptr :
reinterpret_cast<
const wchar_t *>(workingDirectory.utf16()),
936 success = callCreateProcess(&cpargs);
939 CloseHandle(pinfo.hThread);
940 CloseHandle(pinfo.hProcess);
942 *pid = pinfo.dwProcessId;
943 }
else if (GetLastError() == errorElevationRequired) {
945 qWarning(
"QProcess: custom environment will be ignored for detached elevated process.");
946 if (!stdinChannel.file.isEmpty() || !stdoutChannel.file.isEmpty()
947 || !stderrChannel.file.isEmpty()) {
948 qWarning(
"QProcess: file redirection is unsupported for detached elevated processes.");
950 success = startDetachedUacPrompt(program, arguments, nativeArguments,
951 workingDirectory, pid);
956 QString errorString = qt_error_string();
957 setErrorAndEmit(QProcess::FailedToStart,
958 QProcess::tr(
"Process failed to start: %1").arg(errorString));
QT_BEGIN_NAMESPACE constexpr UINT KillProcessExitCode