How to get Inno Setup to unzip a file it installed (all as part of the one installation process)
Asked Answered
S

5

22

To save bandwidth/space as well as prevent accidental meddling, the installation files for a database product (call it Ajax), have been zipped up (call that file AJAX_Install_Files.ZIP). I would like to have Inno Setup "install" (i.e., copy) the AJAX_Install_Files.ZIP file to the destination, and then Unzip the files into the same folder where the .ZIP file is located. A subsequent program would be fired off by Inno Setup to actually run the install of product "Ajax".

I've looked through the documentation, FAQ, and KB at the Inno Setup website, and this does not seem possible other than writing a Pascal script (code) – would that be correct, or are there are any alternative solutions?

Subinfeudation answered 19/5, 2011 at 22:5 Comment(1)
Don't. Innosetup itself compresses the files, and there's no benefit to double-compressing these files. It just slows down the install, requires more code, more disk space during installation, and adds failure modes to the process.Rokach
B
27

You can use an external command line tool for unzipping your archive, see here for example. Put it in your [Files] section:

[Files]
Source: "UNZIP.EXE"; DestDir: "{tmp}"; Flags: deleteafterinstall

Then call it in your [Run] section, like this:

[Run]
Filename: "{tmp}\UNZIP.EXE"; Parameters: "{tmp}\ZipFile.ZIP -d C:\TargetDir"

(You'll probably want to take your target directory from a script variable, so there is some more work that needs to be done)

Baier answered 3/6, 2011 at 9:9 Comment(4)
Is there any way to hide logs showed in the screen?Saltsman
@TalyssondeCastro Use Flags: runhidden.Pinto
Correct, BUT I needed to add quotes around the .zip and target dir. To do this, you have to escape with annother set of quotes so it looked like: """{tmp}\ZipFile.ZIP"" -d ""C:\TargetDir"""Boyar
Keep in mind, you should add the -o flag when unzipping. Otherwise this process will hang indefinitely if a file needs to be overwritten.Mcfadden
P
15

You can use the shell Folder.CopyHere method to extract a ZIP.

const
  SHCONTCH_NOPROGRESSBOX = 4;
  SHCONTCH_RESPONDYESTOALL = 16;

procedure UnZip(ZipPath, TargetPath: string); 
var
  Shell: Variant;
  ZipFile: Variant;
  TargetFolder: Variant;
begin
  Shell := CreateOleObject('Shell.Application');

  ZipFile := Shell.NameSpace(ZipPath);
  if VarIsClear(ZipFile) then
    RaiseException(
      Format('ZIP file "%s" does not exist or cannot be opened', [ZipPath]));

  TargetFolder := Shell.NameSpace(TargetPath);
  if VarIsClear(TargetFolder) then
    RaiseException(Format('Target path "%s" does not exist', [TargetPath]));

  TargetFolder.CopyHere(
    ZipFile.Items, SHCONTCH_NOPROGRESSBOX or SHCONTCH_RESPONDYESTOALL);
end;

Note that the flags SHCONTCH_NOPROGRESSBOX and SHCONTCH_RESPONDYESTOALL work on Windows Vista and newer.


You can use the function for example like this:

[Files]
Source: "archive.zip"; DestDir: "{tmp}"; AfterInstall: UnZipCurrentFileTo('{app}')

Place this auxiliary function below UnZip:

procedure UnZipCurrentFileTo(TargetPath: string);
begin
  UnZip(ExpandConstant(CurrentFileName), ExpandConstant(TargetPath));
end;

Though if you would use it just once, you can instead do:

[Files]
Source: "archive.zip"; DestDir: "{tmp}"; \
 AfterInstall: UnZip(ExpandConstant('{tmp}\archive.zip'), ExpandConstant('{app}'))

For an example of extracting some files only, see:
How to get Inno Setup to unzip a single file?

Pinto answered 20/11, 2016 at 16:35 Comment(2)
Slick, but locks up the UI if the zip file is large. Though, the script could be packaged as a .ps1 file and launched in the same manner as this example launches 7zip: gist.github.com/jakoch/33ac13800c17eddb2dd4Flue
I've added this as an extra example to the official CodeAutomation.iss example script.Shilohshim
F
8

I answered a very similar question and some of the details apply.

I would question why you need a ZIP file of the contents? I personally would place the uncompressed files into the setup. I would then have two [category] entries one for the application and one for the data. Default both the be checked.

This would allow the users to install a fresh set of the data if needed at a later date.

If you really want a ZIP file and want to keep it easy you could, ship both the zip files and the uncompressed files in the same setup.

Update:

By default files that get placed in your setup.exe are compressed.

You can also have the files extracted to a temporary location so you can run your installation application, then have them deleted.

[Files]
Source: "Install1.SQL"; DestDir: "{tmp}"; Flags:deleteafterinstall;
Source: "Install2.SQL"; DestDir: "{tmp}"; Flags:deleteafterinstall;
Future answered 19/5, 2011 at 23:25 Comment(2)
Why a zip of the contents - because that is how the files are supplied to me, & I think it is much easier to deal with a single .ZIP file rather than the 2,000 plus files saved in the .ZIP file. This .ZIP file is the installation and data for just one program of a multiple program installation that I am attempting to automate. Once I get the files "installed" (actually copied) to the target machine, I then am going to launch the database installation program and use another automation tool to install it automatically. So ultimately, I need to repeat the above process many (>2) times.Subinfeudation
if i don't deploy the zip file?Coquina
F
1

You can just create silent self-extracting archive (SFX) archive, example described here how to create SFX archive for stuff you need, and write Pascal code to just run it like this (script for Inno Setup 6.0.2):

[Tasks]
Name: "intallSenselockDriver"; Description: "Install Senselock driver."; GroupDescription: "Install the necessary software:";

[Code]
function ExecTmpFile(FileName: String): Boolean;
var
  ResultCode: Integer;
begin
  if not Exec(ExpandConstant('{tmp}\' + FileName), '', '', SW_SHOWNORMAL, ewWaitUntilTerminated, ResultCode)
  then
    begin
      MsgBox('Other installer failed to run!' + #13#10 + SysErrorMessage(ResultCode), mbError, MB_OK);
      Result := False;
    end
  else
    Result := True;
end;

procedure RunOtherInstallerSFX(ArchiveName: String; ExePath: String);
begin
  ExtractTemporaryFile(ArchiveName);
  ExecTmpFile(ArchiveName);
  ExecTmpFile(ExePath);
end;

function PrepareToInstall(var NeedsRestart: Boolean): String;
begin
  if WizardIsTaskSelected('intallSenselockDriver') then
    RunOtherInstallerSFX('1_senselock_windows_3.1.0.0.exe', '1_senselock_windows_3.1.0.0\InstWiz3.exe');

  Result := '';
end;

It worked perfectly for me.

Fermium answered 7/6, 2019 at 13:38 Comment(0)
A
-1

Using Double quotes worked for me. Single quotes were not working.

[Files]
Source: "unzip.exe"; DestDir: "{userappdata}\{#MyAppName}\{#InputFolderName}"; Flags: ignoreversion 

[Run]
Filename: "{userappdata}\{#MyAppName}\{#InputFolderName}\unzip.exe"; Parameters: " ""{userappdata}\{#MyAppName}\{#InputFolderName}\ZIPFILENAME.zip""  -d  ""{userappdata}\{#MyAppName}\{#InputFolderName}""  ";  Flags: runascurrentuser
Allinclusive answered 8/12, 2020 at 12:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.