InnoSetup: insert an image with a link - inno-setup

Good afternoon, I'm working on a section of the installer where I want to insert an image with a link in wpInstalling section but I don't manage to do it, I know how to insert text but I don't know how to do what I said before. I hope you can help me.
Thanks in advance.

Thank you v20100v for your reply, but I found a simple way to do it. Here I leave the code just in case someone needs it.
[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}\My Program
[Files]
Source: "Logo.bmp"; Flags: dontcopy
[Code]
procedure MyImageClick(Sender: TObject);
var
ErrorCode: Integer;
begin
ShellExec('open', 'http://www.google.es', '', '', SW_SHOWNORMAL, ewNoWait, ErrorCode);
end;
procedure CreateMyImage();
begin
ExtractTemporaryFile('Logo.bmp');
with TBitmapImage.Create(WizardForm) do
begin
Parent := WizardForm.InstallingPage;
Bitmap.LoadFromFile(ExpandConstant('{tmp}\Logo.bmp'));
AutoSize := True;
Left := 0;
Top := WizardForm.InstallingPage.Top + WizardForm.InstallingPage.Height - Height - 8;
Cursor := crHand;
OnClick := #MyImageClick;
end;
end;
procedure InitializeWizard;
begin
CreateMyImage();
end;

You can find more information in this project (made by a japanese dvp). He creates a web control in InnoSetup.
Blog here : Innosetup webctrl v2.1
Download here : inno_webctrl_v2.1.zip

Related

Displaying custom status message while extracting archive in Inno Setup

