Suppose you are using an Inno Setup project to replace existing files. When running the uninstaller it will delete the new files, instead of the expected behavior of restoring the previous ones.
Here is my implementation of a backup & restore mechanism:
1. For each file to be backed up, add a ‘Check’ parameter with the name of your backup function. This function will be called just before installing the file so we can use it to perform the backup.
2. Implement the backup function to perform the backup. Make sure to return True if everything’s OK and the file can be replaced.
3. Implement the restore function by copying all files from backup to the original location.
4. Call the restore function during uninstall (post-uninstall, after the new files have been removed).
Here is a sample Inno Setup script that implements this mechanism. In this example, the backup function supports backing up the entire folder structure, so restoring them to the original location is easy (using xcopy).
; Script generated by the Inno Setup Script Wizard. ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! #define MyAppName "TestBackupRestore" #define MyAppVersion "1.0" #define MyAppPublisher "yossiz74" #define MyAppURL "https://adventuresinscm.wordpress.com/" [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.) AppId={{DA07C52A-E107-4F08-897E-9394690B7C7F} AppName={#MyAppName} AppVersion={#MyAppVersion} ;AppVerName={#MyAppName} {#MyAppVersion} AppPublisher={#MyAppPublisher} AppPublisherURL={#MyAppURL} AppSupportURL={#MyAppURL} AppUpdatesURL={#MyAppURL} DefaultDirName={pf}\{#MyAppName} DisableDirPage=yes DefaultGroupName={#MyAppName} DisableProgramGroupPage=yes OutputBaseFilename=setup Compression=lzma SolidCompression=yes SetupLogging=yes CreateUninstallRegKey=no [Languages] Name: "english"; MessagesFile: "compiler:Default.isl" [Dirs] Name: "{app}\log" Name: "{app}\conf" [Files] Source: "F:\Temp\StructuredQuery.log"; DestDir: "{app}\log"; Flags: ignoreversion; Check: FileBackup Source: "F:\Temp\browserinfo.ini"; DestDir: "{app}\conf"; Flags: ignoreversion; Check: FileBackup ; NOTE: Don't use "Flags: ignoreversion" on any shared system files [Icons] Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}" [Code] var BackupDir: String; function FileBackup(): Boolean; var FileName,Source,Target,TargetDir: String; begin Result := True; Source := ExpandConstant(CurrentFileName); if not FileExists(Source) then begin Result := True; end else begin FileName := ExtractRelativePath(ExpandConstant('{app}') + '\',Source); Target := BackupDir + '\' + FileName; TargetDir := ExtractFilePath(Target); if not DirExists(TargetDir) then if not CreateDir(TargetDir) then Result := False if Result then begin if FileExists(Target) then // Keep original backup Result := True else Result := FileCopy(Source,Target,False); end; end; end; function RestoreFiles(): Boolean; var ResultCode: Integer; var CommandLine: String; begin CommandLine := '/sry "' + BackupDir + '"\* "' + ExpandConstant('{app}') + '"'; Exec('xcopy', CommandLine, '', SW_HIDE, ewWaitUntilTerminated, ResultCode); Result := (ResultCode = 0); end; procedure CurStepChanged(CurStep: TSetupStep); begin if CurStep = ssInstall then begin BackupDir := ExpandConstant('{app}\Backup'); CreateDir(BackupDir); end; end; procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep); begin if CurUninstallStep = usUninstall then BackupDir := ExpandConstant('{app}\Backup'); if CurUninstallStep = usPostUninstall then RestoreFiles(); end;
when i try to use your code.. it shows an error on line ” if Result then begin”..
can you please help me with it? thank a lot..
Note sure, I’ve just copied the code from the post to a completely new empty script and it builds successfully.
I’ve sent you an email so we can take it offline.
Many thanks for this wonderful code block, It works great. Just a small question though, to make a backup of files, the code looks for the filename existing in the Source and then look for same file in {app} directory. How to deal with cases where {app} directories has extra files (probably the files which were deleted in Source in new installation), as those filenames are not present in Source, hence the backup does not get those files.
Many thanks again, looking forward to your suggestion.
If I understand your question correctly, that depends on your upgrade policy.
The mechanism I suggested is intended for an ‘in-place’ upgrade – so files which existed beforehand, but are not in Source, would simply remain there, and nothing got lost.
However if you delete the {app} folder before installing the updated files, then instead of this method you will need to backup the entire folder (and restore it upon rollback), since you cannot know in advance which files currently exist there. Of course, if you know that you should only backup certain files (e.g. based on specified wildcards) you can write a code to scan the existing folders, and backup all those files.
I hope this answers your question.
Hi, I would like to know how to delete the backup after it has been restored.
Hi,
You can add
RemoveDir(BackupDir)
after the call toRestoreFiles()