installer-setup-x86-light.iss 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. // contribute: https://github.com/DomGries/InnoDependencyInstaller
  2. // official article: https://codeproject.com/Articles/20868/Inno-Setup-Dependency-Installer
  3. // requires netcorecheck.exe and netcorecheck_x64.exe (see download link below)
  4. #define UseNetCoreCheck
  5. #ifdef UseNetCoreCheck
  6. ;#define UseDotNet50
  7. #define UseDotNet50Desktop
  8. #endif
  9. // custom setup info
  10. #define MyAppName "PixiEditor"
  11. #define MyAppVersion GetFileVersion("..\Builds\PixiEditor-x86-light\PixiEditor\PixiEditor.exe") ;Not perfect solution, it's enviroment dependend
  12. #define MyAppPublisher "PixiEditor"
  13. #define MyAppURL "https://github.com/PixiEditor/PixiEditor"
  14. #define MyAppExeName "PixiEditor.exe"
  15. #define TargetPlatform "x86-light"
  16. [Setup]
  17. AppId={{83DE4F2A-1F75-43AE-9546-3184F1C44517}
  18. AppName={#MyAppName}
  19. AppVersion={#MyAppVersion}
  20. AppVerName={#MyAppName} {#MyAppVersion}
  21. VersionInfoVersion={#MyAppVersion}
  22. AppPublisher={#MyAppPublisher}
  23. AppPublisherURL={#MyAppURL}
  24. AppSupportURL={#MyAppURL}
  25. AppUpdatesURL={#MyAppURL}
  26. DefaultDirName={autopf}\{#MyAppName}
  27. DisableProgramGroupPage=yes
  28. ; The [Icons] "quicklaunchicon" entry uses {userappdata} but its [Tasks] entry has a proper IsAdminInstallMode Check.
  29. UsedUserAreasWarning=no
  30. LicenseFile=..\LICENSE
  31. ; Uncomment the following line to run in non administrative install mode (install for current user only.)
  32. ;PrivilegesRequired=lowest
  33. OutputDir=Assets\PixiEditor-{#TargetPlatform}
  34. OutputBaseFilename=PixiEditor-{#MyAppVersion}-setup-x86
  35. SetupIconFile=..\icon.ico
  36. Compression=lzma
  37. SolidCompression=yes
  38. WizardStyle=modern
  39. ChangesAssociations = yes
  40. MinVersion=6.0
  41. PrivilegesRequired=admin
  42. // dependency installation requires ready page and ready memo to be enabled (default behaviour)
  43. DisableReadyPage=no
  44. DisableReadyMemo=no
  45. // shared code for installing the dependencies
  46. [Code]
  47. // types and variables
  48. type
  49. TDependency = record
  50. Filename: String;
  51. Parameters: String;
  52. Title: String;
  53. URL: String;
  54. Checksum: String;
  55. ForceSuccess: Boolean;
  56. InstallClean: Boolean;
  57. RebootAfter: Boolean;
  58. end;
  59. InstallResult = (InstallSuccessful, InstallRebootRequired, InstallError);
  60. var
  61. MemoInstallInfo: String;
  62. Dependencies: array of TDependency;
  63. DelayedReboot, ForceX86: Boolean;
  64. DownloadPage: TDownloadWizardPage;
  65. procedure AddDependency(const Filename, Parameters, Title, URL, Checksum: String; const ForceSuccess, InstallClean, RebootAfter: Boolean);
  66. var
  67. Dependency: TDependency;
  68. I: Integer;
  69. begin
  70. MemoInstallInfo := MemoInstallInfo + #13#10 + '%1' + Title;
  71. Dependency.Filename := Filename;
  72. Dependency.Parameters := Parameters;
  73. Dependency.Title := Title;
  74. if FileExists(ExpandConstant('{tmp}{\}') + Filename) then begin
  75. Dependency.URL := '';
  76. end else begin
  77. Dependency.URL := URL;
  78. end;
  79. Dependency.Checksum := Checksum;
  80. Dependency.ForceSuccess := ForceSuccess;
  81. Dependency.InstallClean := InstallClean;
  82. Dependency.RebootAfter := RebootAfter;
  83. I := GetArrayLength(Dependencies);
  84. SetArrayLength(Dependencies, I + 1);
  85. Dependencies[I] := Dependency;
  86. end;
  87. function IsPendingReboot: Boolean;
  88. var
  89. Value: String;
  90. begin
  91. Result := RegQueryMultiStringValue(HKEY_LOCAL_MACHINE, 'SYSTEM\CurrentControlSet\Control\Session Manager', 'PendingFileRenameOperations', Value) or
  92. (RegQueryMultiStringValue(HKEY_LOCAL_MACHINE, 'SYSTEM\CurrentControlSet\Control\Session Manager', 'SetupExecute', Value) and (Value <> ''));
  93. end;
  94. function InstallProducts: InstallResult;
  95. var
  96. ResultCode, I, ProductCount: Integer;
  97. begin
  98. Result := InstallSuccessful;
  99. ProductCount := GetArrayLength(Dependencies);
  100. MemoInstallInfo := SetupMessage(msgReadyMemoTasks);
  101. if ProductCount > 0 then begin
  102. DownloadPage.Show;
  103. for I := 0 to ProductCount - 1 do begin
  104. if Dependencies[I].InstallClean and (DelayedReboot or IsPendingReboot) then begin
  105. Result := InstallRebootRequired;
  106. break;
  107. end;
  108. DownloadPage.SetText(Dependencies[I].Title, '');
  109. DownloadPage.SetProgress(I + 1, ProductCount);
  110. while True do begin
  111. ResultCode := 0;
  112. if ShellExec('', ExpandConstant('{tmp}{\}') + Dependencies[I].Filename, Dependencies[I].Parameters, '', SW_SHOWNORMAL, ewWaitUntilTerminated, ResultCode) then begin
  113. if Dependencies[I].RebootAfter then begin
  114. // delay reboot after install if we installed the last dependency anyways
  115. if I = ProductCount - 1 then begin
  116. DelayedReboot := True;
  117. end else begin
  118. Result := InstallRebootRequired;
  119. MemoInstallInfo := Dependencies[I].Title;
  120. end;
  121. break;
  122. end else if (ResultCode = 0) or Dependencies[I].ForceSuccess then begin
  123. break;
  124. end else if ResultCode = 3010 then begin
  125. // Windows Installer ResultCode 3010: ERROR_SUCCESS_REBOOT_REQUIRED
  126. DelayedReboot := True;
  127. break;
  128. end;
  129. end;
  130. case SuppressibleMsgBox(FmtMessage(SetupMessage(msgErrorFunctionFailed), [Dependencies[I].Title, IntToStr(ResultCode)]), mbError, MB_ABORTRETRYIGNORE, IDIGNORE) of
  131. IDABORT: begin
  132. Result := InstallError;
  133. MemoInstallInfo := MemoInstallInfo + #13#10 + ' ' + Dependencies[I].Title;
  134. break;
  135. end;
  136. IDIGNORE: begin
  137. MemoInstallInfo := MemoInstallInfo + #13#10 + ' ' + Dependencies[I].Title;
  138. break;
  139. end;
  140. end;
  141. end;
  142. if Result <> InstallSuccessful then begin
  143. break;
  144. end;
  145. end;
  146. DownloadPage.Hide;
  147. end;
  148. end;
  149. // Inno Setup event functions
  150. procedure InitializeWizard;
  151. begin
  152. DownloadPage := CreateDownloadPage(SetupMessage(msgWizardPreparing), SetupMessage(msgPreparingDesc), nil);
  153. end;
  154. function PrepareToInstall(var NeedsRestart: Boolean): String;
  155. var
  156. I: Integer;
  157. begin
  158. DelayedReboot := False;
  159. case InstallProducts of
  160. InstallError: begin
  161. Result := MemoInstallInfo;
  162. end;
  163. InstallRebootRequired: begin
  164. Result := MemoInstallInfo;
  165. NeedsRestart := True;
  166. // write into the registry that the installer needs to be executed again after restart
  167. RegWriteStringValue(HKEY_CURRENT_USER, 'SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce', 'InstallBootstrap', ExpandConstant('{srcexe}'));
  168. end;
  169. end;
  170. end;
  171. function NeedRestart: Boolean;
  172. begin
  173. Result := DelayedReboot;
  174. end;
  175. function UpdateReadyMemo(const Space, NewLine, MemoUserInfoInfo, MemoDirInfo, MemoTypeInfo, MemoComponentsInfo, MemoGroupInfo, MemoTasksInfo: String): String;
  176. begin
  177. Result := '';
  178. if MemoUserInfoInfo <> '' then begin
  179. Result := Result + MemoUserInfoInfo + Newline + NewLine;
  180. end;
  181. if MemoDirInfo <> '' then begin
  182. Result := Result + MemoDirInfo + Newline + NewLine;
  183. end;
  184. if MemoTypeInfo <> '' then begin
  185. Result := Result + MemoTypeInfo + Newline + NewLine;
  186. end;
  187. if MemoComponentsInfo <> '' then begin
  188. Result := Result + MemoComponentsInfo + Newline + NewLine;
  189. end;
  190. if MemoGroupInfo <> '' then begin
  191. Result := Result + MemoGroupInfo + Newline + NewLine;
  192. end;
  193. if MemoTasksInfo <> '' then begin
  194. Result := Result + MemoTasksInfo;
  195. end;
  196. if MemoInstallInfo <> '' then begin
  197. if MemoTasksInfo = '' then begin
  198. Result := Result + SetupMessage(msgReadyMemoTasks);
  199. end;
  200. Result := Result + FmtMessage(MemoInstallInfo, [Space]);
  201. end;
  202. end;
  203. function NextButtonClick(const CurPageID: Integer): Boolean;
  204. var
  205. I, ProductCount: Integer;
  206. Retry: Boolean;
  207. begin
  208. Result := True;
  209. if (CurPageID = wpReady) and (MemoInstallInfo <> '') then begin
  210. DownloadPage.Show;
  211. ProductCount := GetArrayLength(Dependencies);
  212. for I := 0 to ProductCount - 1 do begin
  213. if Dependencies[I].URL <> '' then begin
  214. DownloadPage.Clear;
  215. DownloadPage.Add(Dependencies[I].URL, Dependencies[I].Filename, Dependencies[I].Checksum);
  216. Retry := True;
  217. while Retry do begin
  218. Retry := False;
  219. try
  220. DownloadPage.Download;
  221. except
  222. if GetExceptionMessage = SetupMessage(msgErrorDownloadAborted) then begin
  223. Result := False;
  224. I := ProductCount;
  225. end else begin
  226. case SuppressibleMsgBox(AddPeriod(GetExceptionMessage), mbError, MB_ABORTRETRYIGNORE, IDIGNORE) of
  227. IDABORT: begin
  228. Result := False;
  229. I := ProductCount;
  230. end;
  231. IDRETRY: begin
  232. Retry := True;
  233. end;
  234. end;
  235. end;
  236. end;
  237. end;
  238. end;
  239. end;
  240. DownloadPage.Hide;
  241. end;
  242. end;
  243. // architecture helper functions
  244. function IsX64: Boolean;
  245. begin
  246. Result := not ForceX86 and Is64BitInstallMode;
  247. end;
  248. function GetString(const x86, x64: String): String;
  249. begin
  250. if IsX64 then begin
  251. Result := x64;
  252. end else begin
  253. Result := x86;
  254. end;
  255. end;
  256. function GetArchitectureSuffix: String;
  257. begin
  258. Result := GetString('', '_x64');
  259. end;
  260. function GetArchitectureTitle: String;
  261. begin
  262. Result := GetString(' (x86)', ' (x64)');
  263. end;
  264. function CompareVersion(const Version1, Version2: String): Integer;
  265. var
  266. Position, Number1, Number2: Integer;
  267. begin
  268. Result := 0;
  269. while (Version1 <> '') or (Version2 <> '') do begin
  270. Position := Pos('.', Version1);
  271. if Position > 0 then begin
  272. Number1 := StrToIntDef(Copy(Version1, 1, Position - 1), 0);
  273. Delete(Version1, 1, Position);
  274. end else if Version1 <> '' then begin
  275. Number1 := StrToIntDef(Version1, 0);
  276. Version1 := '';
  277. end else begin
  278. Number1 := 0;
  279. end;
  280. Position := Pos('.', Version2);
  281. if Position > 0 then begin
  282. Number2 := StrToIntDef(Copy(Version2, 1, Position - 1), 0);
  283. Delete(Version2, 1, Position);
  284. end else if Version2 <> '' then begin
  285. Number2 := StrToIntDef(Version2, 0);
  286. Version2 := '';
  287. end else begin
  288. Number2 := 0;
  289. end;
  290. if Number1 < Number2 then begin
  291. Result := -1;
  292. break;
  293. end else if Number1 > Number2 then begin
  294. Result := 1;
  295. break;
  296. end;
  297. end;
  298. end;
  299. #ifdef UseNetCoreCheck
  300. // https://github.com/dotnet/deployment-tools/tree/master/src/clickonce/native/projects/NetCoreCheck
  301. function IsNetCoreInstalled(const Version: String): Boolean;
  302. var
  303. ResultCode: Integer;
  304. begin
  305. if not FileExists(ExpandConstant('{tmp}{\}') + 'netcorecheck' + GetArchitectureSuffix + '.exe') then begin
  306. ExtractTemporaryFile('netcorecheck' + GetArchitectureSuffix + '.exe');
  307. end;
  308. Result := ShellExec('', ExpandConstant('{tmp}{\}') + 'netcorecheck' + GetArchitectureSuffix + '.exe', Version, '', SW_HIDE, ewWaitUntilTerminated, ResultCode) and (ResultCode = 0);
  309. end;
  310. #endif
  311. // custom setup content
  312. [Languages]
  313. Name: en; MessagesFile: "compiler:Default.isl"
  314. Name: nl; MessagesFile: "compiler:Languages\Dutch.isl"
  315. Name: de; MessagesFile: "compiler:Languages\German.isl"
  316. [Files]
  317. #ifdef UseNetCoreCheck
  318. // download netcorecheck.exe: https://go.microsoft.com/fwlink/?linkid=2135256
  319. // download netcorecheck_x64.exe: https://go.microsoft.com/fwlink/?linkid=2135504
  320. Source: "netcorecheck.exe"; Flags: dontcopy noencryption
  321. Source: "netcorecheck_x64.exe"; Flags: dontcopy noencryption
  322. #endif
  323. Source: "..\Builds\PixiEditor-{#TargetPlatform}\PixiEditor\PixiEditor.exe"; DestDir: "{app}"; Flags: ignoreversion
  324. Source: "..\Builds\PixiEditor-{#TargetPlatform}\PixiEditor\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
  325. [Icons]
  326. Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
  327. Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
  328. Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: quicklaunchicon
  329. [Tasks]
  330. Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
  331. Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked; OnlyBelowVersion: 6.1; Check: not IsAdminInstallMode
  332. [Run]
  333. Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
  334. [Registry]
  335. Root: HKCR; Subkey: ".pixi"; ValueData: "{#MyAppName}"; Flags: uninsdeletevalue; ValueType: string; ValueName: ""
  336. Root: HKCR; Subkey: "{#MyAppName}"; ValueData: "Program {#MyAppName}"; Flags: uninsdeletekey; ValueType: string; ValueName: ""
  337. Root: HKCR; Subkey: "{#MyAppName}\DefaultIcon"; ValueData: "{app}\{#MyAppExeName},0"; ValueType: string; ValueName: ""
  338. Root: HKCR; Subkey: "{#MyAppName}\shell\open\command"; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; ValueType: string; ValueName: ""
  339. [Code]
  340. function InitializeSetup: Boolean;
  341. var
  342. Version: String;
  343. begin
  344. #ifdef UseDotNet50
  345. // https://dotnet.microsoft.com/download/dotnet/5.0
  346. if not IsNetCoreInstalled('Microsoft.NETCore.App 5.0.0') then begin
  347. AddDependency('dotnet50' + GetArchitectureSuffix + '.exe',
  348. '/lcid ' + IntToStr(GetUILanguage) + ' /passive /norestart',
  349. '.NET Runtime 5.0' + GetArchitectureTitle,
  350. GetString('https://download.visualstudio.microsoft.com/download/pr/a7e15da3-7a15-43c2-a481-cf50bf305214/c69b951e8b47101e90b1289c387bb01a/dotnet-runtime-5.0.0-win-x86.exe', 'https://download.visualstudio.microsoft.com/download/pr/36a9dc4e-1745-4f17-8a9c-f547a12e3764/ae25e38f20a4854d5e015a88659a22f9/dotnet-runtime-5.0.0-win-x64.exe'),
  351. '', False, False, False);
  352. end;
  353. #endif
  354. #ifdef UseDotNet50Desktop
  355. // https://dotnet.microsoft.com/download/dotnet/5.0
  356. if not IsNetCoreInstalled('Microsoft.WindowsDesktop.App 5.0.0') then begin
  357. AddDependency('dotnet50desktop' + GetArchitectureSuffix + '.exe',
  358. '/lcid ' + IntToStr(GetUILanguage) + ' /passive /norestart',
  359. '.NET Desktop Runtime 5.0' + GetArchitectureTitle,
  360. GetString('https://download.visualstudio.microsoft.com/download/pr/b2780d75-e54a-448a-95fc-da9721b2b4c2/62310a9e9f0ba7b18741944cbae9f592/windowsdesktop-runtime-5.0.0-win-x86.exe', 'https://download.visualstudio.microsoft.com/download/pr/1b3a8899-127a-4465-a3c2-7ce5e4feb07b/1e153ad470768baa40ed3f57e6e7a9d8/windowsdesktop-runtime-5.0.0-win-x64.exe'),
  361. '', False, False, False);
  362. end;
  363. #endif
  364. Result := True;
  365. end;