; Script generated by the Inno Setup Script Wizard. ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! #define MyAppVersion "3.3.7" #define MyAppName "UniGetUI" #define MyAppPublisher "Devolutions Inc." #define MyAppURL "https://github.com/Devolutions/UniGetUI" #define MyAppExeName "UniGetUI.exe" #ifndef InstallerCompression #define InstallerCompression "lzma" #endif #define public Dependency_Path_NetCoreCheck "InstallerExtras\" #include "InstallerExtras\CodeDependencies.iss" [Setup] ; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications. ; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) UninstallDisplayName="UniGetUI" AppId={{889610CC-4337-4BDB-AC3B-4F21806C0BDE} AppName={#MyAppName} AppVersion={#MyAppVersion} AppVerName={#MyAppName} {#MyAppVersion} AppPublisher={#MyAppPublisher} AppPublisherURL="https://devolutions.net/unigetui/" AppSupportURL={#MyAppURL} AppUpdatesURL={#MyAppURL} VersionInfoVersion=3.3.7.0 VersionInfoProductVersion=3.3.7.0 DefaultDirName="{autopf64}\UniGetUI" DisableProgramGroupPage=yes DisableDirPage=no DirExistsWarning=no ; Force-close any process holding files we overwrite (backstop for the kill in PrepareToInstall). CloseApplications=force CloseApplicationsFilter=*.exe,*.dll RestartApplications=no ; Default to per-user install mode and let the dialog opt into all-users installs when needed. PrivilegesRequired=lowest PrivilegesRequiredOverridesAllowed=dialog OutputBaseFilename=UniGetUI Installer OutputDir=. ; Comment line below to disable digital signature of installer SignTool=azsign SignedUninstaller=yes SignedUninstallerDir=InstallerExtras\ MinVersion=10.0 SetupIconFile=src\SharedAssets\Assets\Images\icon.ico UninstallDisplayIcon={app}\UniGetUI.exe Compression={#InstallerCompression} SolidCompression=yes WizardStyle=modern dynamic WizardImageFile=InstallerExtras\installer-banner.png WizardImageFileDynamicDark=InstallerExtras\installer-banner.png WizardSmallImageFile=InstallerExtras\unigetui-256.png WizardSmallImageFileDynamicDark=InstallerExtras\unigetui-256.png DisableWelcomePage=no AllowUNCPath=no UsePreviousTasks=yes UsePreviousPrivileges=yes UsePreviousAppDir=yes ChangesEnvironment=yes RestartIfNeededByRun=no Uninstallable=WizardIsTaskSelected('regularinstall') AppModifyPath="{app}\UniGetUI.Installer.exe" /silent /NoDeployInstaller [Languages] Name: "English"; MessagesFile: "compiler:Default.isl" Name: "Armenian"; MessagesFile: "compiler:Languages\Armenian.isl" Name: "BrazilianPortuguese"; MessagesFile: "compiler:Languages\BrazilianPortuguese.isl" Name: "Catalan"; MessagesFile: "compiler:Languages\Catalan.isl" Name: "Corsican"; MessagesFile: "compiler:Languages\Corsican.isl" Name: "Czech"; MessagesFile: "compiler:Languages\Czech.isl" Name: "Danish"; MessagesFile: "compiler:Languages\Danish.isl" Name: "Dutch"; MessagesFile: "compiler:Languages\Dutch.isl" Name: "Finnish"; MessagesFile: "compiler:Languages\Finnish.isl" Name: "French"; MessagesFile: "compiler:Languages\French.isl" Name: "German"; MessagesFile: "compiler:Languages\German.isl" Name: "Hebrew"; MessagesFile: "compiler:Languages\Hebrew.isl" ;Name: "Icelandic"; MessagesFile: "compiler:Languages\Icelandic.isl" Name: "Italian"; MessagesFile: "compiler:Languages\Italian.isl" Name: "Japanese"; MessagesFile: "compiler:Languages\Japanese.isl" Name: "Korean"; MessagesFile: "compiler:Languages\Korean.isl" Name: "Norwegian"; MessagesFile: "compiler:Languages\Norwegian.isl" Name: "Polish"; MessagesFile: "compiler:Languages\Polish.isl" Name: "Portuguese"; MessagesFile: "compiler:Languages\Portuguese.isl" Name: "Russian"; MessagesFile: "compiler:Languages\Russian.isl" Name: "Slovenian"; MessagesFile: "compiler:Languages\Slovenian.isl" Name: "Spanish"; MessagesFile: "compiler:Languages\Spanish.isl" Name: "Turkish"; MessagesFile: "compiler:Languages\Turkish.isl" Name: "Ukrainian"; MessagesFile: "compiler:Languages\Ukrainian.isl" ; Include installer's messages #include "InstallerExtras\CustomMessages.iss" [Code] var PreserveAutostartDisabled: Boolean; // StartupApproved stores the on/off state in the first byte's low bit (03 = off). function IsAutostartDisabledByUser: Boolean; var Data: AnsiString; begin Result := False; if RegQueryBinaryValue(HKEY_CURRENT_USER, 'Software\Microsoft\Windows\CurrentVersion\Explorer\StartupApproved\Run', 'WingetUI', Data) then Result := (Length(Data) >= 1) and ((Ord(Data[1]) and 1) = 1); end; procedure InitializeWizard; begin WizardForm.Bevel.Visible := False; WizardForm.Bevel1.Visible := True; end; // Kills all instances of an image and loops until none remain (taskkill returns 0 while killing, 128 when none left). procedure TaskKillWait(FileName: String); var ResultCode, Attempts: Integer; begin Attempts := 0; repeat if not Exec('taskkill.exe', '/f /im "' + FileName + '"', '', SW_HIDE, ewWaitUntilTerminated, ResultCode) then Break; if ResultCode <> 0 then Break; Sleep(500); Attempts := Attempts + 1; until Attempts >= 10; end; procedure KillRunningApps; begin TaskKillWait('WingetUI.exe'); TaskKillWait('UniGetUI.exe'); TaskKillWait('UniGetUI.Avalonia.exe'); // Elevator (gsudo cache) and pinget live in {app} and lock their own files. TaskKillWait('UniGetUI Elevator.exe'); TaskKillWait('pinget.exe'); Sleep(1000); // let the OS release file handles before copying end; function GetCurrentProcessId: Cardinal; external 'GetCurrentProcessId@kernel32.dll stdcall'; function UpdateMarkerPath(): String; begin Result := ExpandConstant('{app}\.unigetui-update-in-progress'); end; // Marker holds our PID; the app blocks only while this installer runs. Name MUST match UpdateInProgressGuard.MarkerFileName. procedure WriteUpdateMarker; var Pid: Int64; begin ForceDirectories(ExpandConstant('{app}')); Pid := GetCurrentProcessId; SaveStringToFile(UpdateMarkerPath(), IntToStr(Pid), False); end; procedure RemoveUpdateMarker; begin DeleteFile(UpdateMarkerPath()); end; // Runs before any file is copied: shut everything down, then mark the copy window. function PrepareToInstall(var NeedsRestart: Boolean): String; begin // Capture before [Registry] rewrites the Run key, so updates keep the user's choice. PreserveAutostartDisabled := IsAutostartDisabledByUser; KillRunningApps; WriteUpdateMarker; Result := ''; end; // Clear the marker once the copy is done, before the post-install launch. procedure CurStepChanged(CurStep: TSetupStep); begin if CurStep = ssPostInstall then RemoveUpdateMarker; end; function CmdLineParamExists(const Value: string): Boolean; var I: Integer; begin Result := False; for I := 1 to ParamCount do if CompareText(ParamStr(I), Value) = 0 then begin Result := True; Exit; end; end; function IsMSStoreInstall: Boolean; begin Result := CmdLineParamExists('/MSStore'); end; function ShouldInstallVCRedist: Boolean; begin Result := not (CmdLineParamExists('/NoVCRedist') or IsMSStoreInstall); end; function ShouldInstallEdgeWebView: Boolean; begin Result := not (CmdLineParamExists('/NoEdgeWebView') or IsMSStoreInstall); end; function ShouldLaunchAfterInstall: Boolean; begin Result := not (CmdLineParamExists('/NoAutoStart') or IsMSStoreInstall); end; function ShouldSuppressRunOnStartup: Boolean; begin Result := CmdLineParamExists('/NoRunOnStartup') or IsMSStoreInstall or PreserveAutostartDisabled; end; var CustomExitCode: integer; procedure ExitProcess(exitCode:integer); external 'ExitProcess@kernel32.dll stdcall'; procedure DeinitializeSetup(); begin RemoveUpdateMarker; // also clear on abort, before ssPostInstall if (CustomExitCode <> 0) then begin DelTree(ExpandConstant('{tmp}'), True, True, True); ExitProcess(0); end; end; function IsCharValid(Value: Char): Boolean; begin Result := Ord(Value) <= $007F; end; function IsDirNameValid(const Value: string): Boolean; var I: Integer; begin Result := False; for I := 1 to Length(Value) do if not IsCharValid(Value[I]) then Exit; Result := True; end; function NextButtonClick(CurPageID: Integer): Boolean; begin Result := True; if (CurPageID = wpSelectDir) and not IsDirNameValid(WizardForm.DirEdit.Text) then begin Result := False; MsgBox('There is an invalid character in the selected install location. ' + 'Install location cannot contain special characters. ' + 'Please input a valid path to continue, such as '+ExpandConstant('{commonpf64}')+'\UniGetUI', mbError, MB_OK); end; end; function InitializeSetup: Boolean; begin try if ShouldInstallVCRedist then begin Dependency_AddVC2015To2022; end; if ShouldInstallEdgeWebView then begin Dependency_AddWebView2; end; Result := True; except Result := True; end; end; [Tasks] Name: "portableinstall"; Description: "{cm:PortInst}"; GroupDescription: "{cm:InstallType}"; Flags: unchecked exclusive Name: "regularinstall"; Description: "{cm:RegInst}"; GroupDescription: "{cm:InstallType}"; Flags: exclusive Name: "regularinstall\startmenuicon"; Description: "{cm:RegStartMmenuIcon}"; GroupDescription: "{cm:ShCuts}"; Name: "regularinstall\desktopicon"; Description: "{cm:RegDesktopIcon}"; GroupDescription: "{cm:ShCuts}"; [Registry] Root: HKCU; Subkey: "SOFTWARE\Microsoft\Windows\CurrentVersion\Run"; ValueType: string; ValueName: "WingetUI"; ValueData: """{app}\UniGetUI.exe"" --daemon"; Flags: uninsdeletevalue noerror; Tasks: regularinstall; Root: HKCU; Subkey: "Software\Microsoft\Windows\CurrentVersion\Explorer\StartupApproved\Run"; ValueType: binary; ValueName: "WingetUI"; ValueData: "03"; Flags: uninsdeletevalue; Tasks: regularinstall; Check: ShouldSuppressRunOnStartup; // Register the unigetui:// deep link Root: HKA; Subkey: "Software\Classes\unigetui"; ValueType: "string"; ValueData: "URL:UniGetUI Protocol"; Flags: uninsdeletekey; Tasks: regularinstall; Root: HKA; Subkey: "Software\Classes\unigetui"; ValueType: "string"; ValueName: "URL Protocol"; ValueData: ""; Tasks: regularinstall; Root: HKA; Subkey: "Software\Classes\unigetui\DefaultIcon"; ValueType: "string"; ValueData: "{app}\{#MyAppExeName},0"; Tasks: regularinstall; Root: HKA; Subkey: "Software\Classes\unigetui\shell\open\command"; ValueType: "string"; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Tasks: regularinstall; // Register the .ubundle file type Root: HKA; Subkey: "Software\Classes\.ubundle"; ValueType: string; ValueData: "UniGetUI.PackageBundle"; Flags: uninsdeletekey; Tasks: regularinstall; Root: HKA; Subkey: "Software\Classes\UniGetUI.PackageBundle"; ValueType: string; ValueData: {cm:PackageBundleName}; Flags: uninsdeletekey; Tasks: regularinstall; Root: HKA; Subkey: "Software\Classes\UniGetUI.PackageBundle\DefaultIcon"; ValueType: string; ValueData: "{app}\{#MyAppExeName},0"; Flags: uninsdeletekey; Tasks: regularinstall; Root: HKA; Subkey: "Software\Classes\UniGetUI.PackageBundle\shell\open\command"; ValueType: string; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey; Tasks: regularinstall; [InstallDelete] Type: filesandordirs; Name: "{app}\Avalonia" Type: filesandordirs; Name: "{app}\Assets" Type: files; Name: "{app}\WingetUI.exe" Type: files; Name: "{app}\UniGetUI.Avalonia.exe" Type: files; Name: "{app}\*.dll" Type: files; Name: "{app}\*.pdb" Type: files; Name: "{app}\*.pri" Type: files; Name: "{app}\*.xbf" Type: files; Name: "{app}\*.json" [Files] ; Deploy installer for autorepair jobs (unless disabled) Source: "{srcexe}"; DestDir: "{app}"; DestName: "UniGetUI.Installer.exe"; Flags: external ignoreversion; Tasks: regularinstall; Check: not CmdLineParamExists('/NoDeployInstaller'); ; Deploy integrity tree Source: "unigetui_bin\IntegrityTree.json"; DestDir: "{app}"; Flags: createallsubdirs ignoreversion recursesubdirs; ; Deploy executable files (running instances already killed in PrepareToInstall). Source: "unigetui_bin\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion; Source: "unigetui_bin\*"; DestDir: "{app}"; Flags: createallsubdirs ignoreversion recursesubdirs; ; Make installation portable (if required) Source: "InstallerExtras\ForceUniGetUIPortable"; DestDir: "{app}"; Tasks: portableinstall [Icons] Name: "{autostartmenu}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: regularinstall\startmenuicon Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: regularinstall\desktopicon [Run] ; Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -File -NonInteractive ""{tmp}\EnsureWinGet.ps1"""; StatusMsg: "Ensuring WinGet is properly installed... (this may take a while)"; WorkingDir: {app}; Check: not CmdLineParamExists('/NoWinGet'); Flags: runhidden Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: runasoriginaluser nowait postinstall; Check: ShouldLaunchAfterInstall; Filename: "{app}\{#MyAppExeName}"; Parameters: "--migrate-wingetui-to-unigetui"; StatusMsg: "Removing old icons..."; [UninstallRun] ; Remove WingetUI Notification registries ; Filename: "{app}\{#MyAppExeName}"; Parameters: "--uninstall-unigetui"; Flags: skipifdoesntexist runhidden; Filename: {sys}\taskkill.exe; Parameters: "/f /im WingetUI.exe"; Flags: skipifdoesntexist runhidden; RunOnceId: "KillWingetUI" Filename: {sys}\taskkill.exe; Parameters: "/f /im UniGetUI.exe"; Flags: skipifdoesntexist runhidden; RunOnceId: "KillUniGetUI" Filename: {sys}\taskkill.exe; Parameters: "/f /im UniGetUI.Avalonia.exe"; Flags: skipifdoesntexist runhidden; RunOnceId: "KillUniGetUIAvalonia"