Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Pascal

Inno Setup: Cleanup Extra Files

4.65/5 (6 votes)
14 Mar 2018CPOL2 min read 27K   195  
Does your app create extra files post install? Now clean them up!

Introduction

Within its lifecycle, an app can create files and folders which may not be of any value to the user once uninstalled. Common practice is to simply ignore the extras and just uninstall what has been installed. Some of the pitfalls of proceeding any further are mentioned in the comments to this answer, yet the code at ISXKB prompted this author to further expand upon the scenario.

Requirements

The reader is best served by having or at least intending to build an active installation with Inno Setup. Very friendly and intuitive interface, along with extensive documentation. Determine where and how files relating to your app are created, and what purpose they will have once the user is no longer using your software.

Using the Code

Download and paste the code in the code section of the .iss script. The dialog driven script is run when the app is uninstalled.

The chief point of interest is at the bottom of the code where paths containing Inno defined constants can be inserted or removed:

 FileX:= ExpandConstant({Take care these are exactly what are required!}

PrepDeleteOneFile(FileB, False, True, false); // 2nd parm: dir/file, 
                                              // 3rd parm confirm, 4th parm: confirm for many
DeleteManyFiles(FileX, False); // 2nd Parm: dir/file

The following snippet is for a VB compilation:

Pascal
FileA:= ExpandConstant('{userprograms}\{#MyAppName}\*'); //'*' is not recommended
FileB:= ExpandConstant('{userprograms}\{#MyAppName}');
FileC:= ExpandConstant('{app}\{#MyAppName}.log');
FileD:= ExpandConstant('{app}\Process.log');
FileE:= ExpandConstant('{app}\*'); //'*' is not recommended
FileF:= ExpandConstant('{app}');
ExistsB:= FileExists(FileB);
ExistsC:= FileExists(FileC);
ExistsD:= DirExists(FileD);
ExistsF:= DirExists(FileF);

//ask to delete the INI and LOG files
//if ExistsA = true then DeleteManyFiles(FileA);
DeleteManyFiles(FileA, False);
if isEmptyDir(FileA, False) = False And
ExistsB = true then PrepDeleteOneFile(FileB, True, False, False);
if ExistsC = true then PrepDeleteOneFile(FileC, False, False, False);
if ExistsD = true then PrepDeleteOneFile(FileD, False, False, False);
//test to see if MDB files still exists. the MDB files are generated based on
//user ID so we cycle through all the existing databases in the app folder and
//ask the user if they want to delete each one
DeleteManyFiles(+FileF+ '??????XX.mdb', False);
DeleteManyFiles(+FileF+ '{app}\??????YY.mdb', False);
DeleteManyFiles(+FileF+ '{app}\??????ZZ.mdb', False);

//Any Subfolders in MyApp?
if isEmptyDir(FileF, True) = False Then
Begin
DeleteManyFiles(FileE, True);
end;

The Inno Delete Functions work very well, however they only return false on fail, so we can assume in most situations, the reason is either in-use or not accessible.

If an Updater is used (see below), also consider replicating the above code in the Updater, as depending on the Setup & Updater settings, the code can be removed from the setup uninstall binary (typically unins000.exe) when the Updater executes.

Some of the language dialogs were made with Google Translate so any corrections to them are welcome.

Apologies to non Spanish/German/English subscribers, as those languages were the only ones on offer at ISXKB.

Addendum

The following section is for anyone interested using Inno to update an application. An updater is a separate iss script typically run from {tmp} (inno's temp sub-directory for MyApp prefixed is-.) to update the installation {App} from an external source -e.g. an http server.

Updaters do not have an uninstall as such as they are defined to operate on MyApp only, but each time an updater is run from {tmp}, any temporary files related to the install session are created in that folder.

In the usual course of installation, these temporary folders are removed after install, but in the case of updating MyApp, Inno (5.59) generates an (Abort-Ignore-Retry) error when attempting to remove an Updater {srcexe} from {tmp} in the ssPostInstall step with the deleteafterinstall flag thus:

Source: "{tmp}\{#MyAppUpdaterExeName}"; DestDir: "{tmp}"; DestName: "Deletethis{#MyAppUpdaterExeName}";
 Flags: external skipifsourcedoesntexist ignoreversion replacesameversion deleteafterinstall

So here's a method to silently remove it after reboot:

[code]

const
MOVEFILE_DELAY_UNTIL_REBOOT = $00000004;
...
//Decls
function MoveFileEx (lpExistingFileName : string; lpNewFileName : string; dwFlags: Integer): Integer;
 external 'MoveFileExW@kernel32.dll stdcall';

...

procedure CurPageChanged(CurPageID: Integer);
var
iResultCode : Integer;
      // MovefileEx writes the pathname of {scrcexe} to...
      // HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\PendingFileRenameOperations
      // {srcexe} is equivalent to our running updater: {tmp}\{#MyAppUpdaterExeName}
      if (CurPageID=wpFinished) then
      begin
      iResultCode := MoveFileEx(ExpandConstant('{srcexe}'), '', MOVEFILE_DELAY_UNTIL_REBOOT);
      if iResultCode = 0 then
      MsgBox(ExpandConstant('{srcexe}') + NL + ' is not able to be deleted at next reboot! 
                            Reason code: ' + IntToStr(iResultCode) + '.', mbError, MB_OK);
      end;

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)