I have a big problem to solve which is if you have a directory ..\App which has two folders but you don't know the folders names:
C:\Program Files (x86)\App\EFRTJKD
C:\Program Files (x86)\App\UDSIDJF
How can Inno script help identify the EFRTJKD and UDSIDJF and show them as choices in the installation page? Instead of the Browse directory option?
The two folders both have a file named Program.exe and Version.txt. The Version.txt contains a description of the folder. I want to display the description in the folder selection.
Thank you very much. I really appreciate your help.
Use FindFirst/FindNext to find your folders.
And then you can put them for example to TNewCheckListBox. Hide the DirEdit. And update its hidden contents based on what user selected in the TNewCheckListBox
[Code]
var
DirCheckListBox: TNewCheckListBox;
Dirs: TStringList;
procedure DirCheckListBoxClick(Sender: TObject);
begin
{ When user changes selection, update the path in hidden edit box }
WizardForm.DirEdit.Text := Dirs[DirCheckListBox.ItemIndex];
end;
procedure InitializeWizard();
var
FindRec: TFindRec;
RootPath: string;
Path: string;
Name: AnsiString;
begin
DirCheckListBox := TNewCheckListBox.Create(WizardForm);
DirCheckListBox.Parent := WizardForm.DirEdit.Parent;
DirCheckListBox.Top := WizardForm.SelectDirBrowseLabel.Top;
DirCheckListBox.Left := WizardForm.DirEdit.Left;
DirCheckListBox.Width := WizardForm.DirEdit.Width;
DirCheckListBox.Height :=
WizardForm.DiskSpaceLabel.Top - DirCheckListBox.Top - ScaleY(8);
DirCheckListBox.Color := WizardForm.TasksList.Color;
DirCheckListBox.WantTabs := WizardForm.TasksList.WantTabs;
DirCheckListBox.MinItemHeight := WizardForm.TasksList.MinItemHeight;
DirCheckListBox.ParentColor := WizardForm.TasksList.ParentColor;
DirCheckListBox.BorderStyle := WizardForm.TasksList.BorderStyle;
WizardForm.DirEdit.Visible := False;
WizardForm.DirBrowseButton.Visible := False;
WizardForm.SelectDirBrowseLabel.Visible := False;
RootPath := ExpandConstant('{pf}\App');
Dirs := TStringList.Create;
if FindFirst(RootPath + '\*', FindRec) then
begin
repeat
if ((FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY) <> 0) and
(FindRec.Name <> '.') and
(FindRec.Name <> '..') then
begin
Path := RootPath + '\' + FindRec.Name;
{ LoadStringFromFile can handle only ascii/ansi files, no Unicode }
if LoadStringFromFile(Path + '\' + 'version.txt', Name) then
begin
Dirs.Add(Path);
DirCheckListBox.AddRadioButton(Name, '', 0, False, True, nil);
{ If already installed, check the path that was selected previously, }
{ otherwise check the first one }
if (DirCheckListBox.Items.Count = 1) or
(CompareText(WizardForm.DirEdit.Text, Path) = 0) then
begin
DirCheckListBox.ItemIndex := DirCheckListBox.Items.Count - 1;
DirCheckListBox.Checked[DirCheckListBox.ItemIndex] := True;
end;
end;
end;
until not FindNext(FindRec);
end;
if DirCheckListBox.Items.Count = 0 then
begin
RaiseException('No folder found.');
end;
DirCheckListBox.OnClickCheck := #DirCheckListBoxClick;
DirCheckListBoxClick(nil);
end;
Related
I'm creating an installer using Inno Setup and my question is:
How can I add custom text labels like: "Space in your current drive : XXX Mb" and the space required number on that wizard page:
It will be very cool if you can help me. :)
Use GetSpaceOnDisk64 to query free disk space:
var
FreeDiskSpaceLabel: TNewStaticText;
procedure UpdateDiskSpaceLabel;
var
Path, Path2: string;
Free, Total: Int64;
FreeGB: Extended;
S: string;
begin
Path := WizardDirValue;
{ Installation path will be typically absent, }
{ so find the first parent path that really exists }
while not DirExists(Path) do
begin
Path2 := RemoveBackslash(ExtractFilePath(RemoveBackslash(Path)));
if (Path2 = '') or (Path2 = Path) then break;
Path := Path2;
end;
if GetSpaceOnDisk64(Path, Free, Total) then
begin
FreeGB := Extended(Free) / (1024*1024*1024);
S := Format('There is %.1n GB free space on selected drive.', [FreeGB]);
end
else
begin
S := 'Error querying free space on selected drive';
end;
FreeDiskSpaceLabel.Caption := S;
end;
procedure DirEditChange(Sender: TObject);
begin
UpdateDiskSpaceLabel;
end;
procedure InitializeWizard();
begin
FreeDiskSpaceLabel := TNewStaticText.Create(WizardForm);
FreeDiskSpaceLabel.Parent := WizardForm.DiskSpaceLabel.Parent;
FreeDiskSpaceLabel.Top :=
WizardForm.DiskSpaceLabel.Top - WizardForm.DiskSpaceLabel.Height - ScaleY(8);
FreeDiskSpaceLabel.Left := WizardForm.DiskSpaceLabel.Left;
WizardForm.DirEdit.OnChange := #DirEditChange;
{ Update for default/previous path }
UpdateDiskSpaceLabel;
end;
I would like to display a little image, when user hovers mouse cursor over a component on the "Select Components" page.
For example, I would like to do something like this:
I found a half solution here: Long descriptions on Inno Setup components.
But I'm missing the image part.
Building upon my answer to Long descriptions on Inno Setup components. You will need to copy HoverTimerProc and its supporting functions and global variables.
This answer modifies the HoverComponentChanged and InitializeWizard procedures to support the images in addition to description labels.
[Files]
...
Source: Main.bmp; Flags: dontcopy
Source: Additional.bmp; Flags: dontcopy
Source: Help.bmp; Flags: dontcopy
[Code]
var
CompLabel: TLabel;
CompImage: TBitmapImage;
LoadingImage: Boolean;
procedure HoverComponentChanged(Index: Integer);
var
Description: string;
Image: string;
ImagePath: string;
begin
case Index of
0: begin Description := 'This is the description of Main Files'; Image := 'main.bmp'; end;
1: begin Description := 'This is the description of Additional Files'; Image := 'additional.bmp'; end;
2: begin Description := 'This is the description of Help Files'; Image := 'help.bmp'; end;
else
Description := 'Move your mouse over a component to see its description.';
end;
CompLabel.Caption := Description;
if Image <> '' then
begin
{ The ExtractTemporaryFile pumps the message queue, prevent recursion }
if not LoadingImage then
begin
LoadingImage := True;
try
ImagePath := ExpandConstant('{tmp}\' + Image);
if not FileExists(ImagePath) then
begin
ExtractTemporaryFile(Image);
end;
CompImage.Bitmap.LoadFromFile(ImagePath);
finally
LoadingImage := False;
end;
end;
CompImage.Visible := True;
end
else
begin
CompImage.Visible := False;
end;
end;
procedure InitializeWizard();
var
HoverTimerCallback: LongWord;
begin
{ For HoverTimerProc and its supporting functions, }
{ see https://stackoverflow.com/q/10867087/850848#37796528 }
HoverTimerCallback := WrapTimerProc(#HoverTimerProc, 4);
SetTimer(0, 0, 50, HoverTimerCallback);
CompLabel := TLabel.Create(WizardForm);
CompLabel.Parent := WizardForm.SelectComponentsPage;
CompLabel.Left := WizardForm.ComponentsList.Left;
CompLabel.Width := (WizardForm.ComponentsList.Width - ScaleX(16)) div 2;
CompLabel.Height := ScaleY(64);
CompLabel.Top := WizardForm.ComponentsList.Top + WizardForm.ComponentsList.Height - CompLabel.Height;
CompLabel.AutoSize := False;
CompLabel.WordWrap := True;
CompImage := TBitmapImage.Create(WizardForm);
CompImage.Parent := WizardForm.SelectComponentsPage;
CompImage.Top := CompLabel.Top;
CompImage.Width := CompImage.Width;
CompImage.Height := CompLabel.Height;
CompImage.Left := WizardForm.ComponentsList.Left + WizardForm.ComponentsList.Width - CompLabel.Width;
WizardForm.ComponentsList.Height := WizardForm.ComponentsList.Height - CompLabel.Height - ScaleY(8);
end;
I try to write a script in InnoSetup by Ant's example.
<delete includeemptydirs="true">
<fileset dir="${term.path}/configuration" excludes="*.rtf,*.property,accounts/**/*,log/*,**/*.p12"/>
</delete>
But i dont understand how i can delete files in directory exclude files by naming pattern:
*.rtf,*.property,accounts/**/*,log/*,**/*.p12
". I didn't find exclude parameters in Inno Setup's [InstallDelete] sectoin in the help file.
I have solved this issue by add "[Code]" section into my inno script. I sure that my issue can be solved more compact and better way.
[Code]
//Procedure checks whether the file extension
//specified values or not. In the case of non-compliance,
//the file is deleted
procedure CompareAndRemove(const Path: String);
begin
if (ExtractFileExt(Path) <> '.rtf')
and (ExtractFileExt(Path) <> '.p12')
and (ExtractFileExt(Path) <> '.property')
then DelayDeleteFile(Path, 2);
end;
// Procedure compare Path of folder with given paths
procedure CompareImportantFolders(const PathToCompare: String; const Path: String );
begin
if (PathToCompare <> Path+'.')
and (PathToCompare <> Path+'..')
then DelTree(PathToCompare, True, True, True);
end;
// Procedure check a folder to important files inside
function isImportantFilesExist(Path: String): Boolean;
var
FindRec: TFindRec;
begin
if FindFirst(ExpandConstant(Path + '*'), FindRec) then
begin
try
repeat
// If just file
if FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY = 0
then
begin
if ExtractFileExt(Path+FindRec.Name) = '.p12'
then
Result := true;
end;
until not FindNext(FindRec);
finally
FindClose(FindRec);
end;
end;
end;
//Procedure runs on folder's first level and deletes all files exclude
// files with special ext. (look at procedure "CompareAndRemove")
procedure CleanDirOutOfFiles(const Path: String);
var
FindRec: TFindRec;
begin
if FindFirst(ExpandConstant(Path + '*'), FindRec) then
begin
try
repeat
// if just File
if FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY = 0
then
begin
CompareAndRemove(Path+FindRec.Name);
end;
until not FindNext(FindRec);
finally
FindClose(FindRec);
end;
end;
end;
// Procedure runs in folder and delete all folders include
// itself
procedure CleanDirOutOfFolders(const Path: String);
var
FilesFound: Integer;
DirFound: Integer;
FindRec: TFindRec;
begin //(1)
if FindFirst(Path + '*', FindRec) then
begin //(2)
try
repeat
// If found file - Directory
if FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY = 16
then
begin
CompareImportantFolders(Path+FindRec.Name, Path)
end;
until not FindNext(FindRec);
finally
FindClose(FindRec);
end;
end;
end;
// Procedure clean folder out of unimportant
// files and directories
procedure CleanDir(const Path: String);
var
FilesFound: Integer;
DirFound: Integer;
FindRec: TFindRec;
begin //(1)
FilesFound := 0;
DirFound := 0;
if FindFirst(ExpandConstant(Path + '*'), FindRec) then
begin //(2)
try
repeat
// If found file - file
if FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY = 0
then
begin
CompareAndRemove(Path+FindRec.Name);
end
// If found file - directory
else
begin
if (Path+FindRec.Name <> Path+'.')
and (Path+FindRec.Name <> Path+'..')
and (Path+FindRec.Name <> Path+'log')
and (Path+FindRec.Name <> Path+'accounts')
then
begin
CleanDirOutOfFolders(Path+FindRec.Name+'\');
CleanDirOutOfFiles(Path+FindRec.Name+'\');
if not isImportantFilesExist(Path+FindRec.Name+'\')
then
begin
DelTree(Path+FindRec.Name, True, True, True);
end;
end;
end;
until not FindNext(FindRec);
finally
FindClose(FindRec);
end;
end;
end;
I need to edit a specific line from a text file using Inno Setup. I need my installer to find this line ("appinstalldir" "C:MYXFOLDER\\apps\\common\\App70") and use the directory path from the installer.
This is the code I am trying to use:
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssDone then
begin
SaveStringToFile(
ExpandConstant('{app}\app70.txt'),
'directory's path' + '\\apps\\common\\App70', True);
end;
end;
This is my text file:
"App"
{
"appID" "70"
{
"appinstalldir" "C:MYXFOLDER\\apps\\common\\App70"
}
}
This code can do it. But note, that this code doesn't check, if the value for the tag is enclosed by quote chars, once it finds a tag specified by TagName parameter, it cuts off the rest of the line and appends the value given by TagValue parameter:
function ReplaceValue(const FileName, TagName, TagValue: string): Boolean;
var
I: Integer;
Tag: string;
Line: string;
TagPos: Integer;
FileLines: TStringList;
begin
Result := False;
FileLines := TStringList.Create;
try
Tag := '"' + TagName + '"';
FileLines.LoadFromFile(FileName);
for I := 0 to FileLines.Count - 1 do
begin
Line := FileLines[I];
TagPos := Pos(Tag, Line);
if TagPos > 0 then
begin
Result := True;
Delete(Line, TagPos + Length(Tag), MaxInt);
Line := Line + ' "' + TagValue + '"';
FileLines[I] := Line;
FileLines.SaveToFile(FileName);
Break;
end;
end;
finally
FileLines.Free;
end;
end;
procedure CurStepChanged(CurStep: TSetupStep);
var
NewPath: string;
begin
if CurStep = ssDone then
begin
NewPath := ExpandConstant('{app}') + '\apps\common\App70';
StringChangeEx(NewPath, '\', '\\', True);
if ReplaceValue(ExpandConstant('{app}\app70.txt'), 'appinstalldir',
NewPath)
then
MsgBox('Tag value has been replaced!', mbInformation, MB_OK)
else
MsgBox('Tag value has not been replaced!.', mbError, MB_OK);
end;
end;
I am making use of Inno Setup (it's amazing!). I was hoping to customise the installer so that I can accept a string from the user in the form of an input field and maybe add a message to it.
How can I do this? I had a look through the docs, google search and not much came up!
Thanks all for any help
You can use Pascal scripting in InnoSetup to create new pages for the installer. These pages can be integrated into the normal installation flow. This is well documented within the InnoSetup documentation (Google search should also come up with samples). Also the Samples folder within your Program Files\InnoSetup has some code examples.
Some time ago, there was a software called InnoSetup Form designer, which allowed you to visually design the page. The link is still there, but on the page I could not find the download. Maybe if you look around a bit you can find it?
EDIT
This is a sample for a page I made once. This is the code section of the ISS file.[Code]
var
EnableFolderPage: Boolean;
lblBlobFileFolder: TLabel;
lblBlobFileWarning1: TLabel;
lblBlobFileWarning2: TLabel;
tbBlobFileFolder: TEdit;
btnBlobFileFolder: TButton;
function GetBlobFolder(param: String): String;
begin
Result := Trim(tbBlobFileFolder.Text);
end;
{ BlobFileForm_Activate }
procedure BlobFileForm_Activate(Page: TWizardPage);
var
s: string;
begin
s := Trim(tbBlobFileFolder.Text);
if (s = '') then
begin
tbBlobFileFolder.Text := ExpandConstant('{sys}');
end;
end;
{ BlobFileForm_NextButtonClick }
function BlobFileForm_NextButtonClick(Page: TWizardPage): Boolean;
var
s: string;
begin
s := Trim(tbBlobFileFolder.Text);
if (s = '') then
begin
MsgBox(ExpandConstant('{cm:BlobFileForm_NoFolder}'), mbError, MB_OK);
Result := false;
end else
begin
if not DirExists(s) then
begin
MsgBox(ExpandConstant('{cm:BlobFileForm_DirDoesntExist}'), mbError, MB_OK);
Result := false;
end else
begin
Result := True;
end;
end;
end;
procedure btnBlobFileFolder_Click(sender: TObject);
var
directory: string;
begin
if BrowseForFolder('', directory, true) then
begin
tbBlobFileFolder.Text := directory;
end;
end;
{ BlobFileForm_CreatePage }
function BlobFileForm_CreatePage(PreviousPageId: Integer): Integer;
var
Page: TWizardPage;
begin
Page := CreateCustomPage(
PreviousPageId,
ExpandConstant('{cm:BlobFileForm_Caption}'),
ExpandConstant('{cm:BlobFileForm_Description}')
);
{ lblBlobFileFolder }
lblBlobFileFolder := TLabel.Create(Page);
with lblBlobFileFolder do
begin
Parent := Page.Surface;
Caption := ExpandConstant('{cm:BlobFileForm_lblBlobFileFolder_Caption0}');
Left := ScaleX(8);
Top := ScaleY(8);
Width := ScaleX(167);
Height := ScaleY(13);
end;
{ lblBlobFileWarning1 }
lblBlobFileWarning1 := TLabel.Create(Page);
with lblBlobFileWarning1 do
begin
Parent := Page.Surface;
Caption := ExpandConstant('{cm:BlobFileForm_lblBlobFileWarning1_Caption0}');
Left := ScaleX(8);
Top := ScaleY(80);
Width := ScaleX(50);
Height := ScaleY(13);
Font.Color := -16777208;
Font.Height := ScaleY(-11);
Font.Name := 'Tahoma';
Font.Style := [fsBold];
end;
{ lblBlobFileWarning2 }
lblBlobFileWarning2 := TLabel.Create(Page);
with lblBlobFileWarning2 do
begin
Parent := Page.Surface;
Caption :=
ExpandConstant('{cm:BlobFileForm_lblBlobFileWarning2_Caption0}') + #13 +
ExpandConstant('{cm:BlobFileForm_lblBlobFileWarning2_Caption1}') + #13 +
ExpandConstant('{cm:BlobFileForm_lblBlobFileWarning2_Caption2}') + #13 +
ExpandConstant('{cm:BlobFileForm_lblBlobFileWarning2_Caption3}') + #13 +
ExpandConstant('{cm:BlobFileForm_lblBlobFileWarning2_Caption4}');
Left := ScaleX(8);
Top := ScaleY(96);
Width := ScaleX(399);
Height := ScaleY(133);
AutoSize := False;
WordWrap := True;
end;
{ tbBlobFileFolder }
tbBlobFileFolder := TEdit.Create(Page);
with tbBlobFileFolder do
begin
Parent := Page.Surface;
Left := ScaleX(8);
Top := ScaleY(24);
Width := ScaleX(401);
Height := ScaleY(21);
TabOrder := 0;
end;
{ btnBlobFileFolder }
btnBlobFileFolder := TButton.Create(Page);
with btnBlobFileFolder do
begin
Parent := Page.Surface;
Caption := ExpandConstant('{cm:BlobFileForm_btnBlobFileFolder_Caption0}');
Left := ScaleX(320);
Top := ScaleY(48);
Width := ScaleX(91);
Height := ScaleY(23);
TabOrder := 1;
end;
with Page do
begin
OnActivate := #BlobFileForm_Activate;
OnNextButtonClick := #BlobFileForm_NextButtonClick;
end;
with btnBlobFileFolder do
begin
OnClick := #btnBlobFileFolder_Click;
end;
Result := Page.ID;
end;
procedure InitializeWizard();
begin
BlobFileForm_CreatePage(wpSelectDir);
end;
EDIT 2
To write the value the user entered to a registry key, create a new function:
function GetUserEnteredText(param: String): String;
begin
Result := Trim(tbTextBox.Text);
end;
This function simply returns what was entered in the text box. Please note that the function must take a string parameter - even though you ignore it!
In the [Registry] section of your script, declare the key that should be written like that:
Root: HKLM; Subkey: SOFTWARE\MyCompany\MyTool; ValueType: string; ValueName: MyValue; ValueData: {code:GetUserEnteredText}; Flags: createvalueifdoesntexist uninsdeletekeyifempty uninsdeletevalue
This creates a registry value named "MyValue" in HKLM\SOFTWARE\MyCompany\MyTool that contains what the user entered in the text box.
Here is shorter code to add a custom page to Inno Setup installer with an Input Field:
var
CustomQueryPage: TInputQueryWizardPage;
procedure AddCustomQueryPage();
begin
CustomQueryPage := CreateInputQueryPage(
wpWelcome,
'Custom message',
'Custom description',
'Custom instructions');
{ Add items (False means it's not a password edit) }
CustomQueryPage.Add('Custom Field:', False);
end;
procedure InitializeWizard();
begin
AddCustomQueryPage();
end;
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssPostInstall then
begin
{ Read custom value }
MsgBox('Custom Value = ' + CustomQueryPage.Values[0], mbInformation, MB_OK);
end;
end;