installer-setup-x64-light.iss 14 KB

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