inno setup to browse and extract zip file at sepcific location - inno-setup

I want to enable users to browse and extract zip files at a specific location.
Requirements/steps:
Display welcome page
Next display browse button to select installation directory(DisableDirPage=no)
Next display browse button to select zip file(JDK)
Extract JDK zip file selected in step 3 at location selected in step 2, that means JDK should be extracted in installation directory that user selects in step 2
Problems with my code:
After the first step my code directly jump into 3rd step and then it goes to 2nd.
The code to extract zip is not working if I pass method name as the parameter. If I pass the hardcoded value of the location it works. I don't know pascal and it basically seems to be a syntax related issue.
[SETUP]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}\My Program
DefaultGroupName=My Program
UninstallDisplayIcon={app}\MyProg.exe
DisableProgramGroupPage=no
DisableWelcomePage=no
DisableDirPage=no
Compression=lzma2
SolidCompression=yes
OutputDir=userdocs:Inno Setup Examples Output
[Files]
Source: "{code:GetLicensePath}"; DestDir: "{app}"; Flags: external
Source: "7za.exe"; DestDir: "D:\authorized\Builds\Solo\"; Flags: deleteafterinstall;
[Icons]
Name: "{group}\My Program"; Filename: "{app}\MyProg.exe"
[Run]
Filename: D:\authorized\Builds\Solo\7za.exe; Parameters: "x ""{{Code:GetZipPath}}"" -o""{app}\"" * -r -aoa"; Flags: runhidden runascurrentuser;
[Code]
var
Page: TInputFileWizardPage;
DataDir:String;
procedure InitializeWizard();
begin
Page :=
CreateInputFilePage(
wpWelcome,
'Select Zip File Location',
'Where is your Zip file located?',
'Select where Zip file is located, then click Next.');
Page.Add(
'Location of Zip file:',
'*.7z|*.rar|All files|*.*',
'.zip');
// Set initial value (optional)
Page.Values[0] := ExpandConstant('{%USERPROFILE}\Downloads\setup.7z');
;
end;
function GetZipPath(Param: string): string;
begin
DataDir := Page.Values[0];
end;
Could you help me, please?

The order of your custom page is determined by the first argument of the Create* function. So change wpWelcome to wpSelectDir.
Why double {{...}} - That’s likely the problem. Also code: should be lowercase.
Your scripted constant function does not really return anything. It should be:
Result := Page.Values[0];

Related

Setup is "unresponsive" at startup if I compile it with compression [duplicate]

My Installer created with Inno Setup is about 850 MB in size containing about 7000 files and 890 Folders to an uncompressed size of 1.98 GB.
When starting the install process, after the Windows UAC Dialog shows up, the Installer is sitting with an empty icon in the Taskbar for approx. 45 seconds before the Welcome Dialog is being shown.
I'm assuming that this is happening during the process of unpacking the installer? Running the installer with just a dummy file entry has the Welcome Dialog show up immediately.
In the [Files] section, I only specify a single relative folder:
Source: "{#Source}\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
Compression in the [Setup] section is set to:
Compression=lzma
SolidCompression=yes
Is there a dialog I can show during that time that gives the user visual feedback that something is being prepared?
To append to this question:
The last entry in the Log file before the 45 second hang is:
Extracting temporary file: C:\Users\Markus\AppData\Local\Temp\is-CBETM.tmp\license.rtf
I'm using a custom License Page on which I extract the file and load it as RTFText:
procedure LicensePage_Create;
var
LicenseFileName: string;
LicenseFilePath: string;
LicenseText: AnsiString;
begin
LicensePage := CreateOutputMsgMemoPage(wpSelectDir, SetupMessage(msgWizardLicense), SetupMessage(msgLicenseLabel), SetupMessage(msgLicenseLabel3), '');
LicensePage.RichEditViewer.Height := WizardForm.LicenseMemo.Height;
LicenseFileName := 'license.rtf';
ExtractTemporaryFile(LicenseFileName);
LicenseFilePath := ExpandConstant('{tmp}\license.rtf');
LoadStringFromFile(LicenseFilePath, LicenseText);
LicensePage.RichEditViewer.RTFText := LicenseText;
DeleteFile(LicenseFilePath);
LicensePage.OnActivate := #LicensePageActivate;
LicenseAcceptedRadio := CloneLicenseRadioButton(WizardForm.LicenseAcceptedRadio);
LicenseNotAcceptedRadio := CloneLicenseRadioButton(WizardForm.LicenseNotAcceptedRadio);
LicenseNotAcceptedRadio.Checked := True;
LicensePageID := LicensePage.ID;
end;
When you want to use SolidCompression (is it really worth it?), you have to put all files that are needed for the installer to start (like "license" file) before the big files.
Otherwise the installer has to decompress all the big files while starting.

Inno Setup Runtime error while accessing CurrentFileName when installing an empty folder