I have an installation file for my app and it contains the .exe file and a .zip file as well.
What I want is:
Recently I added a code in the [Code] section that is extracting files from zip, But actually, it happened after the installation is done, and the progress bar is 100%, So what I want is to make that code's (unzipping) process work with the progress bar and show the user what is extracting at the moment.
For example: let's say extracting files will take 50% of the progress bar and the rest will take it the code section while it is unzipping, with the state about what is extracting at the moment.
Here is the code:
[Code]
procedure InitializeWizard;
begin
ForceDirectories(ExpandConstant('{localappdata}\folder-A\app\folder-B'))
end;
const
SHCONTCH_NOPROGRESSBOX = 4;
SHCONTCH_RESPONDYESTOALL = 16;
procedure unzip(ZipFile, TargetFldr: variant);
var
shellobj: variant;
SrcFldr, DestFldr: variant;
shellfldritems: variant;
begin
if FileExists(ZipFile) then begin
if not DirExists(TargetFldr) then
if not ForceDirectories(TargetFldr) then begin
MsgBox('Can not create folder '+TargetFldr+' !!', mbError, MB_OK);
Exit;
end;
shellobj := CreateOleObject('Shell.Application');
SrcFldr := shellobj.NameSpace(ZipFile);
DestFldr := shellobj.NameSpace(TargetFldr);
shellfldritems := SrcFldr.Items;
DestFldr.CopyHere(
shellfldritems, SHCONTCH_NOPROGRESSBOX or SHCONTCH_RESPONDYESTOALL);
end;
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssPostInstall then
begin
unzip(ExpandConstant('{app}\example.zip'),ExpandConstant('{app}\'));
end;
end;
The easiest solution is to use the WizardForm.StatusLabel:
WizardForm.StatusLabel.Caption := 'Extracting...';
For more fancy solution you can use TOutputProgressWizardPage. For an example that even displays a progress bar (though by using a DLL for the extraction), see:
Inno Setup - How to add cancel button to decompressing page?
This post lists more related examples:
Inno Setup: How to modify long running script so it will not freeze GUI?

How to unzip multiple files with InnoTools post install?

The script sample I have came from http://www.saidsimple.com/daniel/blog/117966/ and it’s only set for one zip. I want to be able to unzip any zips in a particular location. I guess one approach might be a wildcard *.zip when the zip name might vary depending on earlier installer selections.
No unzipping occurs. I’ve missed defining something or procedure is not setup properly. In my use the zips are text files the intended program reads for functions.
[Setup] …
SolidCompression=true
Compression=lzma
CreateAppDir=false
DirExistsWarning=false
ShowLanguageDialog=false
CreateUninstallRegKey=no
#include <idp.iss>
[Files]
Source: "{tmp}\text.net"; DestDir: "{userappdata}\ccc"; Flags: external; Components: abc
Source: "{tmp}\HLNJ.zip"; DestDir: "{userappdata}\ccc"; Flags: external deleteafterinstall; Components: hlnj
Source: "{tmp}\HNJ.zip"; DestDir: "{userappdata}\ccc"; Flags: external deleteafterinstall; Components: hnj
[Code]
const
SHCONTCH_NOPROGRESSBOX = 4;
SHCONTCH_RESPONDYESTOALL = 16;
procedure InitializeWizard; ...
begin ...
end;
procedure CurStepChanged(CurStep: TSetupStep); ...
begin
if CurStep = ssPostInstall then
begin ...
end;
end;
procedure unzip(ZipFile, TargetFldr: PAnsiChar);
var
shellobj: variant;
ZipFileV, TargetFldrV: variant;
SrcFldr, DestFldr: variant;
shellfldritems: variant;
begin
if FileExists('{userappdata}\ccc\HLNJ.zip') then begin
ForceDirectories('{userappdata}\ccc’);
shellobj := CreateOleObject('Shell.Application');
ZipFileV := string(ZipFile);
TargetFldrV := string(TargetFldr);
SrcFldr := shellobj.NameSpace(ZipFileV);
DestFldr := shellobj.NameSpace(TargetFldrV);
shellfldritems := SrcFldr.Items;
DestFldr.CopyHere(shellfldritems, SHCONTCH_NOPROGRESSBOX or SHCONTCH_RESPONDYESTOALL);
end;
end;
procedure ExtractSomething(src, target : AnsiString);
begin
unzip(ExpandConstant(src), ExpandConstant(target));
end;
I would expect one of the zips to be unzipped. But nothing, even in inno log; nothing happens in this section of code. At least deletion of zip works.
EDIT: I’m revisiting an issue I did not solve last year. The problem is getting the Unzip to work. Zip downloads to location but is deleted without unzipping first.
EDIT 2: Might not be the best but appears to work. I’ve changed my recent code to a working version for Inno 5 (edited the filenames, removed setup.)
; #pragma include __INCLUDE__ + ";" + ReadReg(HKLM, "Software\Mitrich Software\Inno Download Plugin", "InstallDir")
#pragma include __INCLUDE__ + ";" + "c:\lib\InnoDownloadPlugin"
[Setup]
#include <idp.iss>
[Types]
Name: custom; Description: "Custom installation"; Flags: iscustom
[Components]
Name: conn; Description: “CC File”; Types: custom; Flags: exclusive
Name: hlnj; Description: “H L (Recommended)”; Types: custom; Flags: exclusive
[Files]
Source: "{tmp}\text.net"; DestDir: "{userappdata}\ccc”; Flags: external; Components: conn
Source: "{tmp}\HLNJ.zip”; DestDir: "{userappdata}\ccc”; Flags: external deleteafterinstall; Components: hlnj conn
[Code]
const
SHCONTCH_NOPROGRESSBOX = 4;
SHCONTCH_RESPONDYESTOALL = 16;
procedure InitializeWizard;
begin
idpAddFileComp('http://ccc.sourceforge.net/text.net', ExpandConstant('{tmp}\text.net'), 'conn');
idpAddFileComp('http://ccc.sourceforge.net/SecurityUpdates/HLNJ.zip', ExpandConstant('{tmp}\HLNJ.zip'), 'hlnj');
idpDownloadAfter(wpReady);
end;
procedure CurStepChanged1(CurStep: TSetupStep);
begin
if CurStep = ssPostInstall then
begin
FileCopy(ExpandConstant('{tmp}\text.net'), ExpandConstant('{userappdata}\ccc\text.net'), false);
FileCopy(ExpandConstant('{tmp}\HLNJ.zip'), ExpandConstant('{userappdata}\ccc\HLNJ.zip'), false);
end;
end;
procedure unzip(ZipFile, TargetFldr: variant);
var
shellobj: variant;
SrcFldr, DestFldr: variant;
shellfldritems: variant;
begin
if FileExists(ZipFile) then begin
if not DirExists(TargetFldr) then
if not ForceDirectories(TargetFldr) then begin
MsgBox('Can not create folder '+TargetFldr+' !!', mbError, MB_OK);
Exit;
end;
shellobj := CreateOleObject('Shell.Application');
SrcFldr := shellobj.NameSpace(ZipFile);
DestFldr := shellobj.NameSpace(TargetFldr);
shellfldritems := SrcFldr.Items;
DestFldr.CopyHere(shellfldritems, SHCONTCH_NOPROGRESSBOX or SHCONTCH_RESPONDYESTOALL);
if FileExists(TargetFldr+'\HLNJ.zip') then MsgBox('HLNJ.zip'+ZipFile+
' extracted to '+TargetFldr, mbInformation, MB_OK);
end else MsgBox('HLNJ.zip does not exist', mbError, MB_OK);
end;
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssPostInstall then
begin
unzip(ExpandConstant('{userappdata}\ccc\HLNJ.zip'),ExpandConstant('{userappdata}\ccc'));
end;
end;
You can not even extract one .zip file.
So step by step first one and then ...
The code is not complete.
So one can only guess what is missing or wrong.
To test the proper functioning of the unzip procedure you should use a simple standard inno-setup program.
If this works you can add extra features and then find the error easier.
Also the used constants "src" and "target" are not visible.
How are they constructed?
unzip(ExpandConstant(src), ExpandConstant(target));
The use of different types of data should be avoided.
AnsiString vs PAnsiChar
procedure unzip(ZipFile, TargetFldr: PAnsiChar);
....
end;
procedure ExtractSomething(src, target : AnsiString);
begin
unzip(ExpandConstant(src), ExpandConstant(target));
end;
The use of {tmp} will, I suspect, made by the #include idp.iss download.
This code also not exists.
We will simulate this and use a known zip file from a known directory. So we do not need the download of the files.
Information also does not harm but makes it easier to find fault.
I used some MsgBox() for that.
A simple procedure is for the beginning following.
Copy the HLNJ.zip file to C:\HLNJ.zip
and look for a file or folder name part of the HLNJ.zip
so we can test the extraction.
I use here a file named atext.txt wich is part of my HLNJ.zip
CreateOleObject needs variants so use them instead.
[Files]
; Simulate the download of HLNJ.zip is ok
; On the development PC .. on the client PC.
Source: "C:\HLNJ.zip"; DestDir: "{tmp}";
; Now "HLNJ.zip" is in the {tmp} folder so we can use it.
Source: "{tmp}\HLNJ.zip"; DestDir: "{userappdata}\ccc"; Flags: external deleteafterinstall
[Code]
const
SHCONTCH_NOPROGRESSBOX = 4;
SHCONTCH_RESPONDYESTOALL = 16;
....
procedure unzip(ZipFile, TargetFldr: variant);// <--- variant instead of PAnsiChar
var
shellobj: variant;
SrcFldr, DestFldr: variant;
shellfldritems: variant;
begin
if FileExists(ZipFile) then begin
if not DirExists(TargetFldr) then
if not ForceDirectories(TargetFldr) then begin
MsgBox('Can not create folder '+TargetFldr+' !!', mbError, MB_OK);
Exit;
end;
shellobj := CreateOleObject('Shell.Application');
SrcFldr := shellobj.NameSpace(ZipFile);
DestFldr := shellobj.NameSpace(TargetFldr);
shellfldritems := SrcFldr.Items;
DestFldr.CopyHere(shellfldritems, SHCONTCH_NOPROGRESSBOX or SHCONTCH_RESPONDYESTOALL);
if FileExists(TargetFldr+'\atext.txt') then MsgBox('ZipFile '+ZipFile+
' extracted to '+TargetFldr, mbInformation, MB_OK);
end else MsgBox('ZipFile '+ZipFile+' does not exist', mbError, MB_OK);
end;
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssPostInstall then
begin
unzip(ExpandConstant('{userappdata}\ccc\HLNJ.zip'),ExpandConstant('{userappdata}\ccc\extracted'));
end;
end;

Opening a document in wizard before install

My problem is that i would like to make an "hyperlink"(i know there is now such thing in inno) when you click label a document(rtf) with instructions will open.
The problem: i DON'T want to copy this program along with the setup,
it should be inside the setup and after the installation it is no more
needed, thus it should be deleted or thrown out.
cant use {tmp} folder since it is accesed only in [run] phase(that is installation if i am not mistaken) and i need it earlier.
Any suggestions?
The temporary folder is not explicitly reserved for [Run] section. It can be used whenever needed (it is widely used e.g. for DLL libraries). And there is no such thing as a hyperlink label in Inno Setup as far as I know. I've made an example of a link lable and extended it for opening files that are extracted from the setup archive into a temporary folder (a folder that is deleted when the installer terminates):
[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}\My Program
[Files]
; the dontcopy flag tells the installer that this file is not going to be copied to
; the target system
Source: "File.txt"; Flags: dontcopy
[Code]
var
LinkLabel: TLabel;
procedure LinkLabelClick(Sender: TObject);
var
FileName: string;
ErrorCode: Integer;
begin
FileName := ExpandConstant('{tmp}\File.txt');
// if the file was not yet extracted into the temporary folder, do it now
if not FileExists(FileName) then
ExtractTemporaryFile('File.txt');
// open the file from the temporary folder; if that fails, show the error message
if not ShellExec('', FileName, '', '', SW_SHOW, ewNoWait, ErrorCode) then
MsgBox(Format('File could not be opened. Code: %d', [ErrorCode]), mbError, MB_OK);
end;
procedure InitializeWizard;
begin
LinkLabel := TLabel.Create(WizardForm);
LinkLabel.Parent := WizardForm;
LinkLabel.Left := 8;
LinkLabel.Top := WizardForm.ClientHeight - LinkLabel.ClientHeight - 8;
LinkLabel.Cursor := crHand;
LinkLabel.Font.Color := clBlue;
LinkLabel.Font.Style := [fsUnderline];
LinkLabel.Caption := 'Click me to read something important!';
LinkLabel.OnClick := #LinkLabelClick;
end;
procedure CurPageChanged(CurPageID: Integer);
begin
LinkLabel.Visible := CurPageID <> wpLicense;
end;

Is it possible to display the EULA and then run the setup with /SILENT or /VERYSILENT parameter?

Basically what I'm trying to achieve is the following:
If the user run the setup with the /SILENT or /VERYSILENT parameters, the setup will immediately present the EULA. If the user rejects, the install is canceled. If the user accepts, the rest of the install will happen in silent or verysilent mode.
Edit: both solutions presented by RobeN and TLama worked perfectly. The only problem is when the EULA is too big to fit a Message Box (that would be the most common situation). Anyway that's a good solution to at least display some warning or information before the install begins.
Simple solution - probably not the best, but quite fast.
Based on How to detect whether the setup runs in very silent mode?
[Files]
Source: "EULA_ANSI.txt"; DestDir: "{tmp}"; Flags: dontcopy nocompression
[Code]
var
isSilent: Boolean;
EULAText: AnsiString;
function InitializeSetup(): Boolean;
var
j: Integer;
begin
result := true;
isSilent := False;
for j := 1 to ParamCount do
if (CompareText(ParamStr(j), '/verysilent') = 0) or
(CompareText(ParamStr(j), '/silent') = 0) then
begin
isSilent := True;
Break;
end;
if isSilent then begin
ExtractTemporaryFile('EULA_ANSI.TXT');
if LoadStringFromFile(ExpandConstant('{tmp}\EULA_ANSI.txt'),
EULAText) then
begin
if MsgBox(EULAText, mbConfirmation, MB_YESNO) = IDNO then
result := false;
end
else begin
MsgBox('Unable to display EULA.' + #13#10 + #13#10 +
'Installation terminated!', mbCriticalError, MB_OK);
result := false;
end;
end
else begin
MsgBox(ExpandConstant('Standard Installation'), mbInformation,
MB_OK);
end;
end;
I do not think you can do that directly.
But you can introduce another command-line option, like /AUTOMATIC, that does what you need.
[Code]
function ShouldSkipPage(PageID: Integer): Boolean;
begin
Result :=
(Pos('/AUTOMATIC', Uppercase(GetCmdTail())) > 0) and
(PageID <> wpLicense);
end;

inno setup bmp image appear on a single page

I want a bmp image to appear on a single page "selectadditionaltasks" but it appears on all pages. What am I doing wrong?
procedure LogoOnClick(Sender: TObject);
var ResCode: Integer;
begin
end;
procedure LogoWizard();
var
BtnPanel: TPanel;
BtnImage: TBitmapImage;
begin
ExtractTemporaryFile('Logo.bmp')
BtnPanel:=TPanel.Create(WizardForm)
with BtnPanel do begin
Left:=40
Top:=250
Width:=455
Height:=42
Cursor:=crHand
OnClick:=#logoOnClick
Parent:=WizardForm
end
BtnImage:=TBitmapImage.Create(WizardForm)
with BtnImage do begin
AutoSize:=True;
Enabled:=False;
Bitmap.LoadFromFile(ExpandConstant('{tmp}')+'\Logo.bmp')
Parent:=BtnPanel
end
end;
procedure InitializeWizard();
begin
LogoWizard();
end;
image example
By setting a Parent of your BtnPanel to the WizardForm you're telling, that you want that panel to be an immediate child of the whole wizard form. You'd have to change the BtnPanel.Parent property to the page surface, on which you want that panel to appear.
Since you want your image to appear on the Select Additional Tasks wizard page, the best I can suggest is to use just the image without an underlying panel and resize the TasksList check list box, which by default covers also the bottom area of the page, where you want to place your image. And that does the following script. You may follow the commented version of this script as well:
[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}\My Program
[Files]
Source: "Logo.bmp"; Flags: dontcopy
[Tasks]
Name: associate; Description: "&Associate files"; Flags: unchecked
Name: desktopicon; Description: "Create a &desktop icon"; Flags: unchecked
[Code]
procedure LogoOnClick(Sender: TObject);
begin
MsgBox('Hello!', mbInformation, MB_OK);
end;
procedure InitializeWizard;
var
BtnImage: TBitmapImage;
begin
ExtractTemporaryFile('Logo.bmp');
BtnImage := TBitmapImage.Create(WizardForm);
with BtnImage do
begin
Parent := WizardForm.SelectTasksPage;
Bitmap.LoadFromFile(ExpandConstant('{tmp}')+'\Logo.bmp');
AutoSize := True;
Left := 0;
Top := WizardForm.SelectTasksPage.Top + WizardForm.SelectTasksPage.Height -
Height - 8;
Cursor := crHand;
OnClick := #LogoOnClick;
end;
WizardForm.TasksList.Height :=
WizardForm.TasksList.Height - BtnImage.Height - 8;
end;

Resources