common.iss 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. #define AppExeName "SyncTrayzor.exe"
  2. #define AppRoot "..\.."
  3. #define AppSrc AppRoot + "\src\SyncTrayzor"
  4. #define AppBin AppRoot +"\bin\" + Arch + "\Release"
  5. #define AppExe AppBin + "\SyncTrayzor.exe"
  6. #define AppName GetStringFileInfo(AppExe, "ProductName")
  7. #define AppVersion GetFileVersion(AppExe)
  8. #define AppPublisher "SyncTrayzor"
  9. #define AppURL "https://github.com/canton7/SyncTrayzor"
  10. #define AppDataFolder "SyncTrayzor"
  11. #define RunRegKey "Software\Microsoft\Windows\CurrentVersion\Run"
  12. #define DotNetInstallerExe "dotNet451Setup.exe"
  13. [Setup]
  14. AppId={{#AppId}
  15. AppName={#AppName} ({#Arch})
  16. AppVersion={#AppVersion}
  17. ;AppVerName={#AppName} {#AppVersion}
  18. AppPublisher={#AppPublisher}
  19. AppPublisherURL={#AppURL}
  20. AppSupportURL={#AppURL}
  21. AppUpdatesURL={#AppURL}
  22. DefaultDirName={pf}\{#AppName}
  23. DefaultGroupName={#AppName}
  24. AllowNoIcons=yes
  25. LicenseFile={#AppRoot}\LICENSE.txt
  26. OutputDir="."
  27. OutputBaseFilename={#AppName}Setup-{#Arch}
  28. SetupIconFile={#AppSrc}\Icons\default.ico
  29. WizardSmallImageFile=..\icon.bmp
  30. Compression=lzma2/max
  31. ;Compression=None
  32. SolidCompression=yes
  33. PrivilegesRequired=admin
  34. CloseApplications=yes
  35. RestartApplications=no
  36. ; If we try and close CefSharp.BrowserSubprocess.exe we'll fail - it doesn't respond well
  37. ; However if we close *just* SyncTrayzor, that will take care of shutting down CefSharp and syncthing
  38. CloseApplicationsFilter=SyncTrayzor.exe
  39. TouchDate=current
  40. #if "x64" == Arch
  41. ArchitecturesInstallIn64BitMode=x64
  42. ArchitecturesAllowed=x64
  43. #endif
  44. [Languages]
  45. Name: "english"; MessagesFile: "compiler:Default.isl"
  46. [CustomMessages]
  47. InstallingDotNetFramework=Installing .NET Framework. This might take a few minutes...
  48. DotNetFrameworkFailedToLaunch=Failed to launch .NET Framework Installer with error "%1". Please fix the error then run this installer again.
  49. DotNetFrameworkFailed1602=.NET Framework installation was cancelled. This installation can continue, but be aware that this application may not run unless the .NET Framework installation is completed successfully.
  50. DotNetFrameworkFailed1603=A fatal error occurred while installing the .NET Framework. Please fix the error, then run the installer again.
  51. DotNetFrameworkFailed5100=Your computer does not meet the requirements of the .NET Framework. Please consult the documentation.
  52. DotNetFrameworkFailedOther=The .NET Framework installer exited with an unexpected status code "%1". Please review any other messages shown by the installer to determine whether the installation completed successfully, and abort this installation and fix the problem if it did not.
  53. [Tasks]
  54. Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
  55. [Dirs]
  56. Name: "{userappdata}\{#AppDataFolder}"
  57. [Files]
  58. ; Near the beginning, as it's extracted first and this makes it cheaper
  59. Source: "..\{#DotNetInstallerExe}"; DestDir: {tmp}; Flags: dontcopy nocompression noencryption
  60. Source: "{#AppBin}\*"; DestDir: "{app}"; Excludes: "*.xml,*.vshost.*,*.config,*.log,FluentValidation.resources.dll,System.Windows.Interactivity.resources.dll,syncthing.exe,data,logs,ffmpegsumo.dll,d3dcompiler_43.dll,d3dcompiler_47.dll,libEGL.dll,libGLESv2.dll,pdf.dll"; Flags: ignoreversion recursesubdirs
  61. Source: "{#AppBin}\SyncTrayzor.exe.Installer.config"; DestDir: "{app}"; DestName: "SyncTrayzor.exe.config"; Flags: ignoreversion
  62. Source: "{#AppSrc}\Icons\default.ico"; DestDir: "{app}"; Flags: ignoreversion
  63. Source: "{#AppRoot}\*.md"; DestDir: "{app}"; Flags: ignoreversion
  64. Source: "{#AppRoot}\*.txt"; DestDir: "{app}"; Flags: ignoreversion
  65. Source: "*.dll"; DestDir: "{app}"; Flags: ignoreversion
  66. Source: "syncthing.exe"; DestDir: "{app}"; DestName: "syncthing.exe"; Flags: ignoreversion
  67. [Icons]
  68. Name: "{group}\{#AppName}"; Filename: "{app}\{#AppExeName}"
  69. Name: "{group}\{cm:UninstallProgram,{#AppName}}"; Filename: "{uninstallexe}"
  70. Name: "{commondesktop}\{#AppName}"; Filename: "{app}\{#AppExeName}"; Tasks: desktopicon
  71. [Run]
  72. Filename: "{app}\{#AppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(AppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
  73. [Code]
  74. var
  75. GlobalRestartRequired: boolean;
  76. function DotNetIsMissing(): Boolean;
  77. var
  78. Exists: Boolean;
  79. Release: Cardinal;
  80. begin
  81. Exists := RegQueryDWordValue(HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full', 'Release', Release);
  82. Result := not Exists or (Release < 378758);
  83. end;
  84. // Adapted from https://blogs.msdn.microsoft.com/davidrickard/2015/07/17/installing-net-framework-4-5-automatically-with-inno-setup/
  85. function InstallDotNet(): String;
  86. var
  87. StatusText: string;
  88. ResultCode: Integer;
  89. begin
  90. StatusText := WizardForm.StatusLabel.Caption;
  91. WizardForm.StatusLabel.Caption := CustomMessage('InstallingDotNetFramework');
  92. WizardForm.ProgressGauge.Style := npbstMarquee;
  93. try
  94. ExtractTemporaryFile('{#DotNetInstallerExe}');
  95. if not Exec(ExpandConstant('{tmp}\{#DotNetInstallerExe}'), '/passive /norestart /showrmui /showfinalerror', '', SW_SHOW, ewWaitUntilTerminated, ResultCode) then
  96. begin
  97. Result := FmtMessage(CustomMessage('DotNetFrameworkFailedToLaunch'), [SysErrorMessage(ResultCode)]);
  98. end
  99. else
  100. begin
  101. // See https://msdn.microsoft.com/en-us/library/ee942965(v=vs.110).aspx#return_codes
  102. case resultCode of
  103. 0: begin
  104. // Successful
  105. end;
  106. 1602 : begin
  107. MsgBox(CustomMessage('DotNetFrameworkFailed1602'), mbInformation, MB_OK);
  108. end;
  109. 1603: begin
  110. Result := CustomMessage('DotNetFrameworkFailed1603');
  111. end;
  112. 1641: begin
  113. GlobalRestartRequired := True;
  114. end;
  115. 3010: begin
  116. GlobalRestartRequired := True;
  117. end;
  118. 5100: begin
  119. Result := CustomMessage('DotNetFrameworkFailed5100');
  120. end;
  121. else begin
  122. MsgBox(FmtMessage(CustomMessage('DotNetFrameworkFailedOther'), [IntToStr(ResultCode)]), mbError, MB_OK);
  123. end;
  124. end;
  125. end;
  126. finally
  127. WizardForm.StatusLabel.Caption := StatusText;
  128. WizardForm.ProgressGauge.Style := npbstNormal;
  129. end;
  130. end;
  131. procedure BumpInstallCount;
  132. var
  133. FileContents: AnsiString;
  134. InstallCount: integer;
  135. begin
  136. { Increment the install count in InstallCount.txt if it exists, or create it with the contents '1' if it doesn't }
  137. if LoadStringFromFile(ExpandConstant('{app}\InstallCount.txt'), FileContents) then
  138. begin
  139. InstallCount := StrTointDef(Trim(string(FileContents)), 0) + 1;
  140. end
  141. else
  142. begin
  143. InstallCount := 1;
  144. end;
  145. SaveStringToFile(ExpandConstant('{app}\InstallCount.txt'), IntToStr(InstallCount), False);
  146. end;
  147. procedure CurStepChanged(CurStep: TSetupStep);
  148. var
  149. FindRec: TFindRec;
  150. FolderPath: String;
  151. FilePath: String;
  152. begin
  153. if CurStep = ssInstall then
  154. begin
  155. BumpInstallCount();
  156. { We might be being run from ProcessRunner.exe, *and* we might be trying to update it. Funsies. Let's rename it (which Windows lets us do) }
  157. DeleteFile(ExpandConstant('{app}\ProcessRunner.exe.old'));
  158. RenameFile(ExpandConstant('{app}\ProcessRunner.exe'), ExpandConstant('{app}\ProcessRunner.exe.old'));
  159. Log(ExpandConstant('Looking for resource files in {app}\*'));
  160. { Remove resource files. This means that out-of-date languages will be removed, which (as a last-ditch resore) will alert maintainers that something's wrong }
  161. if FindFirst(ExpandConstant('{app}\*'), FindRec) then
  162. begin
  163. try
  164. repeat
  165. if (FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY <> 0) and (FindRec.Name <> '.') and (FindRec.Name <> '..') then
  166. begin
  167. FolderPath := ExpandConstant('{app}\') + FindRec.Name;
  168. FilePath := FolderPath + '\SyncTrayzor.resources.dll';
  169. if DeleteFile(FilePath) then
  170. begin
  171. Log('Deleted ' + FilePath);
  172. if DelTree(FolderPath, True, False, False) then
  173. Log('Deleted ' + FolderPath);
  174. end;
  175. end;
  176. until not FindNext(FindRec);
  177. finally
  178. FindClose(FindRec);
  179. end;
  180. end;
  181. end
  182. end;
  183. function PrepareToInstall(var NeedsRestart: Boolean): String;
  184. begin
  185. // 'NeedsRestart' only has an effect if we return a non-empty string, thus aborting the installation.
  186. // If the installers indicate that they want a restart, this should be done at the end of installation.
  187. // Therefore we set the global 'restartRequired' if a restart is needed, and return this from NeedRestart()
  188. if DotNetIsMissing() then
  189. begin
  190. Result := InstallDotNet();
  191. end;
  192. end;
  193. function NeedRestart(): Boolean;
  194. begin
  195. Result := GlobalRestartRequired;
  196. end;
  197. [UninstallDelete]
  198. Type: files; Name: "{app}\ProcessRunner.exe.old"
  199. Type: files; Name: "{app}\InstallCount.txt"
  200. Type: filesandordirs; Name: "{userappdata}\{#AppDataFolder}"
  201. Type: filesandordirs; Name: "{localappdata}\{#AppDataFolder}"