#define MyAppName "pgAdmin 4" #define MyAppVersion MYAPP_VERSION #define MyAppPublisher "The pgAdmin Development Team" #define MyAppURL "www.pgadmin.org" #define MyAppExeName "pgAdmin4.exe" #define MyAppID "C14F64E7-DCB9-4DE1-8560-16F08FCFF64E" #define MyAppFullVersion MYAPP_FULLVERSION #define MyAppArchitecturesMode "x64" #define MyAppVCDist MYAPP_VCDIST #define MyAppInvalidPath "Please provide a valid path." #define MyAppErrorMsgIsWin32 "You already have a 32 bit installation of pgAdmin 4. Please uninstall this before installing the 64 bit version." #define MyAppErrorMsgIsWin64 "You already have a 64 bit installation of pgAdmin 4. Please uninstall this before installing the 32 bit version." #define MinimumWindowsVer "6.2.9200" [Setup] AppId={#MyAppName}{#MyAppVersion} AppName={#MyAppName} AppVersion={#MyAppFullVersion} AppPublisher={#MyAppPublisher} AppPublisherURL={#MyAppURL} AppSupportURL={#MyAppURL} AppUpdatesURL={#MyAppURL} DefaultDirName={autopf}\{#MyAppName}\{#MyAppVersion} DefaultGroupName={#MyAppName} DisableWelcomePage=no DisableProgramGroupPage=auto LicenseFile=Resources\license.rtf OutputBaseFilename=pgadmin4-setup SetupIconFile=Resources\pgAdmin4.ico Compression=lzma SolidCompression=yes PrivilegesRequired=lowest PrivilegesRequiredOverridesAllowed=dialog ChangesEnvironment=yes UninstallDisplayIcon={app}\runtime\{#MyAppExeName} ArchitecturesInstallIn64BitMode={#MyAppArchitecturesMode} AllowNoIcons=yes WizardImageFile=sidebar.bmp MinVersion={#MinimumWindowsVer} [Languages] Name: "english"; MessagesFile: "compiler:Default.isl" ;This section will override the standard error message by default which is called internally and we don't have a control over this. [Messages] InvalidPath={#MyAppInvalidPath} ;This section would be used for customized error message display. [CustomMessages] english.NewerVersionExists=A newer version of {#MyAppName} english.InvalidPath={#MyAppInvalidPath} [Icons] Name: {group}\{#MyAppName} {#MyAppVersion}; Filename: {app}\runtime\{#MyAppExeName}; IconFilename: {app}\pgAdmin4.ico; WorkingDir: {app}\runtime; [Files] Source: "..\..\win-build\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs; [Run] Filename: "{app}\installer\{#MyAppVCDist}"; StatusMsg: "VC runtime redistributable package"; Parameters: "/passive /verysilent /norestart"; Check: InstallVC; [Registry] Root: HKA; Subkey: "Software\{#MyAppName}\{#MyAppVersion}"; Flags: uninsdeletekeyifempty Root: HKA; Subkey: "Software\{#MyAppName}\{#MyAppVersion}"; Flags: uninsdeletekey Root: HKA; Subkey: "Software\{#MyAppName}\{#MyAppVersion}"; ValueType: string; ValueName: "InstallPath"; ValueData: "{app}" Root: HKA; Subkey: "Software\{#MyAppName}\{#MyAppVersion}"; ValueType: string; ValueName: "Version"; ValueData: "{#MyAppFullVersion}" [Code] var UpgradeMode: Boolean; // Procedure to split a string into an array of integers procedure Explode(var Dest: TArrayOfInteger; Text: String; Separator: String); var i, p: Integer; begin i := 0; repeat SetArrayLength(Dest, i+1); p := Pos(Separator,Text); if p > 0 then begin Dest[i] := StrToInt(Copy(Text, 1, p-1)); Text := Copy(Text, p + Length(Separator), Length(Text)); i := i + 1; end else begin Dest[i] := StrToInt(Text); Text := ''; end; until Length(Text)=0; end; // Function compares version strings numerically: // * when v1 = v2, result = 0 // * when v1 < v2, result = -1 // * when v1 > v2, result = 1 // // Supports version numbers with trailing zeroes, for example 1.02.05. // Supports comparison of two version number of different lengths, // for example CompareVersions('1.2', '2.0.3') // When any of the parameters is '' (empty string) it considers version // number as 0 function CompareVersions(v1: String; v2: String): Integer; var v1parts: TArrayOfInteger; v2parts: TArrayOfInteger; i: Integer; begin if v1 = '' then begin v1 := '0'; end; if v2 = '' then begin v2 := '0'; end; Explode(v1parts, v1, '.'); Explode(v2parts, v2, '.'); if (GetArrayLength(v1parts) > GetArrayLength(v2parts)) then begin SetArrayLength(v2parts, GetArrayLength(v1parts)) end else if (GetArrayLength(v2parts) > GetArrayLength(v1parts)) then begin SetArrayLength(v1parts, GetArrayLength(v2parts)) end; for i := 0 to GetArrayLength(v1parts) - 1 do begin if v1parts[i] > v2parts[i] then begin { v1 is greater } Result := 1; exit; end else if v1parts[i] < v2parts[i] then begin { v2 is greater } Result := -1; exit; end; end; { Are Equal } Result := 0; end; function IsPathValid(Path: string): Boolean; var I: Integer; Ret: Boolean; begin Ret := True; Path := Uppercase(Path); Result := (Length(Path) >= 3) and (Path[1] >= 'A') and (Path[1] <= 'Z') and (Path[2] = ':') and (Path[3] = '\'); if Result then begin for I := 3 to Length(Path) do begin case Path[I] of '0'..'9', 'A'..'Z', '\', ' ', '.', '-', '_', '(', ')': else begin Ret := False; break; end; end; end; end; Result := Ret; end; function CheckPgAdminAlreadyInstalled: Boolean; var Version: String; InstallationFound: Boolean; begin InstallationFound := False; // Check the installation mode 64 or 32 bit of installer if Is64BitInstallMode then begin // Check if pgAdmin 32 bit is already installed RegQueryStringValue(HKLM32,'Software\{#MyAppName}\{#MyAppVersion}', 'Version', Version); // If version is found then shouldn't install 64bit - abort if Length(Version) > 0 then begin MsgBox(ExpandConstant('{#MyAppErrorMsgIsWin32}'), mbCriticalError, MB_OK); Result := False; InstallationFound := True; end; end else begin // Suppose system is running a 32-bit version of Windows then no need to check HKLM64 in RegQueryStringValue // So IsWin64 - will make sure its should only execute on 64-bit version of windows. if IsWin64 then begin // Check if pgAdmin 64 bit is already installed RegQueryStringValue(HKLM64,'Software\{#MyAppName}\{#MyAppVersion}', 'Version', Version); // If version is found the shouldn't install 32bit - abort if Length(Version) > 0 then begin MsgBox(ExpandConstant('{#MyAppErrorMsgIsWin64}'), mbCriticalError, MB_OK); Result := False; InstallationFound := True; end; end; end; if not (InstallationFound) then begin if RegValueExists(HKEY_LOCAL_MACHINE,'Software\{#MyAppName}\{#MyAppVersion}', 'Version') then begin UpgradeMode := True; RegQueryStringValue(HKEY_LOCAL_MACHINE,'Software\{#MyAppName}\{#MyAppVersion}', 'Version', Version); if CompareVersions(Version, '{#MyAppFullVersion}') = 1 then begin MsgBox(ExpandConstant('{cm:NewerVersionExists}' + '(v' + Version + ') is already installed' ), mbInformation, MB_OK); Result := False; end else begin Result := True; end; end; end; if ( not (InstallationFound) and not (UpgradeMode) ) then begin // This is required as it will be passed on to the InitializeSetup function Result := True; end; end; // Find current version before installation function InitializeSetup: Boolean; begin Result := CheckPgAdminAlreadyInstalled; end; function IsUpgradeMode(): Boolean; begin Result := UpgradeMode; end; function InstallVC: Boolean; begin Result := True; end; // This function would be called during upgrade mode // In upgrade mode - delete web/* and exclude config_local.py procedure DelWebfolder(Path: string); var FindRec: TFindRec; FilePath: string; begin if FindFirst(Path + '\*', FindRec) then begin try repeat if (FindRec.Name <> '.') and (FindRec.Name <> '..') then begin FilePath := Path + '\' + FindRec.Name; if FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY = 0 then begin if CompareText(FindRec.Name, 'config_local.py') <> 0 then begin DeleteFile(FilePath); end end else begin DelWebfolder(FilePath); RemoveDir(FilePath); end; end; until not FindNext(FindRec); finally FindClose(FindRec); end; end; end; // This function would be called during upgrade mode // In upgrade mode - delete python/* for example procedure DelFolder(Path: string); var FindRec: TFindRec; FilePath: string; begin if FindFirst(Path + '\*', FindRec) then begin try repeat if (FindRec.Name <> '.') and (FindRec.Name <> '..') then begin FilePath := Path + '\' + FindRec.Name; if FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY = 0 then begin DeleteFile(FilePath); end else begin DelFolder(FilePath); RemoveDir(FilePath); end; end; until not FindNext(FindRec); finally FindClose(FindRec); end; end; end; //procedure CurPageChanged(CurPageID: Integer); function NextButtonClick(CurPageID: Integer): Boolean; var Ret: Boolean; begin Ret := True; case CurPageID of wpSelectDir: begin // Validate InstallDir path if Not IsPathValid(ExpandConstant('{app}')) then begin MsgBox(ExpandConstant('{cm:InvalidPath}'), mbError, MB_OK); Ret := False; end; end; wpReady: begin if (IsUpgradeMode) then begin DelWebfolder(ExpandConstant('{app}\web')); DelFolder(ExpandConstant('{app}\python')); end; end; end; Result := Ret; end; // End of program