Setup.dpr 14 KB

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