What does it mean that message boxes are being suppressed in Inno Setup? - inno-setup

Here's a page from documentation: SuppressibleMsgBox.
What does it mean If message boxes are being suppressed...?

There's a link to the explanation right after the part you have quoted:
If message boxes are being suppressed (see Setup Command Line Parameters), Default is returned.
In the link, there's /SUPPRESSMSGBOXES commandline parameter documented:
Instructs Setup to suppress message boxes. Only has an effect when combined with '/SILENT' or '/VERYSILENT'.
So normally, the SuppressibleMsgBox behaves as the MsgBox. But if you run the installer with the /SUPPRESSMSGBOXES parameter, the SuppressibleMsgBox does nothing, only silently returns the value of the Default parameter.
A practical example of use of the function:
function NextButtonClick(CurPageID: Integer): Boolean;
var
Dir: string;
Msg: string;
begin
Result := True;
if CurPageID = wpSelectDir then
begin
Dir := WizardForm.DirEdit.Text;
if Pos(' ', Dir) > 0 then
begin
Msg :=
'It is not recommended to install the application to a path with spaces. '
+ 'Do you want to continue anyway?';
if SuppressibleMsgBox(Msg, mbInformation, MB_YESNO, IDYES) = IDNO then
begin
Result := False;
end;
end;
end;
end;
In an interactive installation, the installer will warn, if the user tries to install to a path with spaces. But if you are automating a silent installation with /SILENT /SUPPRESSMSGBOXES, the installer will proceed.
It's good idea to use SuppressibleMsgBox whenever you do not want that particular message to break silent installation. So for most cases.

Related

Silent Setup exit codes required by Microsoft Store: Disk Space full

Microsoft Store seems to require nowadays a quite few EXE RETURN (exit) codes during Silent setup that are not available by default. How to e.g. return an exit code when the DISK is FULL? I can see its possible to return error code when reboot is required with /RESTARTEXITCODE=exit but it would be required to have exit codes also in these cases:
Application already exists
Installation already in progress
Disk space is full
More exe return codes listed here:
https://learn.microsoft.com/en-us/windows/uwp/publish/msiexe/provide-package-details
I can see the current Inno Setup exit codes here:
https://jrsoftware.org/ishelp/index.php?topic=setupexitcodes
Imo, you cannot really implement this cleanly in Inno Setup. You would have to re-implement the disk space check and forcefully abort the installation with the required custom exit code.
I recommend you add a "Store installation" command-line switch to your installer to enable all Store-related hacks you will likely need to implement.
Something like this:
[Code]
function IsStoreInstallation: Boolean;
begin
Result := WizardSilent() and CmdLineParamExists('/StoreInstallation');
end;
procedure StoreInstallationExit(Code: Integer);
begin
Log(Format('Aborting store installation with code %d', [Code]));
ExitProcess(Code);
end;
function PrepareToInstall(var NeedsRestart: Boolean): String;
var
Free, Total: Int64;
AbortCode: Integer;
begin
Log('prepare');
if IsStoreInstallation() then
begin
Log('Store installation, checking for available disk space');
AbortCode := 0;
if not GetSpaceOnDisk64(WizardDirValue, Free, Total) then
begin
Log('Failed to check for available disk space, aborting');
AbortCode := 15;
end
else
if Free < Int64(10) * 1024 * 1024 then
begin
Log(Format('Too low available disk space (%s), aborting', [
IntToStr(Free)]));
AbortCode := 15;
end
else
begin
Log(Format('Enough available disk space (%s)', [IntToStr(Free)]));
end;
if AbortCode <> 0 then
begin
StoreInstallationExit(AbortCode);
end;
end;
end;
For CmdLineParamExists, see Is it possible to accept custom command line parameters with Inno Setup
For ExitProcess, see Exit from Inno Setup installation from [Code]

WizardForm.DirEdit.Text not updating properly. Inno setup

