products.pas 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. {
  2. --- TYPES AND VARIABLES ---
  3. }
  4. type
  5. TProduct = record
  6. File: String;
  7. Title: String;
  8. Parameters: String;
  9. ForceSuccess : boolean;
  10. InstallClean : boolean;
  11. MustRebootAfter : boolean;
  12. end;
  13. InstallResult = (InstallSuccessful, InstallRebootRequired, InstallError);
  14. var
  15. installMemo, downloadMessage: string;
  16. products: array of TProduct;
  17. delayedReboot, isForcedX86: boolean;
  18. DependencyPage: TOutputProgressWizardPage;
  19. procedure AddProduct(filename, parameters, title, size, url: string; forceSuccess, installClean, mustRebootAfter : boolean);
  20. {
  21. Adds a product to the list of products to download.
  22. Parameters:
  23. filename: the file name under which to save the file
  24. parameters: the parameters with which to run the file
  25. title: the product title
  26. size: the file size
  27. url: the URL to download from
  28. forceSuccess: whether to continue in case of setup failure
  29. installClean: whether the product needs a reboot before installing
  30. mustRebootAfter: whether the product needs a reboot after installing
  31. }
  32. var
  33. path: string;
  34. i: Integer;
  35. begin
  36. installMemo := installMemo + '%1' + title + #13;
  37. path := ExpandConstant('{src}{\}') + CustomMessage('DependenciesDir') + '\' + filename;
  38. if not FileExists(path) then begin
  39. path := ExpandConstant('{tmp}{\}') + filename;
  40. if not FileExists(path) then begin
  41. isxdl_AddFile(url, path);
  42. downloadMessage := downloadMessage + '%1' + title + ' (' + size + ')' + #13;
  43. end;
  44. end;
  45. i := GetArrayLength(products);
  46. SetArrayLength(products, i + 1);
  47. products[i].File := path;
  48. products[i].Title := title;
  49. products[i].Parameters := parameters;
  50. products[i].ForceSuccess := forceSuccess;
  51. products[i].InstallClean := installClean;
  52. products[i].MustRebootAfter := mustRebootAfter;
  53. end;
  54. function SmartExec(product : TProduct; var resultcode : Integer): boolean;
  55. {
  56. Executes a product and returns the exit code.
  57. Parameters:
  58. product: the product to install
  59. resultcode: the exit code
  60. }
  61. begin
  62. if (LowerCase(Copy(product.File, Length(product.File) - 2, 3)) = 'exe') then begin
  63. Result := Exec(product.File, product.Parameters, '', SW_SHOWNORMAL, ewWaitUntilTerminated, resultcode);
  64. end else begin
  65. Result := ShellExec('', product.File, product.Parameters, '', SW_SHOWNORMAL, ewWaitUntilTerminated, resultcode);
  66. end;
  67. end;
  68. function PendingReboot: boolean;
  69. {
  70. Checks whether the machine has a pending reboot.
  71. }
  72. var names: String;
  73. begin
  74. if (RegQueryMultiStringValue(HKEY_LOCAL_MACHINE, 'SYSTEM\CurrentControlSet\Control\Session Manager', 'PendingFileRenameOperations', names)) then begin
  75. Result := true;
  76. end else if ((RegQueryMultiStringValue(HKEY_LOCAL_MACHINE, 'SYSTEM\CurrentControlSet\Control\Session Manager', 'SetupExecute', names)) and (names <> '')) then begin
  77. Result := true;
  78. end else begin
  79. Result := false;
  80. end;
  81. end;
  82. function InstallProducts: InstallResult;
  83. {
  84. Installs the downloaded products
  85. }
  86. var
  87. resultCode, i, productCount, finishCount: Integer;
  88. begin
  89. Result := InstallSuccessful;
  90. productCount := GetArrayLength(products);
  91. if productCount > 0 then begin
  92. DependencyPage := CreateOutputProgressPage(CustomMessage('depinstall_title'), CustomMessage('depinstall_description'));
  93. DependencyPage.Show;
  94. for i := 0 to productCount - 1 do begin
  95. if (products[i].InstallClean and (delayedReboot or PendingReboot())) then begin
  96. Result := InstallRebootRequired;
  97. break;
  98. end;
  99. DependencyPage.SetText(FmtMessage(CustomMessage('depinstall_status'), [products[i].Title]), '');
  100. DependencyPage.SetProgress(i, productCount);
  101. while true do begin
  102. // set 0 as used code for shown error if SmartExec fails
  103. resultCode := 0;
  104. if SmartExec(products[i], resultCode) then begin
  105. // setup executed; resultCode contains the exit code
  106. if (products[i].MustRebootAfter) then begin
  107. // delay reboot after install if we installed the last dependency anyways
  108. if (i = productCount - 1) then begin
  109. delayedReboot := true;
  110. end else begin
  111. Result := InstallRebootRequired;
  112. end;
  113. break;
  114. end else if (resultCode = 0) or (products[i].ForceSuccess) then begin
  115. finishCount := finishCount + 1;
  116. break;
  117. end else if (resultCode = 3010) then begin
  118. // Windows Installer resultCode 3010: ERROR_SUCCESS_REBOOT_REQUIRED
  119. delayedReboot := true;
  120. finishCount := finishCount + 1;
  121. break;
  122. end;
  123. end;
  124. case MsgBox(FmtMessage(SetupMessage(msgErrorFunctionFailed), [products[i].Title, IntToStr(resultCode)]), mbError, MB_ABORTRETRYIGNORE) of
  125. IDABORT: begin
  126. Result := InstallError;
  127. break;
  128. end;
  129. IDIGNORE: begin
  130. break;
  131. end;
  132. end;
  133. end;
  134. if Result <> InstallSuccessful then begin
  135. break;
  136. end;
  137. end;
  138. // only leave not installed products for error message
  139. for i := 0 to productCount - finishCount - 1 do begin
  140. products[i] := products[i+finishCount];
  141. end;
  142. SetArrayLength(products, productCount - finishCount);
  143. DependencyPage.Hide;
  144. end;
  145. end;
  146. {
  147. --------------------
  148. INNO EVENT FUNCTIONS
  149. --------------------
  150. }
  151. function PrepareToInstall(var NeedsRestart: boolean): String;
  152. {
  153. Before the "preparing to install" page.
  154. See: http://www.jrsoftware.org/ishelp/index.php?topic=scriptevents
  155. }
  156. var
  157. i: Integer;
  158. s: string;
  159. begin
  160. delayedReboot := false;
  161. case InstallProducts() of
  162. InstallError: begin
  163. s := CustomMessage('depinstall_error');
  164. for i := 0 to GetArrayLength(products) - 1 do begin
  165. s := s + #13 + ' ' + products[i].Title;
  166. end;
  167. Result := s;
  168. end;
  169. InstallRebootRequired: begin
  170. Result := products[0].Title;
  171. NeedsRestart := true;
  172. // write into the registry that the installer needs to be executed again after restart
  173. RegWriteStringValue(HKEY_CURRENT_USER, 'SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce', 'InstallBootstrap', ExpandConstant('{srcexe}'));
  174. end;
  175. end;
  176. end;
  177. function NeedRestart : boolean;
  178. {
  179. Checks whether a restart is needed at the end of install
  180. See: http://www.jrsoftware.org/ishelp/index.php?topic=scriptevents
  181. }
  182. begin
  183. Result := delayedReboot;
  184. end;
  185. function UpdateReadyMemo(Space, NewLine, MemoUserInfoInfo, MemoDirInfo, MemoTypeInfo, MemoComponentsInfo, MemoGroupInfo, MemoTasksInfo: String): String;
  186. {
  187. Just before the "ready" page.
  188. See: http://www.jrsoftware.org/ishelp/index.php?topic=scriptevents
  189. }
  190. var
  191. s: string;
  192. begin
  193. if downloadMessage <> '' then
  194. s := s + CustomMessage('depdownload_memo_title') + ':' + NewLine + FmtMessage(downloadMessage, [Space]) + NewLine;
  195. if installMemo <> '' then
  196. s := s + CustomMessage('depinstall_memo_title') + ':' + NewLine + FmtMessage(installMemo, [Space]) + NewLine;
  197. if MemoDirInfo <> '' then
  198. s := s + MemoDirInfo + NewLine + NewLine;
  199. if MemoGroupInfo <> '' then
  200. s := s + MemoGroupInfo + NewLine + NewLine;
  201. if MemoTasksInfo <> '' then
  202. s := s + MemoTasksInfo;
  203. Result := s
  204. end;
  205. function NextButtonClick(CurPageID: Integer): boolean;
  206. {
  207. At each "next" button click
  208. See: http://www.jrsoftware.org/ishelp/index.php?topic=scriptevents
  209. }
  210. begin
  211. Result := true;
  212. if CurPageID = wpReady then begin
  213. if downloadMessage <> '' then begin
  214. // change isxdl language only if it is not english because isxdl default language is already english
  215. //if (ActiveLanguage() <> 'en') then begin
  216. // ExtractTemporaryFile(CustomMessage('isxdl_langfile'));
  217. // isxdl_SetOption('language', ExpandConstant('{tmp}{\}') + CustomMessage('isxdl_langfile'));
  218. //end;
  219. //isxdl_SetOption('title', FmtMessage(SetupMessage(msgSetupWindowTitle), [CustomMessage('appname')]));
  220. //if SuppressibleMsgBox(FmtMessage(CustomMessage('depdownload_msg'), [FmtMessage(downloadMessage, [''])]), mbConfirmation, MB_YESNO, IDYES) = IDNO then
  221. // Result := false
  222. //else if
  223. if isxdl_DownloadFiles(StrToInt(ExpandConstant('{wizardhwnd}'))) = 0 then
  224. Result := false;
  225. end;
  226. end;
  227. end;
  228. {
  229. -----------------------------
  230. ARCHITECTURE HELPER FUNCTIONS
  231. -----------------------------
  232. }
  233. function IsX86: boolean;
  234. {
  235. Gets whether the computer is x86 (32 bits).
  236. }
  237. begin
  238. Result := isForcedX86 or (ProcessorArchitecture = paX86) or (ProcessorArchitecture = paUnknown);
  239. end;
  240. function IsX64: boolean;
  241. {
  242. Gets whether the computer is x64 (64 bits).
  243. }
  244. begin
  245. Result := (not isForcedX86) and Is64BitInstallMode and (ProcessorArchitecture = paX64);
  246. end;
  247. function IsIA64: boolean;
  248. {
  249. Gets whether the computer is IA64 (Itanium 64 bits).
  250. }
  251. begin
  252. Result := (not isForcedX86) and Is64BitInstallMode and (ProcessorArchitecture = paIA64);
  253. end;
  254. function GetString(x86, x64, ia64: String): String;
  255. {
  256. Gets a string depending on the computer architecture.
  257. Parameters:
  258. x86: the string if the computer is x86
  259. x64: the string if the computer is x64
  260. ia64: the string if the computer is IA64
  261. }
  262. begin
  263. if IsX64() and (x64 <> '') then begin
  264. Result := x64;
  265. end else if IsIA64() and (ia64 <> '') then begin
  266. Result := ia64;
  267. end else begin
  268. Result := x86;
  269. end;
  270. end;
  271. function GetArchitectureString(): String;
  272. {
  273. Gets the "standard" architecture suffix string.
  274. Returns either _x64, _ia64 or nothing.
  275. }
  276. begin
  277. if IsX64() then begin
  278. Result := '_x64';
  279. end else if IsIA64() then begin
  280. Result := '_ia64';
  281. end else begin
  282. Result := '';
  283. end;
  284. end;
  285. procedure SetForceX86(value: boolean);
  286. {
  287. Forces the setup to use X86 products
  288. }
  289. begin
  290. isForcedX86 := value;
  291. end;