| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343 |
- program Setup;
- {
- Inno Setup
- Copyright (C) 1997-2025 Jordan Russell
- Portions by Martijn Laan
- For conditions of distribution and use, see LICENSE.TXT.
- Setup program
- }
- uses
- SafeDLLPath in '..\Components\SafeDLLPath.pas',
- SetupLdrAndSetup.XPTheme in 'Src\SetupLdrAndSetup.XPTheme.pas',
- Forms,
- Windows,
- SysUtils,
- Messages,
- RichEditViewer in '..\Components\RichEditViewer.pas',
- Shared.CommonFunc.Vcl in 'Src\Shared.CommonFunc.Vcl.pas',
- Shared.CommonFunc in 'Src\Shared.CommonFunc.pas',
- Setup.MainForm in 'Src\Setup.MainForm.pas',
- Setup.MainFunc in 'Src\Setup.MainFunc.pas',
- Setup.Install in 'Src\Setup.Install.pas',
- SetupLdrAndSetup.Messages in 'Src\SetupLdrAndSetup.Messages.pas',
- Shared.SetupMessageIDs in 'Src\Shared.SetupMessageIDs.pas',
- Setup.UninstallLog in 'Src\Setup.UninstallLog.pas',
- Shared.Struct in 'Src\Shared.Struct.pas',
- Setup.NewDiskForm in 'Src\Setup.NewDiskForm.pas' {NewDiskForm},
- SetupLdrAndSetup.InstFunc in 'Src\SetupLdrAndSetup.InstFunc.pas',
- Setup.InstFunc in 'Src\Setup.InstFunc.pas',
- Setup.InstFunc.Ole in 'Src\Setup.InstFunc.Ole.pas',
- Setup.WizardForm in 'Src\Setup.WizardForm.pas' {WizardForm},
- Setup.ScriptFunc in 'Src\Setup.ScriptFunc.pas',
- Shared.ScriptFunc in 'Src\Shared.ScriptFunc.pas',
- Shared.SetupTypes in 'Src\Shared.SetupTypes.pas',
- Shared.SetupSteps in 'Src\Shared.SetupSteps.pas',
- Setup.ScriptRunner in 'Src\Setup.ScriptRunner.pas',
- Setup.ScriptDlg in 'Src\Setup.ScriptDlg.pas',
- Setup.ScriptClasses in 'Src\Setup.ScriptClasses.pas',
- Setup.SelectLanguageForm in 'Src\Setup.SelectLanguageForm.pas' {SelectLanguageForm},
- Setup.FileExtractor in 'Src\Setup.FileExtractor.pas',
- Shared.Int64Em in 'Src\Shared.Int64Em.pas',
- Setup.SelectFolderForm in 'Src\Setup.SelectFolderForm.pas' {SelectFolderForm},
- Compression.Base in 'Src\Compression.Base.pas',
- Compression.Zlib in 'Src\Compression.Zlib.pas',
- Compression.bzlib in 'Src\Compression.bzlib.pas',
- Compression.LZMADecompressor in 'Src\Compression.LZMADecompressor.pas',
- Shared.FileClass in 'Src\Shared.FileClass.pas',
- MD5 in '..\Components\MD5.pas',
- SHA1 in '..\Components\SHA1.pas',
- SHA256 in '..\Components\SHA256.pas',
- Setup.LoggingFunc in 'Src\Setup.LoggingFunc.pas',
- Setup.DebugClient in 'Src\Setup.DebugClient.pas',
- Shared.DebugStruct in 'Src\Shared.DebugStruct.pas',
- ChaCha20 in '..\Components\ChaCha20.pas',
- Setup.Uninstall in 'Src\Setup.Uninstall.pas',
- Setup.UninstallProgressForm in 'Src\Setup.UninstallProgressForm.pas' {UninstallProgressForm},
- Setup.UninstallSharedFileForm in 'Src\Setup.UninstallSharedFileForm.pas' {UninstallSharedFileForm},
- SimpleExpression in '..\Components\SimpleExpression.pas',
- UIStateForm in '..\Components\UIStateForm.pas',
- Setup.SetupForm in 'Src\Setup.SetupForm.pas',
- Setup.RegSvr in 'Src\Setup.RegSvr.pas',
- BrowseFunc in '..\Components\BrowseFunc.pas',
- SetupLdrAndSetup.RedirFunc in 'Src\SetupLdrAndSetup.RedirFunc.pas',
- Setup.SecurityFunc in 'Src\Setup.SecurityFunc.pas',
- Setup.Helper in 'Src\Setup.Helper.pas',
- Shared.VerInfoFunc in 'Src\Shared.VerInfoFunc.pas',
- Setup.RegDLL in 'Src\Setup.RegDLL.pas',
- Shared.ResUpdateFunc in 'Src\Shared.ResUpdateFunc.pas',
- Setup.SpawnCommon in 'Src\Setup.SpawnCommon.pas',
- Setup.SpawnServer in 'Src\Setup.SpawnServer.pas',
- Setup.SpawnClient in 'Src\Setup.SpawnClient.pas',
- Shared.TaskDialogFunc in 'Src\Shared.TaskDialogFunc.pas',
- BidiUtils in '..\Components\BidiUtils.pas',
- PathFunc in '..\Components\PathFunc.pas',
- BidiCtrls in '..\Components\BidiCtrls.pas',
- BitmapButton in '..\Components\BitmapButton.pas',
- BitmapImage in '..\Components\BitmapImage.pas',
- FolderTreeView in '..\Components\FolderTreeView.pas',
- NewCheckListBox in '..\Components\NewCheckListBox.pas',
- NewNotebook in '..\Components\NewNotebook.pas',
- NewProgressBar in '..\Components\NewProgressBar.pas',
- NewStaticText in '..\Components\NewStaticText.pas',
- PasswordEdit in '..\Components\PasswordEdit.pas',
- NewUxTheme.TmSchema in '..\Components\NewUxTheme.TmSchema.pas',
- RestartManager in '..\Components\RestartManager.pas',
- Resample in '..\Components\Resample.pas',
- ASMInline in '..\Components\ASMInline.pas',
- TaskbarProgressFunc in '..\Components\TaskbarProgressFunc.pas',
- Setup.DotNetFunc in 'Src\Setup.DotNetFunc.pas',
- Shared.SetupEntFunc in 'Src\Shared.SetupEntFunc.pas',
- Setup.MsiFunc in 'Src\Setup.MsiFunc.pas',
- Shared.DotNetVersion in 'Src\Shared.DotNetVersion.pas',
- NewUxTheme in '..\Components\NewUxTheme.pas',
- PBKDF2 in '..\Components\PBKDF2.pas',
- Compression.SevenZipDecoder in 'Src\Compression.SevenZipDecoder.pas',
- PSStackHelper in '..\Components\PSStackHelper.pas',
- Setup.ScriptFunc.HelperFunc in 'Src\Setup.ScriptFunc.HelperFunc.pas',
- ECDSA in '..\Components\ECDSA.pas',
- ISSigFunc in '..\Components\ISSigFunc.pas',
- StringScanner in '..\Components\StringScanner.pas',
- Compression.SevenZipDLLDecoder in 'Src\Compression.SevenZipDLLDecoder.pas',
- Compression.SevenZipDLLDecoder.Interfaces in 'Src\Compression.SevenZipDLLDecoder.Interfaces.pas',
- Shared.EncryptionFunc in 'Src\Shared.EncryptionFunc.pas';
- {$SETPEOSVERSION 6.1}
- {$SETPESUBSYSVERSION 6.1}
- {$WEAKLINKRTTI ON}
- {$R Res\Setup.icon.res}
- {$R Res\Setup.images.res}
- {$R Res\Setup.version.res}
- procedure ShowExceptionMsg;
- var
- S: String;
- begin
- if ExceptObject is EAbort then begin
- Log('Got EAbort exception.');
- Exit;
- end;
- S := GetExceptMessage;
- Log('Exception message:');
- LoggedAppMessageBox(PChar(S), Pointer(SetupMessages[msgErrorTitle]),
- MB_OK or MB_ICONSTOP, True, IDOK);
- { ^ use a Pointer cast instead of a PChar cast so that it will use "nil"
- if SetupMessages[msgErrorTitle] is empty due to the messages not being
- loaded yet. MessageBox displays 'Error' as the caption if the lpCaption
- parameter is nil. }
- end;
- type
- TDummyClass = class
- private
- class function AntiShutdownHook(var Message: TMessage): Boolean;
- end;
- class function TDummyClass.AntiShutdownHook(var Message: TMessage): Boolean;
- begin
- { This causes Setup/Uninstall/RegSvr to all deny shutdown attempts.
- - If we were to return 1, Windows will send us a WM_ENDSESSION message and
- TApplication.WndProc will call Halt in response. This is no good because
- it would cause an unclean shutdown of Setup, and it would also prevent
- the right exit code from being returned.
- Even if TApplication.WndProc didn't call Halt, it is my understanding
- that Windows could kill us off after sending us the WM_ENDSESSION message
- (see the Remarks section of the WM_ENDSESSION docs).
- - SetupLdr denys shutdown attempts as well, so there is little point in
- Setup trying to handle them. (Depending on the version of Windows, we
- may never even get a WM_QUERYENDSESSION message because of that.)
- Note: TSetupForm also has a WM_QUERYENDSESSION handler of its own to
- prevent CloseQuery from being called. }
- Result := False;
- case Message.Msg of
- WM_QUERYENDSESSION: begin
- { Return zero, except if RestartInitiatedByThisProcess is set
- (which means we called RestartComputer previously) }
- if RestartInitiatedByThisProcess or (IsUninstaller and AllowUninstallerShutdown) then begin
- AcceptedQueryEndSessionInProgress := True;
- Message.Result := 1
- end else
- Message.Result := 0;
- Result := True;
- end;
- WM_ENDSESSION: begin
- { Should only get here if RestartInitiatedByThisProcess is set or an
- Uninstaller shutdown was allowed, or if the user forced a shutdown.
- Skip the default handling which calls Halt. No code of ours depends
- on the Halt call to clean up, and it could theoretically result in
- obscure reentrancy bugs.
- Example: I've found that combo boxes pump incoming sent messages
- when they are destroyed*; if one of those messages were a
- WM_ENDSESSION, the Halt call could cause another destructor to be
- to be entered (DoneApplication frees all still-existing forms)
- before the combo box's destructor has returned.
- * arguably a Windows bug. The internal ComboLBox window is created
- as a child (WS_CHILD) of GetDesktopWindow(); when it is destroyed,
- a WM_PARENTNOTIFY(WM_DESTROY) message is sent to the desktop window.
- Because the desktop window is on a separate thread, pending sent
- messages are dispatched during the SendMessage call. }
- if Bool(Message.wParam) = True then begin
- if not RestartInitiatedByThisProcess and IsUninstaller then
- HandleUninstallerEndSession;
- end else
- AcceptedQueryEndSessionInProgress := False;
- Result := True;
- end;
- end;
- end;
- procedure DisableWindowGhosting;
- var
- Proc: procedure; stdcall;
- begin
- Proc := GetProcAddress(GetModuleHandle(user32), 'DisableProcessWindowsGhosting');
- if Assigned(Proc) then
- Proc;
- end;
- procedure SelectMode;
- { Determines whether we should run as Setup, Uninstall, or RegSvr }
- var
- ParamName, ParamValue: String;
- Mode: (smSetup, smUninstaller, smRegSvr);
- F: TFile;
- ID: Longint;
- I: Integer;
- begin
- { When SignedUninstaller=yes, the EXE header specifies uninstaller mode by
- default. Use Setup mode instead if we're being called from SetupLdr. }
- SplitNewParamStr(1, ParamName, ParamValue);
- if CompareText(ParamName, '/SL5=') = 0 then
- Exit;
- Mode := smSetup;
- for I := 1 to NewParamCount do begin
- if CompareText(NewParamStr(I), '/UNINSTMODE') = 0 then begin
- Mode := smUninstaller;
- Break;
- end;
- if CompareText(NewParamStr(I), '/REGSVRMODE') = 0 then begin
- Mode := smRegSvr;
- Break;
- end;
- end;
- if Mode = smSetup then begin
- { No mode specified on the command line; check the EXE header for one }
- F := TFile.Create(NewParamStr(0), fdOpenExisting, faRead, fsRead);
- try
- F.Seek(SetupExeModeOffset);
- F.ReadBuffer(ID, SizeOf(ID));
- finally
- F.Free;
- end;
- case ID of
- SetupExeModeUninstaller: Mode := smUninstaller;
- SetupExeModeRegSvr: Mode := smRegSvr;
- end;
- end;
- case Mode of
- smUninstaller: begin
- IsUninstaller := True;
- AllowUninstallerShutdown := False;
- RunUninstaller;
- { Shouldn't get here; RunUninstaller should Halt itself }
- Halt(1);
- end;
- smRegSvr: begin
- try
- RunRegSvr;
- except
- ShowExceptionMsg;
- end;
- Halt;
- end;
- end;
- end;
- begin
- try
- SetErrorMode(SEM_FAILCRITICALERRORS);
- DisableWindowGhosting;
- Application.HookMainWindow(TDummyClass.AntiShutdownHook);
- TRichEditViewer.CustomShellExecute := ShellExecuteAsOriginalUser;
- { Don't respect the show command passed by the parent process.
- "Maximized" makes no sense as our windows don't have maximize/restore
- buttons, and "Minimized" is problematic as the VCL doesn't realize the
- app is minimized (Application.Restore has no effect because
- FAppIconic=False).
- If the parent process is SetupLdr, then there shouldn't be a non-normal
- show command because SetupLdr doesn't specify a show command when
- starting Setup. So this should really only matter when UseSetupLdr=no.
- First, overwrite the System.CmdShow variable to ensure that
- Application.Run (if called) doesn't mess with the main form's
- WindowState.
- Second, because ShowWindow overrides the value of nCmdShow on the first
- call if it's SW_SHOWNORMAL, SW_SHOW, or SW_SHOWDEFAULT (which isn't
- specifically documented; I tested each value), make a first call to
- ShowWindow here that doesn't actually do anything (the app window is
- already hidden at this point, and SW_HIDE is not one of the values that
- get overridden), so that when we show our first form, it will be the
- second call to ShowWindow and won't have its SW_SHOWNORMAL nCmdShow
- value overridden. }
- CmdShow := SW_SHOWNORMAL;
- ShowWindow(Application.Handle, SW_HIDE);
- SelectMode; { Only returns if we should run as Setup }
- except
- { Halt on any exception }
- ShowExceptionMsg;
- Halt(ecInitializationError);
- end;
- { Initialize.
- Note: There's no need to localize the following line since it's changed in
- InitializeSetup }
- Application.Title := 'Setup';
- Application.ShowMainForm := False;
- Application.OnException := TMainForm.ShowException;
- try
- Application.Initialize;
- Application.MainFormOnTaskBar := True;
- InitializeSetup;
- MainForm := TMainForm.Create(Application);
- InitializeWizard;
- except
- { Halt on any exception }
- ShowExceptionMsg;
- try
- DeinitSetup(False);
- except
- { don't propagate any exceptions, so that Halt is always called }
- ShowExceptionMsg;
- end;
- if SetupExitCode <> 0 then
- Halt(SetupExitCode)
- else
- Halt(ecInitializationError);
- end;
- { Run }
- try
- Application.Run;
- except
- { Show any exception and continue }
- ShowExceptionMsg;
- end;
- { Deinitialize (clean up) }
- try
- DeinitSetup(SetupExitCode = 0);
- except
- { Show any exception and continue }
- ShowExceptionMsg;
- end;
- Halt(SetupExitCode);
- end.
|