UAC没有被设计为支持这一点,任何试图做这应该被视为一个黑客!问题的
部分原因是,在的ShellExecuteEx的过程是提升操作的一部分,因此它不能而不杀死线程或进程被杀死。为了解决这个问题,我允许安装程序充当一个可以杀死的中间人。这种设计的一个缺陷是UAC对话框在超时终止进程后仍然存在(UAC GUI处于以system身份运行的consent.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
)的情况下才运行子级。