I am trying to set the path in the 'choose install directory' form using INNO setup. Here is my code
procedure CurPageChanged(pageID: Integer);
var
sInstallDir: String;
begin
// Default install dir is the IIS install path
if (pageID = wpSelectDir) then begin
sInstallDir := GetIISInstallPath + '\MyFolder';
Log('GetIISInstallPath: '+ GetIISInstallPath);
Log('sInstallDir: ' + sInstallDir);
WizardForm.DirEdit.Text := sInstallDir;
end;
end;
The problem I am having is that 'GetIISInstallPath' returns me 'c:\inetpub\wwwroot and that is what I see in the WizardForm. It seems to not add the MyFolder bit.
I printed out the involved variables and they all have the correct value.
sInstallDir shows up as 'C:\inetpub\wwwroot\MyFolder' but it does not show in the text field. It shows (as mentioned) only 'C:\inetpub\wwwroot'.
Please advise.
Thank You
Your code works fine for me but, can I suggest you to use
[Setup]
...
DefaultDirName={code:GetDefaultDirName}
[code]
...
function GetDefaultDirName(): String;
begin
Result := GetIISInstallPath + '\MyFolder';
end;
Doing this the "GetIISInstallPath + \MyFolder" will be your default directory

InnoSetup - Set DefaultDirName at runtime

