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
)的情況下才運行子級。