Thursday, February 7, 2013

Inno Setup: Deleting files during install

Deleting files selectively can be a daunting task with Inno Setup. Especially if the sequence presented is Backup the files, then delete them before the new ones are copied on top. In my previous posts I mentioned steps how to take a backup of files and here are some details on how to delete files from a particular folder or for that matter, based on a pattern. This may be necessary on several occasions:
  1. On a Windows system, especially some versions of the OS may be buggy. You copy new DLLs over existing ones and the system doesn't acknowledge - keeps using the old DLLs. Especially observed on some Windows 2003 Servers when the number of arguments in a function defined inside the DLL was varied and a new DLL copied over. This kind of thing happens rarely but when it strikes, you can spend hours star gazing. The solution is to delete the DLLs and copy new ones over.
  2. New files you are copying may be fewer and you dont want old junk in the folder.
Here it goes:

Step #1: Add a function call in the install directives. I will explain the arguments and why the complexity in a bit...

Check:DeleteFiles(ExpandConstant('{app}\\bin\*'), ExpandConstant('{#InstallHomeDir}\UnInstall\{#MyAppVersion}\Websites\\bin'));


Step #2: Create a function to delete the files. 

function DeleteFiles(pattern,dirToCheck:String):Boolean;
var
  i,alen:Integer;
begin
  
  // We will run ONLY if exists condition is satisfied
  if not DirExists(dirToCheck) then begin
    result := true;
    exit;
  end;

  alen := GetArrayLength(DirArray);
  for i := 0 to alen -1 do begin
    if CompareText(pattern, DirArray[i]) = 0 then begin
      result := true;
      exit;
    end;
  end;
  //MsgBox(pattern, mbError, MB_OK);
  DelTree(pattern, false, true, false);
  SetArrayLength(DirArray, alen+1);
  DirArray[alen] := Copy(pattern,0,length(pattern));
  result := true;
end;

Importance of the second argument: You should know by now that Inno Setup calls all the Check functions BEFORE it calls any File directives. This means that if you are making any backups, the Check function above which deletes the files can delete the files BEFORE the backup ever happens. The second argument tells the function where to look if the files have been backed up before they are deleted. If the backup folder exists, that means the files must have been copied (you can extend that check any way you want). The array used in the delete function is also important. The delete must be done ONLY once before the code is installed. The function may be called again by InnoSetup and if the delete kicks in again, you can kiss your installed files goodbye!

3 comments:

Rich Coleman said...

I get "Unknown identifier 'DirArray'." Am I missing something?

Medhavi said...

Good point, use this to declare the variable.

DirArray: array of String;

Wayne said...

Hi
Interesting way of implementing.
I have a [InstallDelete] section
and use:

Type: filesandordirs; Name: c:\MyApp\users ; Tasks: deleteuserfiles

and a [Task]
Name: deleteuserfiles; Description: Remove any existing user settings; Flags: unchecked

which works for me.

Is there a way to delete registry keys in the [InstallDelete] section?

Wayne