I tried to access all files inside a folder through Pascal code. When I iterate through an empty folder I am getting the following error:
Exception: Internal error; An attempt was made to call the "CurrentFileName" function from outside a "Check", "BeforeInstall" or "AfterInstall" event function belonging to a "[Files]" entry
The code I used:
[Files]
Source: ".\3D_Dlls\*"; DestDir: {app}\3D_Dlls; \
Flags: ignoreversion recursesubdirs createallsubdirs skipifsourcedoesntexist; \
Check: FileBackup
[Code]
function FileBackup(): Boolean;
var FileName,Source,Target,TargetDir: String;
begin
Result := True;
Source := ExpandConstant(CurrentFileName);
end
Say for example my folder structure is like that:
3D_Dlls
- Folder 1
- Folder 2 // Empty folder and it invokes the problem
- Folder 3
I believe this is a bug in Inno Setup triggered by the createallsubdirs flag.
When the flag is specified, Inno Setup collects a separate list of empty directories that need to be explicitly created during an installation. When "installing" the empty folder, the call to the CurrentFileName simply fails.
Workarounds:
Remove the createallsubdirs flag, if possible.
Instead, you can explicitly create empty directories using the [Dirs] section.
Catch the exception:
function FileBackup: Boolean;
begin
Result := True;
try
Source := ExpandConstant(CurrentFileName);
except
Log(GetExceptionMessage);
end;
end;
I have reported this on Inno Setup newsgroup, but the newsgroup was reset since.

Inno Setup: Asking for directory page if a task checked

Under the task section I have
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; \
GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
Name: "installFolder"; Description: "Install project folder."; \
GroupDescription:" folder";
and in the Files section is this particular folder
Source: "C:\\Output\LEA\*.*"; DestDir: {code:GetDataDir}; \
Flags: createallsubdirs recursesubdirs ignoreversion;
My aim is to test the for the checked button and then have a window to ask for the directory to install the folder to.
if WizardForm.TasksList.Checked[3] then
GetDataDir;
Can this be done without the need to create pages or the one page to get the directory?
Also, is this a good way to handle extra files that are optional and will be installed to a different location than the default {app} location?
The confusing part for me thus far is when it's all compiled, the GetDataDir is being called before the page to select Tasks. So I choose my directory and then I'm asked whether I want to install it or not. I don't know how to go about getting the GetDataDir to occur afterwards.
The wizard model in Inno Setup means you should always create the wizard pages, but you can skip the ones that don't need to be shown.
This can be done in the ShouldSkipPage() event function by calling IsTaskSelected():
function ShouldSkipPage(PageID: Integer): Boolean;
begin
if (PageID = InstallFolderPage.ID) and not IsTaskSelected('installFolder') then
Result := True
else
Result := False
end;
In this case, with only a single check, it can be shortened to:
function ShouldSkipPage(PageID: Integer): Boolean;
begin
Result := (PageID = InstallFolderPage.ID) and not IsTaskSelected('installFolder')
end;
As TLama said, you don't need to do anything special in the {code:...} functions, just return the appropriate value directly.
You simply need to add '; Tasks: installFolder' at the end of your Source... line, then it won't be called unless the task as been selected.
Source: "C:\\Output\LEA\*.*"; DestDir: {code:GetDataDir}; Flags: createallsubdirs recursesubdirs ignoreversion; Tasks: installFolder

How to rename a file using inno setup

I want to first rename an existing file 'My program old' to 'My program v2' but only if 'My program v2' doesn't already exist.
Then I want to rename 'My program' to 'My program old' but only if 'My program old' doesn't already exist.
And then I want to install 'My program' from the installer but only if 'My program' doesn't already exist.
I would be very grateful for any guidance !
I would give a try to something like this. In the ssInstall stage of the CurStepChanged event, which occurs just before the installation process starts, just check if the file doesn't exist with the FileExists function, and if not, then just call the RenameFile function, which will silently fail if the source file doesn't exist, so you don't need to care if the source file exists. In the [Files] section you can then use the onlyifdoesntexist flag for your last requirement. You can follow the commented version of this script if you want:
[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}\My Program
[Files]
Source: "My program"; DestDir: "{app}"; Flags: onlyifdoesntexist
[Code]
function GetFileName(const AFileName: string): string;
begin
Result := ExpandConstant('{app}\' + AFileName);
end;
procedure CurStepChanged(CurStep: TSetupStep);
begin
if (CurStep = ssInstall) then
begin
if not FileExists(GetFileName('My program v2')) then
RenameFile(GetFileName('My program old'), GetFileName('My program v2'));
if not FileExists(GetFileName('My program old')) then
RenameFile(GetFileName('My program'), GetFileName('My program old'));
end;
end;

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

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?
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)
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.
For an example of extracting some files only, see:
How to get Inno Setup to unzip a single file?
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;
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.
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

Resources