I have an application that needs to allow for up to three simultaneous installations on the same machine.
For some reason, the following code behaves as if UsePreviousAppDir is set to yes. The second time I install the app, the path ends up mangled.
The value I want to see is
C:\Our App\install_x where x corresponds to the user's selection.
It works the first time, but the second run results in something like this:
C:\Our App\install_x\install_y, where x corresponds to the value selected with the first installation and y corresponds to the value selected during this installation.
The install version is a radio button selection grabbed from the first screen in the installer. How do I eliminate this issue?
Setup section:
[Setup]
AppName=Our App
AppId=Our App
AppVerName=Our App Version(CM)
DefaultDirName=C:\Our App
DefaultGroupName=Our Group Name
OutputDir=..\
OutputBaseFilename=mm_setup
DisableStartupPrompt=yes
Compression=zip
UsePreviousAppDir=no
VersionInfoDescription=Our App Setup
CreateUninstallRegKey=no
DirExistsWarning=no
And the method where I set the install version:
procedure gSetVersion;
begin
if gVersionPage.SelectedValueIndex = 0 then
begin
gInstallArea := 'install_a';
end
else if gVersionPage.SelectedValueIndex = 1 then
begin
gInstallArea := 'install_b';
end
else if gVersionPage.SelectedValueIndex = 2 then
begin
gInstallArea := 'install_c';
end
WizardForm.DirEdit.Text := WizardDirValue + '\' + gInstallArea;
end;
Solved the problem via the following hack. Not sure why it was necessary to manually edit the string when the `UsePreviousAppDir=no' was set, but this works
procedure gSetVersion;
var
installVersionIndex: Integer;
installDir: String;
begin
case gVersionPage.SelectedValueIndex of
0: gInstallArea := 'install_a';
1: gInstallArea := 'install_b';
2: gInstallArea := 'install_c';
end
//Set the default installation folder.
//This is necessary because InnoSetup intermittently
//ignores the 'UsePreviousAppDir=no' [Setup] directive
//and because the 'DefaultDirName' directive gets populated
//prior to the user selecting the install version
installVersionIndex := Pos('install_', WizardDirValue);
installDir := WizardDirValue;
if installVersionIndex > 0 then
begin
Delete(installDir, installVersionIndex, 20);
end
WizardForm.DirEdit.Text := installDir + '\' + gInstallArea;
end;

Inno Setup - How to read an INF file during the Setup

i need to know how to read a value from INF file [.inf], during the setup. I want the installer to check the version of the program that i am going to update, This program version is not stored in the registry or any other file, is only in the .inf file. Then is a must to get the version from it.
I got your answers, #Tlama and i cannot use a DLL to get version of the software.
This program only save the current version in the INF file.
What i want to do, is to make the installer to check the current versión of the software that i am working with, and display that version in a label text.
The inf information is this:
NetVersion=1.1.1.1
PatchVersion=2.0.1
ProductName=SoftwareX
I just need the PatchVersion to display after where it says version: #### :
this is the code i am trying to fix:
function GetInfsam: String;
var
sVersion : String;
Begin
sVersion := '';
GetIniString('', 'PatchVersion', 'sVersion', '{app}\Sam.inf');
Result := sVersion;
end;
Procedure InitializeWizard7();
var
L2Ver1 : Tlabel;
L2Ver2 : Tlabel;
Begin
L2Ver1:= TLabel.Create(WizardForm);
L2Ver1.Transparent:= True;
L2Ver1.AutoSize:= False;
L2Ver1.WordWrap:= True;
L2Ver1.Font.name:= 'Agency FB';
L2Ver1.Font.Size:= 12;
L2Ver1.Font.Color:= clwhite;
L2Ver1.Caption:= 'Version:';
L2Ver1.Parent:= WizardForm.SelectdirPage;
L2Ver1.Left := 5;
L2Ver1.top := 260;
L2Ver1.Width := 150;
L2Ver1.Height := 40;
L2Ver2:= TLabel.Create(WizardForm);
L2Ver2.Transparent:= True;
L2Ver2.AutoSize:= False;
L2Ver2.WordWrap:= True;
L2Ver2.Font.name:= 'Agency FB';
L2Ver2.Font.Size:= 12;
L2Ver2.Font.Color:= clwhite;
L2Ver2.Caption:= GetInfsam;
L2Ver2.Parent:= WizardForm.SelectdirPage;
L2Ver2.Left := L2Ver1.Width + L2Ver1.Left + 8;
L2Ver2.top := 260;
L2Ver2.Width := 100;
L2Ver2.Height := 40;
End;
Please, i need help to fix my code.
How to read INF file ?
INF files are just sort of INI files with the specified syntax. So to work with INF files you need to treat them as ordinary INI files. Assuming you have a INF file like this:
[Add.Code]
File.dll=File.dll
[File.dll]
File=http://www.code.com/file.dll
FileVersion=1,0,0,143
You can read the FileVersion key by using GetIniString this way:
procedure InitializeWizard;
var
Version: string;
begin
Version := GetIniString('File.dll', 'FileVersion', '', 'c:\File.inf');
if Version <> '' then
MsgBox('File version: ' + Version, mbInformation, MB_OK);
end;
Update:
1. Malformed INF file
According to your update, if the content of your INF file looks like this:
NetVersion=1.1.1.1
PatchVersion=2.0.1
ProductName=SoftwareX
then it's not a well formed INF file, but a name value pair text file saved with INF extension. Real INF files must have a valid [] section for each key value set, but this section is missing in your file.
2. GetIniString function cannot be called with empty Section parameter value
You must not call the GetIniString function with empty Section parameter value, because for the internally called GetPrivateProfileString function it means to return all section names for a given file, not value of a specified key. So for instance the following call is invalid, because the first parameter Section cannot be empty:
GetIniString('', 'KeyName', 'Default', 'c:\File.xxx');
3. How to work with a name value pair text file ?
You'll just need to work with that file as with a text file. For a key value text file handling would be ideal to use the TStringList class, or at least in Delphi. In InnoSetup unfortunately the TStringList class doesn't have published properties needed for a key value content manipulation, so you'll need to make your own key value text file parsing function. Here's the one for getting value for a given key. As the key value delimiter is supposed to be the = sign. This function returns a key value when succeed to find a AKeyName key in a given AFileName file or default ADefault value when fails:
function GetKeyValue(const AKeyName, AFileName, ADefault: string): string;
var
I: Integer;
KeyPos: Integer;
KeyFull: string;
FileLines: TArrayOfString;
begin
Result := ADefault;
if LoadStringsFromFile(AFileName, FileLines) then
begin
KeyFull := AKeyName + '=';
for I := 0 to GetArrayLength(FileLines) - 1 do
begin
FileLines[I] := TrimLeft(FileLines[I]);
KeyPos := Pos(KeyFull, FileLines[I]);
if KeyPos > 0 then
begin
Result := Copy(FileLines[I], KeyPos + Length(AKeyName) + 1, MaxInt);
Break;
end;
end;
end;
end;
To read a value of the PatchVersion key from the Sam.inf file expected in the currently selected install path you can use something like this. This script will update the label value whenever your user change the text in the directory edit box and when the directory selection page is going to be displayed:
var
// target version label must be declared globally
L2Ver2: TLabel;
procedure DirEditChange(Sender: TObject);
var
FilePath: string;
begin
// assign the expected INF file path
FilePath := AddBackslash(WizardForm.DirEdit.Text) + 'Sam.inf';
// read the PatchVersion key value, return N/A if not found
L2Ver2.Caption := GetKeyValue('PatchVersion', FilePath, 'N/A');
end;
procedure InitializeWizard;
begin
// create the target label as before
L2Ver2 := TLabel.Create(WizardForm);
...
// bind the DirEditChange method to the directory edit's OnChange event
WizardForm.DirEdit.OnChange := #DirEditChange;
end;
procedure CurPageChanged(CurPageID: Integer);
begin
// if the page has been turned to the select directory page, update the
// label caption by firing the assigned OnChange event method manually
if (CurPageID = wpSelectDir) then
DirEditChange(nil);
end;
All my INF files have a structure similar to INI files.
If that's your case too I suggest you to open your INF as if it was INI, using (as suggested by TLama)
in setup functions:
function GetIniInt(const Section, Key: String; const Default, Min, Max: Longint; const Filename: String): Longint;
function GetIniString(const Section, Key, Default, Filename: String): String;
in preprocessor:
str ReadIni(str 1, str 2, str 3, str? 4)
Description (from Inno Setup help)
Reads the value from an INI file. Argument 1 must be the name of the INI file, argument 2 – the name of a section in the INI file, the third argument is the key in the section to read. Last optional argument can be used to provide the default value that will be returned on failure, if it is omitted, an empty string is returned.

How to set automaticly DefaultDirName for previous Inno Setup installation?

my previous installation (A) in Inno Setup has AppID={{8ADA0E54-F327-4717-85A9-9DE3F8A6D100}.
I have another installation (B) with different AppID and I want to install it into the same directory as installation (A).
How do I get automaticly DefaultDirName? I don't want to use the same AppID, because when I uninstall the installation (B) and installation (A) stays installed, it will delete AppID string from registry (installation (A) string).
Can you help me, please?
You'll probably need some code to do what you want. You'll also need a way to find the installation directory of Application A. Here's some code that I've used
[Setup]
DefaultDirName={code:GetDefaultDir}
[Code]
function GetDefaultDir(def: string): string;
var
sTemp : string;
begin
//Set a defualt value so that the install doesn't fail.
sTemp := ExpandConstant('{pf}') + '\MyCompany\MyAppA';
//We need to get the current install directory.
if RegQueryStringValue(HKEY_LOCAL_MACHINE, 'Software\MyCompany\Products\MyAppNameA',
'InstallDir', sTemp) then
begin
//We found the value in the registry so we'll use that. Otherwise we use the default
end;
Result := sTemp;
end;
I developed the following code to find the installation directory based on AppID. It accommodates per-user registry entries as well as those for the entire machine. It has been tested on Windows 7 Enterprise on a domain and in a Virtual PC XP Professional machine:
[code]
const
PreviousAppID = '8ADA0E54-F327-4717-85A9-9DE3F8A6D100';
AppFolder = 'SomeFolder';
UninstallPath = 'Software\Microsoft\Windows\CurrentVersion\Uninstall\{'
+ PreviousAppID + '}_is1';
// Some posts have 'InstallDir', but I have never observed that
InstallKey = 'InstallLocation';
function GetDefaultDir( Param: String ) : String;
var
UserSIDs: TArrayOfString;
I: Integer;
begin
// Check if the current user installed it
if RegQueryStringValue( HKEY_CURRENT_USER, UninstallPath,
InstallKey, Result ) then
// Current user didn't install it. Did someone else?
else if RegGetSubkeyNames( HKEY_USERS, '', UserSIDs ) then begin
for I := 0 to GetArrayLength( UserSIDs ) - 1 do begin
if RegQueryStringValue( HKEY_USERS, UserSIDs[I] + '\' + UninstallPath,
InstallKey, Result ) then break;
end;
end;
// Not installed per-user
if Result = '' then begin
// What about installed for the machine?
if RegQueryStringValue( HKEY_LOCAL_MACHINE, UninstallPath,
InstallKey, Result ) then
// Doesn't appear to be installed, as admin default to Program Files
else if IsAdminLoggedOn() then begin
Result := ExpandConstant('{pf}\') + AppFolder;
// As non-admin, default to Local Application Data
end else begin
Result := ExpandConstant('{localappdata}\') + AppFolder;
end;
end;
end;

Resources