summaryrefslogtreecommitdiffstats
path: root/src/corelib/io
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@theqtcompany.com>2016-04-05 11:26:20 +0200
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2016-04-23 06:12:24 +0000
commitab83912c7900805987f7efe38cee2c60baf5f315 (patch)
treee44b7aa9dd0be3c55416de8312e21c9aea680ae7 /src/corelib/io
parent759b3f49c52c69f0a3ea2df014afbd3259e2bb83 (diff)
Windows/QProcess::startDetached(): Fall back to ShellExecuteEx() for UAC prompt.
When running a process that requires elevated privileges (such as regedt32 or an installer), the Win32 API CreateProcess fails with error ERROR_ELEVATION_REQUIRED. Fall back to ShellExecuteEx() using the verb "runas" in that case, bringing up the UAC prompt. Task-number: QTBUG-7645 Change-Id: Iee82a86a30f78c5a49246d2c0d4566306f3afc71 Reviewed-by: Oliver Wolff <oliver.wolff@qt.io> Reviewed-by: Joerg Bornemann <joerg.bornemann@theqtcompany.com>
Diffstat (limited to 'src/corelib/io')
-rw-r--r--src/corelib/io/qprocess_win.cpp40
1 files changed, 40 insertions, 0 deletions
diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp
index e7cd9d9a17..7e9cffe129 100644
--- a/src/corelib/io/qprocess_win.cpp
+++ b/src/corelib/io/qprocess_win.cpp
@@ -42,6 +42,7 @@
#include <qfileinfo.h>
#include <qregexp.h>
#include <qwineventnotifier.h>
+#include <private/qsystemlibrary_p.h>
#include <private/qthread_p.h>
#include <qdebug.h>
@@ -808,8 +809,45 @@ bool QProcessPrivate::waitForWrite(int msecs)
return false;
}
+// Use ShellExecuteEx() to trigger an UAC prompt when CreateProcess()fails
+// with ERROR_ELEVATION_REQUIRED.
+static bool startDetachedUacPrompt(const QString &programIn, const QStringList &arguments,
+ const QString &workingDir, qint64 *pid)
+{
+ typedef BOOL (WINAPI *ShellExecuteExType)(SHELLEXECUTEINFOW *);
+
+ static const ShellExecuteExType shellExecuteEx = // XP ServicePack 1 onwards.
+ reinterpret_cast<ShellExecuteExType>(QSystemLibrary::resolve(QLatin1String("shell32"),
+ "ShellExecuteExW"));
+ if (!shellExecuteEx)
+ return false;
+
+ const QString args = qt_create_commandline(QString(), arguments); // needs arguments only
+ SHELLEXECUTEINFOW shellExecuteExInfo;
+ memset(&shellExecuteExInfo, 0, sizeof(SHELLEXECUTEINFOW));
+ shellExecuteExInfo.cbSize = sizeof(SHELLEXECUTEINFOW);
+ shellExecuteExInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_UNICODE | SEE_MASK_FLAG_NO_UI;
+ shellExecuteExInfo.lpVerb = L"runas";
+ const QString program = QDir::toNativeSeparators(programIn);
+ shellExecuteExInfo.lpFile = reinterpret_cast<LPCWSTR>(program.utf16());
+ if (!args.isEmpty())
+ shellExecuteExInfo.lpParameters = reinterpret_cast<LPCWSTR>(args.utf16());
+ if (!workingDir.isEmpty())
+ shellExecuteExInfo.lpDirectory = reinterpret_cast<LPCWSTR>(workingDir.utf16());
+ shellExecuteExInfo.nShow = SW_SHOWNORMAL;
+
+ if (!shellExecuteEx(&shellExecuteExInfo))
+ return false;
+ if (pid)
+ *pid = qint64(GetProcessId(shellExecuteExInfo.hProcess));
+ CloseHandle(shellExecuteExInfo.hProcess);
+ return true;
+}
+
bool QProcessPrivate::startDetached(const QString &program, const QStringList &arguments, const QString &workingDir, qint64 *pid)
{
+ static const DWORD errorElevationRequired = 740;
+
QString args = qt_create_commandline(program, arguments);
bool success = false;
PROCESS_INFORMATION pinfo;
@@ -829,6 +867,8 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a
CloseHandle(pinfo.hProcess);
if (pid)
*pid = pinfo.dwProcessId;
+ } else if (GetLastError() == errorElevationRequired) {
+ success = startDetachedUacPrompt(program, arguments, workingDir, pid);
}
return success;