From 9cdc5ec7d7abdc9e8b74cac0206af8643da0bc87 Mon Sep 17 00:00:00 2001 From: deepend-tildeclub <58404188+deepend-tildeclub@users.noreply.github.com> Date: Mon, 12 Jan 2026 18:36:41 -0700 Subject: [PATCH] Refactor ARM64 installer configuration for ZoiteChat --- win32/installer/zoitechat-arm64.iss | 316 ++++++++++++++++++++++++++-- 1 file changed, 296 insertions(+), 20 deletions(-) diff --git a/win32/installer/zoitechat-arm64.iss b/win32/installer/zoitechat-arm64.iss index 4de9c509..7e98c2ba 100644 --- a/win32/installer/zoitechat-arm64.iss +++ b/win32/installer/zoitechat-arm64.iss @@ -1,29 +1,305 @@ -#define MyAppName "ZoiteChat" -#define MyAppVersion "2.17.0" -#define MyAppPublisher "ZoiteChat" -#define MyAppExeName "zoitechat.exe" +#define APPNAM "ZoiteChat" +#define APPVER "<#= [string]::Join('.', $versionParts) #>" + +; ---- ARM64 build defaults (override via ISCC /D...) ---- +#ifndef APPARCH + #define APPARCH "arm64" +#endif + +#ifndef PROJECTDIR + ; Folder containing wizardimage.bmp / wizardsmallimage.bmp + #define PROJECTDIR "C:\...\zoitechat\win32\installer\" +#endif + +#ifndef SRCDIR + ; Root of your staged tree (must contain bin\, lib\, share\, etc\) + ; In your workflow this is typically: \dist + #define SRCDIR "..\dist" +#endif + +; Inno Download Plugin (kept for consistency) +#include [Setup] -AppId={{A2B6A5B2-2F7A-4D1E-9C0B-ARM64ZOITECHAT}} -AppName={#MyAppName} -AppVersion={#MyAppVersion} -AppPublisher={#MyAppPublisher} -DefaultDirName={autopf}\{#MyAppName} -DefaultGroupName={#MyAppName} -OutputDir=installer\Output -OutputBaseFilename=ZoiteChat-ARM64-Setup -Compression=lzma2 -SolidCompression=yes +AppName={#APPNAM} +AppVersion={#APPVER} +AppVerName={#APPNAM} {#APPVER} +AppPublisher=ZoiteChat +AppPublisherURL=http://zoitechat.github.io +AppCopyright=Copyright (C) 1998-2010 Peter Zelezny +AppSupportURL=https://github.com/zoitechat/zoitechat/issues +AppUpdatesURL=http://zoitechat.github.io/downloads.html +LicenseFile=share\doc\zoitechat\COPYING +UninstallDisplayIcon={app}\zoitechat.exe +UninstallDisplayName={#APPNAM} +; ARM64 = 64-bit Program Files +DefaultDirName={pf64}\ZoiteChat +DefaultGroupName={#APPNAM} +AllowNoIcons=yes +SolidCompression=yes +Compression=lzma2/ultra64 + +; Pull files from staged tree (MSYS2 dist) +SourceDir={#SRCDIR} +OutputDir=.. +OutputBaseFilename={#APPNAM}-{#APPVER}_arm64 + +FlatComponentsList=no +PrivilegesRequired=none +ShowComponentSizes=no +CreateUninstallRegKey=not IsTaskSelected('portable') +Uninstallable=not IsTaskSelected('portable') + +; ARM64-only installer ArchitecturesAllowed=arm64 ArchitecturesInstallIn64BitMode=arm64 -[Files] -Source: "..\dist\*"; DestDir: "{app}"; Flags: recursesubdirs createallsubdirs ignoreversion +; You can keep 6.1, but ARM64 Windows is realistically 10+. +MinVersion=10.0 -[Icons] -Name: "{group}\{#MyAppName}"; Filename: "{app}\bin\{#MyAppExeName}" -Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\bin\{#MyAppExeName}"; Tasks: desktopicon +WizardImageFile={#PROJECTDIR}wizardimage.bmp +WizardSmallImageFile={#PROJECTDIR}wizardsmallimage.bmp +SetupIconFile={#PROJECTDIR}..\..\data\icons\zoitechat.ico + +[Types] +Name: "normal"; Description: "Normal Installation" +Name: "minimal"; Description: "Minimal Installation" +Name: "custom"; Description: "Custom Installation"; Flags: iscustom + +[Components] +Name: "libs"; Description: "ZoiteChat"; Types: normal minimal custom; Flags: fixed +Name: "xctext"; Description: "ZoiteChat-Text"; Types: custom; Flags: disablenouninstallwarning +Name: "xtm"; Description: "ZoiteChat Theme Manager"; Types: normal custom; Flags: disablenouninstallwarning +Name: "icons"; Description: "Create Shortcuts"; Types: custom; Flags: disablenouninstallwarning +Name: "icons\desktopicon"; Description: "Create Desktop Shortcut"; Types: custom; Flags: disablenouninstallwarning +Name: "icons\quicklaunchicon"; Description: "Create Quick Launch Shortcut"; Types: custom; Flags: disablenouninstallwarning +Name: "translations"; Description: "Translations"; Types: normal custom; Flags: disablenouninstallwarning +Name: "spell"; Description: "Spelling Dictionaries"; Types: custom; Flags: disablenouninstallwarning +Name: "plugins"; Description: "Plugins"; Types: custom; Flags: disablenouninstallwarning +Name: "plugins\checksum"; Description: "Checksum"; Types: custom; Flags: disablenouninstallwarning +Name: "plugins\exec"; Description: "Exec"; Types: custom; Flags: disablenouninstallwarning +Name: "plugins\fishlim"; Description: "FiSHLiM"; Types: custom; Flags: disablenouninstallwarning +Name: "plugins\sysinfo"; Description: "SysInfo"; Types: custom; Flags: disablenouninstallwarning +Name: "plugins\upd"; Description: "Update Checker"; Types: normal custom; Flags: disablenouninstallwarning +Name: "plugins\winamp"; Description: "Winamp"; Types: custom; Flags: disablenouninstallwarning +Name: "langs"; Description: "Language Interfaces"; Types: custom; Flags: disablenouninstallwarning +Name: "langs\lua"; Description: "Lua"; Types: normal custom; Flags: disablenouninstallwarning + +; These are kept for consistency, but hidden on ARM64 unless you later ship ARM64 installers for them. +Name: "langs\perl"; Description: "Perl (requires Perl 5.20)"; Types: custom; Flags: disablenouninstallwarning; Check: not IsArm64 +Name: "langs\python"; Description: "Python (requires Python 3.8)"; Types: custom; Flags: disablenouninstallwarning; Check: not IsArm64 [Tasks] -Name: "desktopicon"; Description: "Create a &desktop icon"; GroupDescription: "Additional icons:" +Name: portable; Description: "Yes"; GroupDescription: "Portable Mode: Stores configuration files within install directory for portable drives."; Flags: unchecked + +[Registry] +Root: HKCR; Subkey: "irc"; ValueType: none; ValueName: ""; ValueData: ""; Flags: deletekey uninsdeletekey; Tasks: not portable +Root: HKCR; Subkey: "irc"; ValueType: string; ValueName: ""; ValueData: "URL:IRC Protocol"; Flags: uninsdeletevalue; Tasks: not portable +Root: HKCR; Subkey: "irc"; ValueType: string; ValueName: "URL Protocol"; ValueData: ""; Flags: uninsdeletevalue; Tasks: not portable +Root: HKCR; Subkey: "irc\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\zoitechat.exe,0"; Flags: uninsdeletevalue; Tasks: not portable +Root: HKCR; Subkey: "irc\shell"; ValueType: string; ValueName: ""; ValueData: "open"; Flags: uninsdeletevalue; Tasks: not portable +Root: HKCR; Subkey: "irc\shell\open\command"; ValueType: string; ValueName: ""; ValueData: "{app}\zoitechat.exe --url=""%1"""; Flags: uninsdeletevalue; Tasks: not portable + +Root: HKCR; Subkey: ".hct"; ValueType: none; ValueName: ""; ValueData: ""; Flags: deletekey uninsdeletekey; Components:xtm; Tasks: not portable +Root: HKCR; Subkey: ".hct"; ValueType: string; ValueName: ""; ValueData: "ZoiteChat Theme File"; Flags: uninsdeletevalue; Components:xtm; Tasks: not portable +Root: HKCR; Subkey: ".hct"; ValueType: string; ValueName: "ZoiteChat Theme File"; ValueData: ""; Flags: uninsdeletevalue; Components:xtm; Tasks: not portable +Root: HKCR; Subkey: ".hct\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\thememan.exe,0"; Flags: uninsdeletevalue; Components:xtm; Tasks: not portable +Root: HKCR; Subkey: ".hct\shell"; ValueType: string; ValueName: ""; ValueData: "open"; Flags: uninsdeletevalue; Components:xtm; Tasks: not portable +Root: HKCR; Subkey: ".hct\shell\open\command"; ValueType: string; ValueName: ""; ValueData: "{app}\thememan.exe ""%1"""; Flags: uninsdeletevalue; Components:xtm; Tasks: not portable + +[Run] +Filename: "{app}\zoitechat.exe"; Description: "Run ZoiteChat after closing the Wizard"; Flags: nowait postinstall skipifsilent +Filename: "http://docs.zoitechat.org/en/latest/changelog.html"; Description: "See what's changed"; Flags: shellexec runasoriginaluser postinstall skipifsilent unchecked + +; VC++ redist (ARM64) +Filename: "{tmp}\vcredist.exe"; Parameters: "/install /quiet /norestart"; StatusMsg: "Installing Visual C++ Redistributable"; Flags: skipifdoesntexist; Tasks: not portable + +; Old x86/x64 extras intentionally omitted on ARM64 +; (dotnet/perl/python/spelling-dicts) – keep your existing behavior on x86/x64 installers. + +[Files] +; Portable marker (same behavior) +Source: "portable-mode"; DestDir: "{app}"; Tasks: portable; Flags: skipifsourcedoesntexist + +; Optional URLs/cert (don’t fail if your dist doesn’t include them) +Source: "changelog.url"; DestDir: "{app}"; Flags: ignoreversion skipifsourcedoesntexist; Components: libs +Source: "readme.url"; DestDir: "{app}"; Flags: ignoreversion skipifsourcedoesntexist; Components: libs +Source: "cert.pem"; DestDir: "{app}"; Flags: ignoreversion skipifsourcedoesntexist; Components: libs + +; ---- Core binaries + runtime DLLs ---- +; We install bin\ contents into {app} to match the non-ARM installer layout. +Source: "bin\zoitechat.exe"; DestDir: "{app}"; Flags: ignoreversion +Source: "bin\zoitechat-text.exe"; DestDir: "{app}"; Flags: ignoreversion skipifsourcedoesntexist; Components: xctext +Source: "bin\thememan.exe"; DestDir: "{app}"; Flags: ignoreversion skipifsourcedoesntexist; Components: xtm + +; All staged DLLs/helpers shipped alongside the EXE (your CI harvest step should have copied deps into bin\) +Source: "bin\*.dll"; DestDir: "{app}"; Flags: ignoreversion skipifsourcedoesntexist; Components: libs +Source: "bin\gspawn-*.exe"; DestDir: "{app}"; Flags: ignoreversion skipifsourcedoesntexist; Components: libs + +; ---- Shared data ---- +Source: "share\xml\*"; DestDir: "{app}\share\xml"; Flags: ignoreversion createallsubdirs recursesubdirs skipifsourcedoesntexist; Components: libs +Source: "share\doc\*"; DestDir: "{app}\share\doc"; Flags: ignoreversion createallsubdirs recursesubdirs skipifsourcedoesntexist; Components: libs +Source: "share\themes\*"; DestDir: "{app}\share\themes"; Flags: ignoreversion createallsubdirs recursesubdirs skipifsourcedoesntexist; Components: libs +Source: "etc\fonts\*"; DestDir: "{app}\etc\fonts"; Flags: ignoreversion createallsubdirs recursesubdirs skipifsourcedoesntexist; Components: libs + +; Translations split out like the original installer +Source: "share\locale\*"; DestDir: "{app}\share\locale"; Flags: ignoreversion createallsubdirs recursesubdirs skipifsourcedoesntexist; Components: translations + +; ---- Plugins (staged under lib\zoitechat\plugins\*.dll) ---- +; Map them to {app}\plugins like the existing Windows installs. +Source: "lib\zoitechat\plugins\*checksum*.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion skipifsourcedoesntexist; Components: plugins\checksum +Source: "lib\zoitechat\plugins\*exec*.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion skipifsourcedoesntexist; Components: plugins\exec +Source: "lib\zoitechat\plugins\*fishlim*.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion skipifsourcedoesntexist; Components: plugins\fishlim +Source: "lib\zoitechat\plugins\*sysinfo*.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion skipifsourcedoesntexist; Components: plugins\sysinfo +Source: "lib\zoitechat\plugins\*upd*.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion skipifsourcedoesntexist; Components: plugins\upd +Source: "lib\zoitechat\plugins\*winamp*.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion skipifsourcedoesntexist; Components: plugins\winamp +Source: "lib\zoitechat\plugins\*lua*.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion skipifsourcedoesntexist; Components: langs\lua + +; Python integration (only if you actually stage these on ARM64) +Source: "lib\zoitechat\plugins\*python*.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion skipifsourcedoesntexist; Components: langs\python +Source: "python\*.py"; DestDir: "{app}\python"; Flags: ignoreversion skipifsourcedoesntexist; Components: langs\python +Source: "_cffi_backend.cp3*.pyd"; DestDir: "{app}"; Flags: ignoreversion skipifsourcedoesntexist; Components: langs\python + +[Icons] +Name: "{group}\ZoiteChat"; Filename: "{app}\zoitechat.exe"; AppUserModelID: "ZoiteChat.Desktop.Notify"; Tasks: not portable; Check: not WizardNoIcons +Name: "{group}\ZoiteChat Safe Mode"; Filename: "{app}\zoitechat.exe"; Parameters: "--no-auto --no-plugins"; Tasks: not portable; Check: not WizardNoIcons +Name: "{group}\ZoiteChat ChangeLog"; Filename: "{app}\changelog.url"; IconFilename: "{sys}\shell32.dll"; IconIndex: 165; Tasks: not portable; Check: not WizardNoIcons +Name: "{group}\ZoiteChat ReadMe"; Filename: "{app}\readme.url"; IconFilename: "{sys}\shell32.dll"; IconIndex: 23; Tasks: not portable; Check: not WizardNoIcons +Name: "{group}\ZoiteChat Config Folder"; Filename: "%APPDATA%\ZoiteChat\"; Tasks: not portable; Check: not WizardNoIcons +Name: "{group}\ZoiteChat-Text"; Filename: "{app}\zoitechat-text.exe"; Components: xctext; Tasks: not portable; Check: not WizardNoIcons +Name: "{group}\ZoiteChat Theme Manager"; Filename: "{app}\thememan.exe"; Components: xtm; Tasks: not portable; Check: not WizardNoIcons +Name: "{group}\Uninstall ZoiteChat"; Filename: "{uninstallexe}"; Tasks: not portable; Check: not WizardNoIcons +Name: "{commondesktop}\ZoiteChat"; Filename: "{app}\zoitechat.exe"; AppUserModelID: "ZoiteChat.Desktop.Notify"; Components: icons\desktopicon; Tasks: not portable +Name: "{commonappdata}\Microsoft\Internet Explorer\Quick Launch\ZoiteChat"; Filename: "{app}\zoitechat.exe"; Components: icons\quicklaunchicon; Tasks: not portable + +[Messages] +BeveledLabel= {#APPNAM} + +[Code] +procedure InitializeWizard; +begin + WizardForm.LicenseAcceptedRadio.Checked := True; + idpDownloadAfter(wpReady); +end; + +function GetSysDir(): String; +begin + ; ARM64 is 64-bit, so {sys} is correct + Result := ExpandConstant('{sys}\'); +end; + +function CheckVCInstall(): Boolean; +begin + Result := FileExists(GetSysDir() + 'vcruntime140.dll'); +end; + +procedure CurPageChanged(CurPageID: Integer); +var + REDIST: String; +begin + if (CurPageID = wpReady) then + begin + idpClearFiles; + + if not IsTaskSelected('portable') then + begin + ; VC++ 2015-2022 ARM64 redistributable (stable official URL) + REDIST := 'https://aka.ms/vs/17/release/vc_redist.arm64.exe'; + + if not CheckVCInstall() then + idpAddFile(REDIST, ExpandConstant('{tmp}\vcredist.exe')); + end; + end; +end; + +function NextButtonClick(CurPageID: Integer): Boolean; +begin + if (CurPageID = wpSelectTasks) then + if (WizardForm.TasksList.Checked[1] = True) then + if (WizardDirValue() = ExpandConstant('{pf64}\ZoiteChat')) then + begin + WizardForm.TasksList.Checked[1] := False; + MsgBox('Portable mode is only intended for use on portable drives and has been disabled.', mbInformation, MB_OK); + end; + + Result := True; +end; + +function GetUninstallString(): String; +var + sUnInstPath: String; + sUnInstallString: String; +begin + sUnInstallString := ''; + + ; Prefer ARM64 entry, but also handle migrating from x64/x86 installs on ARM devices. + sUnInstPath := 'Software\Microsoft\Windows\CurrentVersion\Uninstall\ZoiteChat (ARM64)_is1'; + if not RegQueryStringValue(HKLM, sUnInstPath, 'UninstallString', sUnInstallString) then + RegQueryStringValue(HKCU, sUnInstPath, 'UninstallString', sUnInstallString); + + if sUnInstallString = '' then + begin + sUnInstPath := 'Software\Microsoft\Windows\CurrentVersion\Uninstall\ZoiteChat (x64)_is1'; + if not RegQueryStringValue(HKLM, sUnInstPath, 'UninstallString', sUnInstallString) then + RegQueryStringValue(HKCU, sUnInstPath, 'UninstallString', sUnInstallString); + end; + + if sUnInstallString = '' then + begin + sUnInstPath := 'Software\Microsoft\Windows\CurrentVersion\Uninstall\ZoiteChat (x86)_is1'; + if not RegQueryStringValue(HKLM, sUnInstPath, 'UninstallString', sUnInstallString) then + RegQueryStringValue(HKCU, sUnInstPath, 'UninstallString', sUnInstallString); + end; + + if sUnInstallString = '' then + begin + sUnInstPath := 'Software\Microsoft\Windows\CurrentVersion\Uninstall\ZoiteChat_is1'; + if not RegQueryStringValue(HKLM32, sUnInstPath, 'UninstallString', sUnInstallString) then + if not RegQueryStringValue(HKCU32, sUnInstPath, 'UninstallString', sUnInstallString) then + if IsWin64 then + if not RegQueryStringValue(HKLM64, sUnInstPath, 'UninstallString', sUnInstallString) then + RegQueryStringValue(HKCU64, sUnInstPath, 'UninstallString', sUnInstallString); + end; + + Result := sUnInstallString; +end; + +function IsUpgrade(): Boolean; +begin + Result := (GetUninstallString() <> ''); +end; + +function UnInstallOldVersion(): Integer; +var + sUnInstallString: String; + iResultCode: Integer; +begin + Result := 0; + sUnInstallString := GetUninstallString(); + + if sUnInstallString <> '' then + begin + sUnInstallString := RemoveQuotes(sUnInstallString); + if Exec(sUnInstallString, '/VERYSILENT /NORESTART /SUPPRESSMSGBOXES', '', SW_HIDE, ewWaitUntilTerminated, iResultCode) then + Result := 3 + else + Result := 2; + end + else + Result := 1; +end; + +procedure CurStepChanged(CurStep: TSetupStep); +begin + if not IsTaskSelected('portable') then + begin + if (CurStep = ssInstall) then + begin + if IsUpgrade() then + UnInstallOldVersion(); + + DeleteFile(ExpandConstant('{app}\portable-mode')); + end; + end; +end;