开发者

How can I ask the user for elevated permissions at runtime?

Some applications, started with a regular user will ask for elevated permissions when necessary (e.g. a file manager needs to write such folder), and then carry on w开发者_如何学Goith the operation.

How can I replicate this behavior?


As Tamás pointed out you need to launch a new process with elevated rights. I searched a lot in the past but I did not find any way to elevate the rights of the current process.

Lets say your primary app is App1.exe and then you call a secondary process App2.exe which requires elevated rights.


A. You can embed a manifest in your App2.exe but the simpler way is to create a manifest file [a text file] named App2.exe.manifest with the following contents and put it in the same directory as App2.exe. Note: !! Strangely enough, if the name of your application is not App2.exe but App2_install.exe or App2_setup.exe (i.e. if the application name contains the "install" or "setup") an UAC Dialog will appear automatically in Windows Vista / Windows 7 and will ask for elevated rights even there is no manifest file !! This is a sample of the manifest file:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
</assembly>

B. You can use a code like the following in App1.exe to launch the App2.exe

QString AppToExec = qApp->applicationDirPath() + "/App2.exe";
// Put any required parameters of App2.exe to AppParams string
QString AppParams = "";
if (0 != genWin32ShellExecute(AppToExec, 
                              "",    // default verb: "open" or "exec"
                              AppParams,
                              false, // run hidden
                              true)) // wait to finish
{
    // (...) handle error
}

...and finally, this is the code of the Win32 function genWin32ShellExecute() I created to launch a process or open a document when using QT on a Win32 O/S:

Header:

#ifdef Q_OS_WIN  // Implement genWin32ShellExecute() especially for UAC
    #include "qt_windows.h"
    #include "qwindowdefs_win.h"
    #include <shellapi.h>

int genWin32ShellExecute(QString AppFullPath,
                         QString Verb,
                         QString Params,
                         bool ShowAppWindow,
                         bool WaitToFinish);
#endif

CPP:

// Execute/Open the specified Application/Document with the given command
// line Parameters
// (if WaitToFinish == true, wait for the spawn process to finish)
//
// Verb parameter values:
// ""           The degault verb for the associated AppFullPath
// "edit"       Launches an editor and opens the document for editing.
// "find"       Initiates a search starting from the specified directory.
// "open"       Launches an application. If this file is not an executable file, its associated application is launched.
// "print"      Prints the document file.
// "properties" Displays the object's properties.
//
// Ret: 0 = success
//     <0 = error
#ifdef Q_OS_WIN
int genWin32ShellExecute(QString AppFullPath,
                         QString Verb,
                         QString Params,
                         bool ShowAppWindow,
                         bool WaitToFinish)
{
    int Result = 0;

    // Setup the required structure
    SHELLEXECUTEINFO ShExecInfo;
    memset(&ShExecInfo, 0, sizeof(SHELLEXECUTEINFO));
    ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
    ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
    ShExecInfo.hwnd = NULL;
    ShExecInfo.lpVerb = NULL;
    if (Verb.length() > 0)
        ShExecInfo.lpVerb = reinterpret_cast<const WCHAR *>(Verb.utf16());
    ShExecInfo.lpFile = NULL;
    if (AppFullPath.length() > 0)
        ShExecInfo.lpFile = reinterpret_cast<const WCHAR *>(AppFullPath.utf16());
    ShExecInfo.lpParameters = NULL;
    if (Params.length() > 0)
        ShExecInfo.lpParameters = reinterpret_cast<const WCHAR *>(Params.utf16());
    ShExecInfo.lpDirectory = NULL;
    ShExecInfo.nShow = (ShowAppWindow ? SW_SHOW : SW_HIDE);
    ShExecInfo.hInstApp = NULL;

    // Spawn the process
    if (ShellExecuteEx(&ShExecInfo) == FALSE)
    {
        Result = -1; // Failed to execute process
    } else if (WaitToFinish)
    {
        WaitForSingleObject(ShExecInfo.hProcess, INFINITE);
    }

    return Result;
}
#endif


See this question on elevating privileges only when required in C# and this article on User Account Control

To sum it up: one needs to launch a new process with elevated permissions. The elevation level cannot be changed at runtime. Launching with elevated permissions is done either via WinAPI or embedding a correct manifest in the executable.


In a nutshell: Create two executable files for windows. The regular executable, and a worker exe file that you use to perform "elevated" operations (by passing command line options).

To the second EXE file you add an application manifest file with a <requestExecutionLevel level="requireAdministrator"/> node.

When launching the worker app, make sure to use the QT function that wraps ShellExecute, NOT CreateProcess as CreateProcess simply fails to launch requireAdministrator apps, whereas ShellExecute (Being a shell function) can perform the UAC elevation prompt.

It is also possible to do this with ActiveX controls, but as you are targeting Qt that seems less appropriate.


You can also launch a COM object in an elevated mode. See this MSDN article for more information.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