0

我有一个具有“RequestExecutionLevel 用户”的 NSIS 安装程序。该安装程序包含一个具有“RequestExecutionLevel admin”的嵌入式 NSIS 安装程序。此子安装程序仅在某些情况下被调用。这样做是为了让某些管理员操作可以包含在子安装程序中,并且只有在必要时才会提示用户进行 UAC 批准。

我的问题是,我如何调用子安装程序,以便:
a)将提示用户使用 UAC 对话框(如果启用了 UAC),并且
b)如果用户不单击是或否,子安装程序将被终止在给定的时间段内。

我一直在使用 ShellExecWait ( http://nsis.sourceforge.net/ShellExecWait ),它运行良好,但不提供指定超时值的选项(即它将永远等待)。

请注意,我已经尝试过使用以下 NSIS 函数:
* ShellExecWait - 不允许超时
* ExecWait - 子安装程序失败,因为它继承了父安装程序的执行级别。
* ExecShell - 不允许超时
* nsExec::Exec - 子安装程序失败,因为它继承了父安装程序的执行级别。

我在这里变得非常绝望 - 任何帮助将不胜感激。

4

1 回答 1

0

UAC 并不是为了支持这一点而设计的,任何这样做的尝试都应该被视为 hack!

部分问题是您的进程中的 ShellExecuteEx 是提升操作的一部分,因此如果不终止线程或进程就无法终止它。为了解决这个问题,我允许设置充当我们可以杀死的中间人。这种设计的一个缺陷是 UAC 对话框在超时终止进程后仍然存在(UAC GUI 在以系统身份运行的许可.exe 中)这意味着用户可以在主安装程序消失后提升子安装程序!我只在 Win7 上对此进行了测试,如果父级消失了,UAC 不会启动新进程,但这可能是一个错误,或者至少该行为没有记录在 AFAIK 中,并且可能不应该在生产代码中使用!

Outfile "test.exe"
RequestExecutionlevel User

!include LogicLib.nsh
!include WinMessages.nsh
!include FileFunc.nsh

Page Instfiles

!macro ElevateWithTimeout_OnInit
${GetParameters} $0
${GetOptions} $0 '--ExecTimer' $1
${If} $1 != ""
    StrCpy $1 $0 "" 12
    ExecShell 'runas' $1 ;RunAs is not really required as long as the .exe has a manifest that requests elevation...
    Quit
${EndIf}
!macroend
Function ElevateWithTimeout
InitPluginsDir
System::Call '*(&i60,tsr1)i.r0'
StrCpy $1 "--ExecTimer $1"
System::Call '*$0(i 60,i 0x40,i $HwndParent,i0,t"$ExePath",tr1,to,i1)i.r0'
System::Call 'shell32::ShellExecuteEx(ir0)i.r1'
System::Call '*$0(i,i,i,i,i,i,i,i,i,i,i,i,i,i,i.r2)'
System::Free $0
Pop $0 ; Timeout (MS)
${If} $1 <> 0
    System::Call 'kernel32::WaitForSingleObject(ir2,ir0)i.r0'
    ${If} 0x102 = $0 ;WAIT_TIMEOUT
        System::Call 'kernel32::TerminateProcess(ir2,i666)'
    ${EndIf}
    System::Call 'kernel32::CloseHandle(ir2)'
${EndIf}
FunctionEnd

Function .onInit
!insertmacro ElevateWithTimeout_OnInit
FunctionEnd

Section
Push 30000
Push "regedit.exe"
call ElevateWithTimeout
SectionEnd

为了创建一个更安全、更强大的解决方案,子安装程序必须在游戏中并知道如果父项不在,何时中止自己,但是在纯 NSIS 代码中这样做是太多的工作。

我可能会建议您放弃超时要求并RequestExecutionlevel highest在外部安装程序中使用,并且仅在您是管理员()时才运行子程序UserInfo::GetAccountType

于 2013-02-27T17:24:42.687 回答