【问题标题】:How can I ask the user for elevated permissions at runtime?如何在运行时要求用户提升权限?
【发布时间】:2011-08-31 19:39:08
【问题描述】:

一些以普通用户启动的应用程序会在必要时请求提升权限(例如文件管理器需要写入此类文件夹),然后继续操作。

如何复制这种行为?

【问题讨论】:

    标签: c++ windows qt


    【解决方案1】:

    正如 Tamás 指出的那样,您需要启动一个具有更高权限的新流程。过去我搜索了很多,但我没有找到任何方法来提升当前进程的权限。

    假设您的主要应用是 App1.exe,然后您调用需要提升权限的辅助进程 App2.exe。


    A.您可以在 App2.exe 中嵌入清单,但更简单的方法是使用以下内容创建一个名为 App2.exe.manifest 的清单文件 [文本文件],并将其放在与 App2.exe 相同的目录中。 笔记: !!奇怪的是,如果您的应用程序的名称不是 App2.exe 而是 App2_install.exe 或 App2_setup.exe(即如果应用程序名称包含“安装”或“设置”),则 UAC 对话框将在 Windows Vista / Windows 7 中自动出现即使没有清单文件也会要求提升权限! 这是清单文件的示例:

    <?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.您可以在 App1.exe 中使用如下代码来启动 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
    }
    

    ...最后,这是我创建的 Win32 函数 genWin32ShellExecute() 的代码,用于在 Win32 O/S 上使用 QT 时启动进程或打开文档:

    标题:

    #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
    

    【讨论】:

    • 实际上是我在研究后指出的:P。感谢您的详细回答。如果可执行文件名称还包含字符串“update”,它也会触发 UAC。
    • 我编辑了我的答案并将你的名字放在了学分中:-) 我必须感谢你的提问,并给了我发布此代码 sn-p 的动机。我记得我在需要这段代码的时候至少花了 1-2 天,因为 SO 中没有对应的问题。
    • 谢谢,这不是必需的:)。我非常感谢您花时间写下这个详细的答案,即使这个问题已经有一个被接受的答案。
    【解决方案2】:

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

    总结一下:需要启动一个具有提升权限的新进程。运行时无法更改海拔高度。通过 WinAPI 或在可执行文件中嵌入正确的清单来以提升的权限启动。

    【讨论】:

      【解决方案3】:

      简而言之:为 windows 创建两个可执行文件。常规可执行文件和用于执行“提升”操作(通过传递命令行选项)的工作 exe 文件。

      向第二个 EXE 文件添加一个带有 &lt;requestExecutionLevel level="requireAdministrator"/&gt; 节点的应用程序清单文件。

      启动工作应用程序时,请确保使用包装 ShellExecute 的 QT 函数,而不是 CreateProcess,因为 CreateProcess 根本无法启动 requireAdministrator 应用程序,而 ShellExecute(作为 shell 函数)可以执行 UAC 提升提示。

      也可以使用 ActiveX 控件执行此操作,但由于您的目标是 Qt,这似乎不太合适。

      【讨论】:

        【解决方案4】:

        您还可以在提升模式下启动 COM 对象。有关更多信息,请参阅此MSDN article

        【讨论】:

          猜你喜欢
          • 2010-10-09
          • 1970-01-01
          • 2014-07-15
          • 2019-03-23
          • 2016-06-05
          • 2015-01-15
          • 2020-05-21
          • 1970-01-01
          • 2016-09-28
          相关资源
          最近更新 更多