Setup.dpr 13 KB

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