Setup.dpr 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. program Setup;
  2. {
  3. Inno Setup
  4. Copyright (C) 1997-2025 Jordan Russell
  5. Portions by Martijn Laan
  6. For conditions of distribution and use, see LICENSE.TXT.
  7. Setup program
  8. }
  9. uses
  10. SafeDLLPath in '..\Components\SafeDLLPath.pas',
  11. SetupLdrAndSetup.XPTheme in 'Src\SetupLdrAndSetup.XPTheme.pas',
  12. Forms,
  13. Windows,
  14. SysUtils,
  15. Messages,
  16. RichEditViewer in '..\Components\RichEditViewer.pas',
  17. Shared.CommonFunc.Vcl in 'Src\Shared.CommonFunc.Vcl.pas',
  18. Shared.CommonFunc in 'Src\Shared.CommonFunc.pas',
  19. Setup.MainForm in 'Src\Setup.MainForm.pas',
  20. Setup.MainFunc in 'Src\Setup.MainFunc.pas',
  21. Setup.Install in 'Src\Setup.Install.pas',
  22. SetupLdrAndSetup.Messages in 'Src\SetupLdrAndSetup.Messages.pas',
  23. Shared.SetupMessageIDs in 'Src\Shared.SetupMessageIDs.pas',
  24. Setup.UninstallLog in 'Src\Setup.UninstallLog.pas',
  25. Shared.Struct in 'Src\Shared.Struct.pas',
  26. Setup.NewDiskForm in 'Src\Setup.NewDiskForm.pas' {NewDiskForm},
  27. SetupLdrAndSetup.InstFunc in 'Src\SetupLdrAndSetup.InstFunc.pas',
  28. Setup.InstFunc in 'Src\Setup.InstFunc.pas',
  29. Setup.InstFunc.Ole in 'Src\Setup.InstFunc.Ole.pas',
  30. Setup.WizardForm in 'Src\Setup.WizardForm.pas' {WizardForm},
  31. Setup.ScriptFunc in 'Src\Setup.ScriptFunc.pas',
  32. Shared.ScriptFunc in 'Src\Shared.ScriptFunc.pas',
  33. Shared.SetupTypes in 'Src\Shared.SetupTypes.pas',
  34. Shared.SetupSteps in 'Src\Shared.SetupSteps.pas',
  35. Setup.ScriptRunner in 'Src\Setup.ScriptRunner.pas',
  36. Setup.ScriptDlg in 'Src\Setup.ScriptDlg.pas',
  37. Setup.ScriptClasses in 'Src\Setup.ScriptClasses.pas',
  38. Setup.SelectLanguageForm in 'Src\Setup.SelectLanguageForm.pas' {SelectLanguageForm},
  39. Setup.FileExtractor in 'Src\Setup.FileExtractor.pas',
  40. Shared.Int64Em in 'Src\Shared.Int64Em.pas',
  41. Setup.SelectFolderForm in 'Src\Setup.SelectFolderForm.pas' {SelectFolderForm},
  42. Compression.Base in 'Src\Compression.Base.pas',
  43. Compression.Zlib in 'Src\Compression.Zlib.pas',
  44. Compression.bzlib in 'Src\Compression.bzlib.pas',
  45. Compression.LZMADecompressor in 'Src\Compression.LZMADecompressor.pas',
  46. Shared.FileClass in 'Src\Shared.FileClass.pas',
  47. MD5 in '..\Components\MD5.pas',
  48. SHA1 in '..\Components\SHA1.pas',
  49. SHA256 in '..\Components\SHA256.pas',
  50. Setup.LoggingFunc in 'Src\Setup.LoggingFunc.pas',
  51. Setup.DebugClient in 'Src\Setup.DebugClient.pas',
  52. Shared.DebugStruct in 'Src\Shared.DebugStruct.pas',
  53. ChaCha20 in '..\Components\ChaCha20.pas',
  54. Setup.Uninstall in 'Src\Setup.Uninstall.pas',
  55. Setup.UninstallProgressForm in 'Src\Setup.UninstallProgressForm.pas' {UninstallProgressForm},
  56. Setup.UninstallSharedFileForm in 'Src\Setup.UninstallSharedFileForm.pas' {UninstallSharedFileForm},
  57. SimpleExpression in '..\Components\SimpleExpression.pas',
  58. UIStateForm in '..\Components\UIStateForm.pas',
  59. Setup.SetupForm in 'Src\Setup.SetupForm.pas',
  60. Setup.RegSvr in 'Src\Setup.RegSvr.pas',
  61. BrowseFunc in '..\Components\BrowseFunc.pas',
  62. SetupLdrAndSetup.RedirFunc in 'Src\SetupLdrAndSetup.RedirFunc.pas',
  63. Setup.SecurityFunc in 'Src\Setup.SecurityFunc.pas',
  64. Setup.Helper in 'Src\Setup.Helper.pas',
  65. Shared.VerInfoFunc in 'Src\Shared.VerInfoFunc.pas',
  66. Setup.RegDLL in 'Src\Setup.RegDLL.pas',
  67. Shared.ResUpdateFunc in 'Src\Shared.ResUpdateFunc.pas',
  68. Setup.SpawnCommon in 'Src\Setup.SpawnCommon.pas',
  69. Setup.SpawnServer in 'Src\Setup.SpawnServer.pas',
  70. Setup.SpawnClient in 'Src\Setup.SpawnClient.pas',
  71. Shared.TaskDialogFunc in 'Src\Shared.TaskDialogFunc.pas',
  72. BidiUtils in '..\Components\BidiUtils.pas',
  73. PathFunc in '..\Components\PathFunc.pas',
  74. BidiCtrls in '..\Components\BidiCtrls.pas',
  75. BitmapImage in '..\Components\BitmapImage.pas',
  76. FolderTreeView in '..\Components\FolderTreeView.pas',
  77. NewCheckListBox in '..\Components\NewCheckListBox.pas',
  78. NewNotebook in '..\Components\NewNotebook.pas',
  79. NewProgressBar in '..\Components\NewProgressBar.pas',
  80. NewStaticText in '..\Components\NewStaticText.pas',
  81. PasswordEdit in '..\Components\PasswordEdit.pas',
  82. NewUxTheme.TmSchema in '..\Components\NewUxTheme.TmSchema.pas',
  83. RestartManager in '..\Components\RestartManager.pas',
  84. Resample in '..\Components\Resample.pas',
  85. ASMInline in '..\Components\ASMInline.pas',
  86. TaskbarProgressFunc in '..\Components\TaskbarProgressFunc.pas',
  87. Setup.DotNetFunc in 'Src\Setup.DotNetFunc.pas',
  88. Shared.SetupEntFunc in 'Src\Shared.SetupEntFunc.pas',
  89. Setup.MsiFunc in 'Src\Setup.MsiFunc.pas',
  90. Shared.DotNetVersion in 'Src\Shared.DotNetVersion.pas',
  91. NewUxTheme in '..\Components\NewUxTheme.pas',
  92. PBKDF2 in '..\Components\PBKDF2.pas',
  93. Compression.SevenZipDecoder in 'Src\Compression.SevenZipDecoder.pas',
  94. PSStackHelper in '..\Components\PSStackHelper.pas',
  95. Setup.ScriptFunc.HelperFunc in 'Src\Setup.ScriptFunc.HelperFunc.pas';
  96. {$SETPEOSVERSION 6.1}
  97. {$SETPESUBSYSVERSION 6.1}
  98. {$WEAKLINKRTTI ON}
  99. {$R Res\Setup.icon.res}
  100. {$R Res\Setup.images.res}
  101. {$R Res\Setup.version.res}
  102. procedure ShowExceptionMsg;
  103. var
  104. S: String;
  105. begin
  106. if ExceptObject is EAbort then begin
  107. Log('Got EAbort exception.');
  108. Exit;
  109. end;
  110. S := GetExceptMessage;
  111. Log('Exception message:');
  112. LoggedAppMessageBox(PChar(S), Pointer(SetupMessages[msgErrorTitle]),
  113. MB_OK or MB_ICONSTOP, True, IDOK);
  114. { ^ use a Pointer cast instead of a PChar cast so that it will use "nil"
  115. if SetupMessages[msgErrorTitle] is empty due to the messages not being
  116. loaded yet. MessageBox displays 'Error' as the caption if the lpCaption
  117. parameter is nil. }
  118. end;
  119. type
  120. TDummyClass = class
  121. private
  122. class function AntiShutdownHook(var Message: TMessage): Boolean;
  123. end;
  124. class function TDummyClass.AntiShutdownHook(var Message: TMessage): Boolean;
  125. begin
  126. { This causes Setup/Uninstall/RegSvr to all deny shutdown attempts.
  127. - If we were to return 1, Windows will send us a WM_ENDSESSION message and
  128. TApplication.WndProc will call Halt in response. This is no good because
  129. it would cause an unclean shutdown of Setup, and it would also prevent
  130. the right exit code from being returned.
  131. Even if TApplication.WndProc didn't call Halt, it is my understanding
  132. that Windows could kill us off after sending us the WM_ENDSESSION message
  133. (see the Remarks section of the WM_ENDSESSION docs).
  134. - SetupLdr denys shutdown attempts as well, so there is little point in
  135. Setup trying to handle them. (Depending on the version of Windows, we
  136. may never even get a WM_QUERYENDSESSION message because of that.)
  137. Note: TSetupForm also has a WM_QUERYENDSESSION handler of its own to
  138. prevent CloseQuery from being called. }
  139. Result := False;
  140. case Message.Msg of
  141. WM_QUERYENDSESSION: begin
  142. { Return zero, except if RestartInitiatedByThisProcess is set
  143. (which means we called RestartComputer previously) }
  144. if RestartInitiatedByThisProcess or (IsUninstaller and AllowUninstallerShutdown) then begin
  145. AcceptedQueryEndSessionInProgress := True;
  146. Message.Result := 1
  147. end else
  148. Message.Result := 0;
  149. Result := True;
  150. end;
  151. WM_ENDSESSION: begin
  152. { Should only get here if RestartInitiatedByThisProcess is set or an
  153. Uninstaller shutdown was allowed, or if the user forced a shutdown.
  154. Skip the default handling which calls Halt. No code of ours depends
  155. on the Halt call to clean up, and it could theoretically result in
  156. obscure reentrancy bugs.
  157. Example: I've found that combo boxes pump incoming sent messages
  158. when they are destroyed*; if one of those messages were a
  159. WM_ENDSESSION, the Halt call could cause another destructor to be
  160. to be entered (DoneApplication frees all still-existing forms)
  161. before the combo box's destructor has returned.
  162. * arguably a Windows bug. The internal ComboLBox window is created
  163. as a child (WS_CHILD) of GetDesktopWindow(); when it is destroyed,
  164. a WM_PARENTNOTIFY(WM_DESTROY) message is sent to the desktop window.
  165. Because the desktop window is on a separate thread, pending sent
  166. messages are dispatched during the SendMessage call. }
  167. if Bool(Message.wParam) = True then begin
  168. if not RestartInitiatedByThisProcess and IsUninstaller then
  169. HandleUninstallerEndSession;
  170. end else
  171. AcceptedQueryEndSessionInProgress := False;
  172. Result := True;
  173. end;
  174. end;
  175. end;
  176. procedure DisableWindowGhosting;
  177. var
  178. Proc: procedure; stdcall;
  179. begin
  180. Proc := GetProcAddress(GetModuleHandle(user32), 'DisableProcessWindowsGhosting');
  181. if Assigned(Proc) then
  182. Proc;
  183. end;
  184. procedure SelectMode;
  185. { Determines whether we should run as Setup, Uninstall, or RegSvr }
  186. var
  187. ParamName, ParamValue: String;
  188. Mode: (smSetup, smUninstaller, smRegSvr);
  189. F: TFile;
  190. ID: Longint;
  191. I: Integer;
  192. begin
  193. { When SignedUninstaller=yes, the EXE header specifies uninstaller mode by
  194. default. Use Setup mode instead if we're being called from SetupLdr. }
  195. SplitNewParamStr(1, ParamName, ParamValue);
  196. if CompareText(ParamName, '/SL5=') = 0 then
  197. Exit;
  198. Mode := smSetup;
  199. for I := 1 to NewParamCount do begin
  200. if CompareText(NewParamStr(I), '/UNINSTMODE') = 0 then begin
  201. Mode := smUninstaller;
  202. Break;
  203. end;
  204. if CompareText(NewParamStr(I), '/REGSVRMODE') = 0 then begin
  205. Mode := smRegSvr;
  206. Break;
  207. end;
  208. end;
  209. if Mode = smSetup then begin
  210. { No mode specified on the command line; check the EXE header for one }
  211. F := TFile.Create(NewParamStr(0), fdOpenExisting, faRead, fsRead);
  212. try
  213. F.Seek(SetupExeModeOffset);
  214. F.ReadBuffer(ID, SizeOf(ID));
  215. finally
  216. F.Free;
  217. end;
  218. case ID of
  219. SetupExeModeUninstaller: Mode := smUninstaller;
  220. SetupExeModeRegSvr: Mode := smRegSvr;
  221. end;
  222. end;
  223. case Mode of
  224. smUninstaller: begin
  225. IsUninstaller := True;
  226. AllowUninstallerShutdown := False;
  227. RunUninstaller;
  228. { Shouldn't get here; RunUninstaller should Halt itself }
  229. Halt(1);
  230. end;
  231. smRegSvr: begin
  232. try
  233. RunRegSvr;
  234. except
  235. ShowExceptionMsg;
  236. end;
  237. Halt;
  238. end;
  239. end;
  240. end;
  241. begin
  242. try
  243. SetErrorMode(SEM_FAILCRITICALERRORS);
  244. DisableWindowGhosting;
  245. Application.HookMainWindow(TDummyClass.AntiShutdownHook);
  246. TRichEditViewer.CustomShellExecute := ShellExecuteAsOriginalUser;
  247. { Don't respect the show command passed by the parent process.
  248. "Maximized" makes no sense as our windows don't have maximize/restore
  249. buttons, and "Minimized" is problematic as the VCL doesn't realize the
  250. app is minimized (Application.Restore has no effect because
  251. FAppIconic=False).
  252. If the parent process is SetupLdr, then there shouldn't be a non-normal
  253. show command because SetupLdr doesn't specify a show command when
  254. starting Setup. So this should really only matter when UseSetupLdr=no.
  255. First, overwrite the System.CmdShow variable to ensure that
  256. Application.Run (if called) doesn't mess with the main form's
  257. WindowState.
  258. Second, because ShowWindow overrides the value of nCmdShow on the first
  259. call if it's SW_SHOWNORMAL, SW_SHOW, or SW_SHOWDEFAULT (which isn't
  260. specifically documented; I tested each value), make a first call to
  261. ShowWindow here that doesn't actually do anything (the app window is
  262. already hidden at this point, and SW_HIDE is not one of the values that
  263. get overridden), so that when we show our first form, it will be the
  264. second call to ShowWindow and won't have its SW_SHOWNORMAL nCmdShow
  265. value overridden. }
  266. CmdShow := SW_SHOWNORMAL;
  267. ShowWindow(Application.Handle, SW_HIDE);
  268. SelectMode; { Only returns if we should run as Setup }
  269. except
  270. { Halt on any exception }
  271. ShowExceptionMsg;
  272. Halt(ecInitializationError);
  273. end;
  274. { Initialize.
  275. Note: There's no need to localize the following line since it's changed in
  276. InitializeSetup }
  277. Application.Title := 'Setup';
  278. Application.ShowMainForm := False;
  279. Application.OnException := TMainForm.ShowException;
  280. try
  281. Application.Initialize;
  282. Application.MainFormOnTaskBar := True;
  283. InitializeSetup;
  284. MainForm := TMainForm.Create(Application);
  285. InitializeWizard;
  286. except
  287. { Halt on any exception }
  288. ShowExceptionMsg;
  289. try
  290. DeinitSetup(False);
  291. except
  292. { don't propagate any exceptions, so that Halt is always called }
  293. ShowExceptionMsg;
  294. end;
  295. if SetupExitCode <> 0 then
  296. Halt(SetupExitCode)
  297. else
  298. Halt(ecInitializationError);
  299. end;
  300. { Run }
  301. try
  302. Application.Run;
  303. except
  304. { Show any exception and continue }
  305. ShowExceptionMsg;
  306. end;
  307. { Deinitialize (clean up) }
  308. try
  309. DeinitSetup(SetupExitCode = 0);
  310. except
  311. { Show any exception and continue }
  312. ShowExceptionMsg;
  313. end;
  314. Halt(SetupExitCode);
  315. end.