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>
This commit is contained in:
parent
759b3f49c5
commit
ab83912c79
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user