WUIsBack/setup/RunOnce.nsh

270 lines
7.3 KiB
Plaintext

!define IsRunOnce `"" HasFlag "/runonce"`
!define IsPostInstall `"" HasFlag "/postinstall"`
!define NoRestart `"" HasFlag "/norestart"`
!macro PromptReboot
!insertmacro InhibitSleep 0
SetErrorLevel ${ERROR_SUCCESS_REBOOT_REQUIRED}
${If} ${NoRestart}
; Prompt for reboot
${IfNot} ${Silent}
${AndIfNot} ${IsPassive}
System::Call '${RestartDialog}($HWNDPARENT, "", ${EWX_REBOOT})'
${EndIf}
Quit
${Else}
; Reboot immediately
System::Call '${GetUserName}(.r0, ${NSIS_MAX_STRLEN}) .r1'
${If} ${IsRunOnce}
${AndIf} $0 == "SYSTEM"
; Running in setup mode
SetErrorLevel ${ERROR_SUCCESS}
Quit
${Else}
; Regular reboot.
Reboot
${EndIf}
${EndIf}
!macroend
!macro RunOnceOverwriteReg type root subkey name value
ClearErrors
ReadReg${type} $0 ${root} "${subkey}" "${name}"
${IfNot} ${Errors}
WriteReg${type} ${root} "${subkey}" "${name}_LegacyUpdateTemp" $0
${EndIf}
WriteReg${type} ${root} "${subkey}" "${name}" `${value}`
!macroend
!macro RunOnceRestoreReg type root subkey name fallback
ClearErrors
ReadReg${type} $0 ${root} "${subkey}" "${name}_LegacyUpdateTemp"
${If} ${Errors}
!if "${fallback}" == "-"
DeleteRegValue ${root} "${subkey}" "${name}"
!else
WriteReg${type} ${root} "${subkey}" "${name}" `${fallback}`
!endif
${Else}
WriteReg${type} ${root} "${subkey}" "${name}" $0
DeleteRegValue ${root} "${subkey}" "${name}_LegacyUpdateTemp"
${EndIf}
!macroend
Function CleanUpRunOnce
; Restore setup keys
; Be careful here. Doing this wrong can cause SYSTEM_LICENSE_VIOLATION bootloops!
!insertmacro RunOnceRestoreReg Str HKLM "${REGPATH_SETUP}" "CmdLine" ""
!insertmacro RunOnceRestoreReg Dword HKLM "${REGPATH_SETUP}" "SetupType" ${SETUP_TYPE_NORMAL}
DeleteRegValue HKLM "${REGPATH_SETUP}" "SetupShutdownRequired"
${If} ${Abort}
Call CleanUpRunOnceFinal
${EndIf}
FunctionEnd
Function CleanUpRunOnceFinal
; Enable keys we disabled if needed
${If} ${IsWinXP2002}
!insertmacro RunOnceRestoreReg Dword HKLM "${REGPATH_SECURITYCENTER}" "FirstRunDisabled" "-"
${EndIf}
${If} ${AtLeastWin8}
!insertmacro RunOnceRestoreReg Dword HKLM "${REGPATH_POLICIES_SYSTEM}" "EnableFirstLogonAnimation" "-"
${EndIf}
; Delete runonce stuff
RMDir /r /REBOOTOK "${RUNONCEDIR}"
; Delete IE6 temp files
RMDir /r /REBOOTOK "$WINDIR\Windows Update Setup Files"
FunctionEnd
Function CopyLauncher
${If} ${IsNativeAMD64}
File /ONAME=LegacyUpdate.exe "..\launcher\obj\LegacyUpdate64.exe"
${Else}
File /ONAME=LegacyUpdate.exe "..\launcher\obj\LegacyUpdate32.exe"
${EndIf}
FunctionEnd
Var /GLOBAL RunOnce.UseFallback
Function PrepareRunOnce
${If} ${RebootFlag}
${IfNot} ${IsRunOnce}
; Copy to runonce path to ensure installer is accessible by the temp user
CreateDirectory "${RUNONCEDIR}"
SetOutPath "${RUNONCEDIR}"
CopyFiles /SILENT "$EXEPATH" "${RUNONCEDIR}\LegacyUpdateSetup.exe"
Call CopyLauncher
; Remove mark of the web to prevent "Open File - Security Warning" dialog
Delete "${RUNONCEDIR}\LegacyUpdateSetup.exe:Zone.Identifier"
${EndIf}
${If} $RunOnce.UseFallback == 1
WriteRegStr HKLM "${REGPATH_RUNONCE}" "LegacyUpdateRunOnce" '"${RUNONCEDIR}\LegacyUpdateSetup.exe" /runonce'
${Else}
; Somewhat documented in KB939857:
; https://web.archive.org/web/20090723061647/http://support.microsoft.com/kb/939857
; See also Wine winternl.h
!insertmacro RunOnceOverwriteReg Str HKLM "${REGPATH_SETUP}" "CmdLine" '"${RUNONCEDIR}\LegacyUpdate.exe" /runonce'
!insertmacro RunOnceOverwriteReg Dword HKLM "${REGPATH_SETUP}" "SetupType" ${SETUP_TYPE_NOREBOOT}
WriteRegDword HKLM "${REGPATH_SETUP}" "SetupShutdownRequired" ${SETUP_SHUTDOWN_REBOOT}
${EndIf}
; Temporarily disable Security Center first run if needed
${If} ${IsWinXP2002}
${AndIfNot} ${AtLeastServicePack} 2
${VerbosePrint} "Disabling Security Center first run"
!insertmacro RunOnceOverwriteReg Dword HKLM "${REGPATH_SECURITYCENTER}" "FirstRunDisabled" 1
${EndIf}
; Temporarily disable logon animation if needed
${If} ${AtLeastWin8}
${VerbosePrint} "Disabling first logon animation"
!insertmacro RunOnceOverwriteReg Dword HKLM "${REGPATH_POLICIES_SYSTEM}" "EnableFirstLogonAnimation" 0
${EndIf}
${EndIf}
FunctionEnd
Function RebootIfRequired
${MementoSectionSave}
${If} ${RebootFlag}
; Give the user a moment to understand we're rebooting
${DetailPrint} "$(StatusRestarting)"
Sleep 2000
; Now reboot
Call PrepareRunOnce
!insertmacro PromptReboot
${Else}
; Restore setup keys
Call CleanUpRunOnce
${EndIf}
FunctionEnd
Function OnRunOnceLogon
; To be safe in case we crash, immediately restore setup keys. We'll set them again if needed.
Call CleanUpRunOnce
; If we're in the middle of installing a service pack, the system will reboot without notice. Be prepared for that
; to happen.
ClearErrors
EnumRegKey $1 HKLM "${REGPATH_CBS_REBOOTINPROGRESS}" 0
${IfNot} ${Errors}
; System will reboot without notice. Be prepared for that to happen.
${VerbosePrint} "CBS reboot is pending"
Call PrepareRunOnce
${EndIf}
FunctionEnd
!macro SetMarquee state
Push $0
FindWindow $0 "#32770" "" $HWNDPARENT
FindWindow $0 "msctls_progress32" "" $0
!if ${state} == 1
${NSD_AddStyle} $0 ${PBS_MARQUEE}
SendMessage $0 ${PBM_SETMARQUEE} 1 100
!else
${NSD_RemoveStyle} $0 ${PBS_MARQUEE}
!endif
Pop $0
!macroend
Function PollCbsInstall
${IfNot} ${AtLeastWinVista}
Return
${EndIf}
ReadRegDWORD $0 HKLM "${REGPATH_CBS}" "ExecuteState"
${If} $0 == ${CBS_EXECUTE_STATE_NONE}
${OrIf} $0 == ${CBS_EXECUTE_STATE_NONE2}
Return
${EndIf}
${VerbosePrint} "Packages are still installing [$0]"
${DetailPrint} "$(StatusCbsInstalling)"
; Set marquee progress bar
!insertmacro SetMarquee 1
${While} 1 == 1
; Are we in a RebootInProgress phase?
ClearErrors
EnumRegKey $1 HKLM "${REGPATH_CBS_REBOOTINPROGRESS}" 0
${IfNot} ${Errors}
; Spin forever. TrustedInstaller will reboot on its own.
${While} 1 == 1
Sleep 10000
${EndWhile}
${EndIf}
; Poll ExecuteState, waiting for TrustedInstaller to be done.
ReadRegDWORD $0 HKLM "${REGPATH_CBS}" "ExecuteState"
${If} $0 == ${CBS_EXECUTE_STATE_NONE}
${OrIf} $0 == ${CBS_EXECUTE_STATE_NONE2}
${Break}
${EndIf}
Sleep 1000
${EndWhile}
; Revert progress bar
!insertmacro SetMarquee 0
FunctionEnd
Function RebootIfCbsRebootPending
${IfNot} ${AtLeastWinVista}
Return
${EndIf}
StrCpy $1 0
ReadRegDWORD $0 HKLM "${REGPATH_CBS}" "ExecuteState"
${If} $0 != ${CBS_EXECUTE_STATE_NONE}
${AndIf} $0 != ${CBS_EXECUTE_STATE_NONE2}
StrCpy $1 1
${EndIf}
ClearErrors
EnumRegKey $0 HKLM "${REGPATH_CBS_REBOOTPENDING}" 0
${IfNot} ${Errors}
StrCpy $1 1
${EndIf}
EnumRegKey $0 HKLM "${REGPATH_CBS_PACKAGESPENDING}" 0
${IfNot} ${Errors}
StrCpy $1 1
${EndIf}
${If} $1 == 1
${VerbosePrint} "Restarting to install previously pending packages"
SetRebootFlag true
Call RebootIfRequired
${EndIf}
FunctionEnd
Function OnRunOnceDone
${If} ${IsRunOnce}
${AndIfNot} ${Abort}
; Set up postinstall runonce
${VerbosePrint} "Preparing postinstall"
WriteRegStr HKLM "${REGPATH_RUNONCE}" "LegacyUpdatePostInstall" '"${RUNONCEDIR}\LegacyUpdateSetup.exe" /postinstall'
System::Call '${GetUserName}(.r0, ${NSIS_MAX_STRLEN}) .r1'
${If} $0 == "SYSTEM"
; Configure winlogon to proceed to the logon dialog
Call CleanUpRunOnce
; Reboot
${DetailPrint} "$(StatusRestarting)"
Sleep 2000
Reboot
; Just to be sure
Sleep 10000
${EndIf}
${EndIf}
FunctionEnd